ippsample/0000755000175000017500000000000013240604131011534 5ustar tilltillippsample/.mailmap0000644000175000017500000000111713240604116013160 0ustar tilltill# Prevent git from showing duplicate names with commands like "git shortlog" # See the manpage of git-shortlog for details. # The syntax is: # Name that should be used Bad name # # You can skip Bad name if it is the same as the one that should be used, and is unique. # # This file is up-to-date if the command git log --format="%aN <%aE>" | sort -u # gives no duplicates. Michael R Sweet msweet Michael R Sweet Michael Sweet ippsample/configure.ac0000644000175000017500000000222413240604116014025 0ustar tilltilldnl dnl Configuration script for the IPP sample code. dnl dnl Copyright 2014-2017 by the IEEE-ISTO Printer Working Group dnl Copyright 2007-2017 by Apple Inc. dnl Copyright 1997-2007 by Easy Software Products, all rights reserved. dnl dnl Licensed under Apache License v2.0. See the file "LICENSE" for more dnl information. dnl dnl We need at least autoconf 2.60... AC_PREREQ(2.60) dnl Package name and version... AC_INIT([IPPSAMPLE], [1.0b1], [https://github.com/istopwg/ippsample/issues], [ippsample], [http://www.pwg.org/ipp/]) dnl Include common configuration scripts... sinclude(config-scripts/cups-opsys.m4) sinclude(config-scripts/cups-common.m4) sinclude(config-scripts/cups-compiler.m4) sinclude(config-scripts/cups-network.m4) sinclude(config-scripts/cups-poll.m4) sinclude(config-scripts/cups-threads.m4) sinclude(config-scripts/cups-ssl.m4) sinclude(config-scripts/cups-largefile.m4) sinclude(config-scripts/cups-dnssd.m4) dnl IPP Sample-specific options IPP="ipp" AC_SUBST(IPP) AC_ARG_WITH(name-prefix, [ --with-name-prefix=... set prefix on command names (default is "ipp")], IPP="$withval",) dnl Generate a bunch of files... AC_OUTPUT(Makedefs) ippsample/test/0000755000175000017500000000000013240604116012516 5ustar tilltillippsample/test/run-tests.sh0000755000175000017500000000043613240604116015024 0ustar tilltill#!/bin/sh # # Integration test script for ippsample. # # Copyright © 2018 by The Printer Working Group. # Copyright © 2018 by Apple Inc. # # Licensed under Apache License v2.0. See the file "LICENSE" for more # information. # # Usage: # # test/run-tests.sh # echo "Coming soon!" ippsample/test/start-server.sh0000755000175000017500000000176613240604116015530 0ustar tilltill#!/bin/sh # # Copyright © 2017-2018 by The Printer Working Group. # # Licensed under Apache License v2.0. See the file "LICENSE" for more # information. # # Usage: # # test/start-server.sh [options] # # Verify we have been run from the correct location... if test ! -d test; then echo "Usage: test/start-server.sh [options]" exit 1 fi # Find where the ippserver binary resides IPPSERVER="" for file in server/ippserver xcode/DerivedData/ippsample/Build/Products/Debug/ippserver xcode/DerivedData/ippsample/Build/Products/Release/ippserver; do if test -x $file; then IPPSERVER="$file" break fi done if test "x$IPPSERVER" = x; then echo "You must build ippserver before running this script." exit 1 fi # Run server with base options: # # - Be very verbose # - Use configuration directory "test" # - Specify IPP Everywhere sub-type echo "Running $IPPSERVER -vvv -C test -r _print $@" exec $IPPSERVER -vvv -C test -r _print "$@" ippsample/test/print/0000755000175000017500000000000013240604116013652 5ustar tilltillippsample/test/print/foo.conf0000644000175000017500000000126013240604116015303 0ustar tilltillDeviceURI ipp://foo.example.com/ipp/print Attr collection media-col-ready { Member collection media-size { Member integer x-dimension 21590 Member integer y-dimension 27940 } Member keyword media-type stationery-letterhead },{ Member collection media-size { Member integer x-dimension 21000 Member integer y-dimension 29700 } Member keyword media-type stationery-plain } Attr keyword media-ready na_letter_8.5x11in,iso_a4_210x297mm Attr keyword media-type-supported stationery-plain,stationery-letterhead Attr integer pages-per-minute 10 Attr integer pages-per-minute-color 5 Strings en test/en.strings Strings fr test/fr.strings ippsample/test/print/ipp-everywhere-pdf.png0000644000175000017500000001772213240604116020113 0ustar tilltillPNG  IHDR+$VvGj \ &H@%MP̴tVV`p\[.R- ?~TIm+i9mVoQ`U>|J]7vxfYb /#g{cc : 47)sFVhOBCŬA \4q Cҧiԁt\Tr8>"]W WB#VVd ѐ"q3cL3s 3:>7K!אNQac1y QM0AKny`0AMM*\"aNƥ`@XI:@ ꢺS~ǶiyYmmh4+0@hNk4=FK4ꂎEaXCW#VTLQ$|@qIpY~fIvژEG)XPoe4 HpD. >L]o_[]T SC\P(ʕ-Ѿbra$8VVC2juA} 7Spꂎ ]iu8b% NAc8’-;uP5ͦv$8e-~K$I/8ϑR):E[VSZnMaX[W1vb>\eWeL{w}ghy!-`ܺlќX]K_lTCDڗ kO 苈'z j 3?fUw1/M8sZsٽϏzG#JG(ue!ǝ˭|pPqWyqT;5~\W=F%1Ҫz.^BR}_㐽az҂_(RYjB5eqgSNz?\HG (Rn?٥ EfzS-Ѿ{[1 /}!LaG$8B  &Hp0A# !L0}͍sf+YZz 1}΀m6MVXz~t{vDG!̊9Kݧ**B$=t Z1aJ{&Z>Mgm/f-B2dxeɷ~d^$8B  &Hp0A# !LaG$8B  &Hp0,naր`wOՎ0dHqnoطo_Qː!Cv7}]]}^mϘ<%?UUXчŎ;sNFм}!^G)h +1|xqglSlݺ7lͷtpjTWWc)q%>KxP :t(aƅbhh? MMWh=DZPUUfϙ44;mUv;.r,^~CNfw|`bwpM 0t0˱̺hO=a)Sy0x`K̜wx.#/O_>4[nb N=g>{eV\/Z]FIpԽwҾu8䓭.d8 ^|K^}5sf1v Θ:ΜyL.#G•W]_z(\knx≽XI֯_w[k-% 8w[MY{pXjUZJ t <8ЋXX]k)Ip,0mF%KZJ4y=\'rE= n܋Ք N 6 ?}ѼܼiSCVUUG{ y߳g%8RKʢxyFXUn>8gsN4X ]{"`ƅ30hРi!C`QM'9xu.f-Bʦ&Hp0A# !LaG$8B  &Hp0A# !LaG$8B  &Hp0tp ޴(DTEkJ=o!Y[>MG#,f!BŊvO[ĊXhOY}Pb0aYS>PN UU)Cow}z-(8;2&,@,]xFd#z`׬EEcBɒdub#1XtVu^SnΞ`/ƲwȦhXHcc#>i18@% ZP?23W~u/B)@ܥ bu%@/. tro!DbvE!B!B!BQї=`ln|$nIuYx/T~z@ej$^2L QVA25LK'4$ϝ #WǻH~"gZ Bfr343o[">4.ẇ~4#|ʚ$q.0!oJ! -(8̬0320!Je9;Mm.P6D`0(fP'ͧ-[ Nyz Ω.vX`au~ `=k9&jU'lGq-pxkq8]b`ljkkWlSwWs(Vٹ9 D'<=6JTlSZ{EӼcIŇ1;q8@=$: 6unc4霠i f tZ ݼP[[[Ui@43N@_DV5vsiN;<~\S4[?~0ۼcXK ̴uz7X :M۩Y&R3՟ *z'"`ǽ<.:=A_9DW@j,hxr= m`(`H=%?ζ*̚:^oۥ M_('0 lP65:ܳu5Lb⫽N pXn@AHDtt?|61~"/p/0Jf G;2f̈f_f @ 8]u_(Ԙ5h` .w\C%_4>vM/#B7<.5q: mi|Fd;NR.J| f+;䭫p&t:GgYu\>($8z{diP.F\5;/x.'l5 |%WNe^{NK FՔqRra(㲧^t^75 { |> _=Ϲ\.WUyz4uä ugvnuz`cpgvl/Z2WM@4ܯ ll.+'¥KaD@;]>TC|r9uT;~mDSuET}13Z7۲J؛j^C/i@z|+~Pƍ1vφ|kj;pz!Wá7xU:8A6yA;&܌`1 Egcs4$߰^㛩Yj?m%PzV y72LV z,=m\m M۔^0r BGm.LfjX҃pEzޕ`,C=˂'p b6&fΝY | ɰnHd-0K<^ƿvoĉRV?{ffLPccԩvpɏ}>_cnq(<ܷk̵ =H6-[ T/ĕw쓛k.: ,it0̑It}5knjJ gz~UsuTJ%,&:S1F 1psjR ?R}Egt$Yr3NN{VL>AU]vt]q #YD/A]= z YD6}jT麵s#铐<&SRNsLͭ[߾zP/q:g'JH $7_Gz]Ї^NK=ձ }7c+0ogo)hҲɳXӷn&ԾP Bk 1#khuuCY(c?Pc y@g< ]&"jL:g&8&郞@ɊwaX;ѣ]xK=Ngj:]O{<%Ri ~yڵ\Db JJ~w \ yRDž>2Lp8ekt:G{HzQHeGW"q*aıļy]NUU,哔Х577泥W2@gztnxNf禎_K\'捕z![7Z>;5 C_ hYEkãv~N2M:ծ:a ch4z n=N:W3C \n4h> U}NgR{n dCss~ӵ uܷI5#J"}15 WحOE<|p@ tnX3vG$*üDx1NcFFP?Cz`֝b HǸtLq"rٱK.O6Qsyq8U~MMMf,Dym y&4(@7 5 3E/v]邟3>dЂ|Bɼ$Nkk3Ab|mHh7 cN#czkê4ںņ` 3E躤(/q=}B?xfA) X#F)88P iZ)c(8=C?z9w+>ug8BWj:win DBSh(hS-NQ1xVl6YfBБ@ PyG"kv"Y<LvCYDC9uvژt[|PW]C : d;%q550_c Ś*ROP:F.r_FzVH:v‡d/|rmn{;mӂGO0U0^^J4Sq5*@L+M*no9Rg(&kcuo`1L~?:D)7}aODa9T+7BnNT;FG+$VvGj \ &H@%MP̴tVV`p\[.R- ?~TIm+i9mVoQ`U>|J]7vxfYb /#g{cc : 47)sFVhOBCŬA \4q Cҧiԁt\Tr8>"]W WB#VVd ѐ"q3cL3s 3:>7K!אNQac1y QM0AKny`0AMM*\"aNƥ`@XI:@ ꢺS~ǶiyYmmh4+0@hNk4=FK4ꂎEaXCW#VTLQ$|@qIpY~fIvژEG)XPoe4 HpD. >L]o_[]T SC\P(ʕ-Ѿbra$8VVC2juA} 7Spꂎ ]iu8b% NAc8’-;uP5ͦv$8e-~K$I/8ϑR):E[VSZnMaX[W1vb>\eWeL{w}ghy!-`ܺlќX]K_lTCDڗ kO 苈'z j 3?fUw1/M8sZsٽϏzG#JG(ue!ǝ˭|pPqWyqT;5~\W=F%1Ҫz.^BR}_㐽az҂_(RYjB5eqgSNz?\HG (Rn?٥ EfzS-Ѿ{[1 /}!LaG$8B  &Hp0A# !L0}͍sf+YZz 1}΀m6MVXz~t{vDG!̊9Kݧ**B$=t Z1aJ{&Z>Mgm/f-B2dxeɷ~d^$8B  &Hp0A# !LaG$8B  &Hp0,naր`wOՎ0dHqnoطo_Qː!Cv7}]]}^mϘ<%?UUXчŎ;sNFм}!^G)h +1|xqglSlݺ7lͷtpjTWWc)q%>KxP :t(aƅbhh? MMWh=DZPUUfϙ44;mUv;.r,^~CNfw|`bwpM 0t0˱̺hO=a)Sy0x`K̜wx.#/O_>4[nb N=g>{eV\/Z]FIpԽwҾu8䓭.d8 ^|K^}5sf1v Θ:ΜyL.#G•W]_z(\knx≽XI֯_w[k-% 8w[MY{pXjUZJ t <8ЋXX]k)Ip,0mF%KZJ4y=\'rE= n܋Ք N 6 ?}ѼܼiSCVUUG{ y߳g%8RKʢxyFXUn>8gsN4X ]{"`ƅ30hРi!C`QM'9xu.f-Bʦ&Hp0A# !LaG$8B  &Hp0A# !LaG$8B  &Hp0tp ޴(DTEkJ=o!Y[>MG#,f!BŊvO[ĊXhOY}Pb0aYS>PN UU)Cow}z-(8;2&,@,]xFd#z`׬EEcBɒdub#1XtVu^SnΞ`/ƲwȦhXHcc#>i18@% ZP?23W~u/B)@ܥ bu%@/. tro!DbvE!B!B!BQї=`ln|$nIuYx/T~z@ej$^2L QVA25LK'4$ϝ #WǻH~"gZ Bfr343o[">4.ẇ~4#|ʚ$q.0!oJ! -(8̬0320!Je9;Mm.P6D`0(fP'ͧ-[ Nyz Ω.vX`au~ `=k9&jU'lGq-pxkq8]b`ljkkWlSwWs(Vٹ9 D'<=6JTlSZ{EӼcIŇ1;q8@=$: 6unc4霠i f tZ ݼP[[[Ui@43N@_DV5vsiN;<~\S4[?~0ۼcXK ̴uz7X :M۩Y&R3՟ *z'"`ǽ<.:=A_9DW@j,hxr= m`(`H=%?ζ*̚:^oۥ M_('0 lP65:ܳu5Lb⫽N pXn@AHDtt?|61~"/p/0Jf G;2f̈f_f @ 8]u_(Ԙ5h` .w\C%_4>vM/#B7<.5q: mi|Fd;NR.J| f+;䭫p&t:GgYu\>($8z{diP.F\5;/x.'l5 |%WNe^{NK FՔqRra(㲧^t^75 { |> _=Ϲ\.WUyz4uä ugvnuz`cpgvl/Z2WM@4ܯ ll.+'¥KaD@;]>TC|r9uT;~mDSuET}13Z7۲J؛j^C/i@z|+~Pƍ1vφ|kj;pz!Wá7xU:8A6yA;&܌`1 Egcs4$߰^㛩Yj?m%PzV y72LV z,=m\m M۔^0r BGm.LfjX҃pEzޕ`,C=˂'p b6&fΝY | ɰnHd-0K<^ƿvoĉRV?{ffLPccԩvpɏ}>_cnq(<ܷk̵ =H6-[ T/ĕw쓛k.: ,it0̑It}5knjJ gz~UsuTJ%,&:S1F 1psjR ?R}Egt$Yr3NN{VL>AU]vt]q #YD/A]= z YD6}jT麵s#铐<&SRNsLͭ[߾zP/q:g'JH $7_Gz]Ї^NK=ձ }7c+0ogo)hҲɳXӷn&ԾP Bk 1#khuuCY(c?Pc y@g< ]&"jL:g&8&郞@ɊwaX;ѣ]xK=Ngj:]O{<%Ri ~yڵ\Db JJ~w \ yRDž>2Lp8ekt:G{HzQHeGW"q*aıļy]NUU,哔Х577泥W2@gztnxNf禎_K\'捕z![7Z>;5 C_ hYEkãv~N2M:ծ:a ch4z n=N:W3C \n4h> U}NgR{n dCss~ӵ uܷI5#J"}15 WحOE<|p@ tnX3vG$*üDx1NcFFP?Cz`֝b HǸtLq"rٱK.O6Qsyq8U~MMMf,Dym y&4(@7 5 3E/v]邟3>dЂ|Bɼ$Nkk3Ab|mHh7 cN#czkê4ںņ` 3E躤(/q=}B?xfA) X#F)88P iZ)c(8=C?z9w+>ug8BWj:win DBSh(hS-NQ1xVl6YfBБ@ PyG"kv"Y<LvCYDC9uvژt[|PW]C : d;%q550_c Ś*ROP:F.r_FzVH:v‡d/|rmn{;mӂGO0U0^^J4Sq5*@L+M*no9Rg(&kcuo`1L~?:D)7}aODa9T+7BnNT;FG #include #include #include #include #include #include #include #include #ifdef __APPLE__ # include #endif /* __APPLE__ */ #ifdef __linux /* * does not define termios2 structure, but * is not compatible with header... */ struct termios2 { tcflag_t c_iflag; /* input mode flags */ tcflag_t c_oflag; /* output mode flags */ tcflag_t c_cflag; /* control mode flags */ tcflag_t c_lflag; /* local mode flags */ cc_t c_line; /* line discipline */ cc_t c_cc[NCCS]; /* control characters */ speed_t c_ispeed; /* input speed */ speed_t c_ospeed; /* output speed */ }; #endif /* __linux */ #ifndef WIN32 # include # include # include #endif /* !WIN32 */ /* * Local types... */ typedef struct gcode_buffer_s /**** Buffer for G-code status lines ****/ { char buffer[8192], /* Buffer */ *bufptr; /* Pointer info buffer */ size_t bytes; /* Bytes in buffer */ } gcode_buffer_t; /* * Local globals... */ static int Verbosity = 0; /* Log level */ /* * Local functions... */ static int gcode_fill(gcode_buffer_t *buf, int device_fd, int wait_secs); static char *gcode_gets(gcode_buffer_t *buf); static int gcode_puts(gcode_buffer_t *buf, int device_fd, char *line, int linenum); static int load_env_options(cups_option_t **options); static int open_device(const char *device_uri); static void usage(int status) __attribute__((noreturn)); static int xform_document(const char *filename, const char *outformat, int num_options, cups_option_t *options, gcode_buffer_t *buf, int device_fd); /* * 'main()' - Main entry for transform utility. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ const char *filename = NULL, /* File to transform */ *content_type, /* Source content type */ *device_uri, /* Destination URI */ *output_type, /* Destination content type */ *opt; /* Option character */ int num_options; /* Number of options */ cups_option_t *options; /* Options */ int fd = 1; /* Output file/socket */ int status = 0; /* Exit status */ gcode_buffer_t buffer; /* G-code response buffer */ /* * Process the command-line... */ num_options = load_env_options(&options); content_type = getenv("CONTENT_TYPE"); device_uri = getenv("DEVICE_URI"); output_type = getenv("OUTPUT_TYPE"); if ((opt = getenv("SERVER_LOGLEVEL")) != NULL) { if (!strcmp(opt, "debug")) Verbosity = 2; else if (!strcmp(opt, "info")) Verbosity = 1; } for (i = 1; i < argc; i ++) { if (argv[i][0] == '-' && argv[i][1] != '-') { for (opt = argv[i] + 1; *opt; opt ++) { switch (*opt) { case 'd' : i ++; if (i >= argc) usage(1); device_uri = argv[i]; break; case 'i' : i ++; if (i >= argc) usage(1); content_type = argv[i]; break; case 'm' : i ++; if (i >= argc) usage(1); output_type = argv[i]; break; case 'o' : i ++; if (i >= argc) usage(1); num_options = cupsParseOptions(argv[i], num_options, &options); break; case 'v' : /* Be verbose... */ Verbosity ++; break; default : fprintf(stderr, "ERROR: Unknown option '-%c'.\n", *opt); usage(1); break; } } } else if (!strcmp(argv[i], "--help")) usage(0); else if (!strncmp(argv[i], "--", 2)) { fprintf(stderr, "ERROR: Unknown option '%s'.\n", argv[i]); usage(1); } else if (!filename) filename = argv[i]; else usage(1); } /* * Check that we have everything we need... */ if (!filename) usage(1); if (!content_type) { if ((opt = strrchr(filename, '.')) != NULL) { if (!strcmp(opt, ".3mf")) content_type = "model/3mf"; else if (!strcmp(opt, ".stl")) content_type = "application/sla"; } } if (!content_type) { fprintf(stderr, "ERROR: Unknown format for \"%s\", please specify with '-i' option.\n", filename); usage(1); } else if (strcmp(content_type, "application/sla") && strcmp(content_type, "model/3mf")) { fprintf(stderr, "ERROR: Unsupported format \"%s\" for \"%s\".\n", content_type, filename); usage(1); } if (!output_type) { fputs("ERROR: Unknown output format, please specify with '-m' option.\n", stderr); usage(1); } else if (strcmp(output_type, "application/g-code") && strncmp(output_type, "application/g-code;", 19)) { fprintf(stderr, "ERROR: Unsupported output format \"%s\".\n", output_type); usage(1); } /* * If the device URI is specified, open the connection... */ if (device_uri) { if (strncmp(device_uri, "usbserial:///dev/", 17)) { fprintf(stderr, "ERROR: Unsupported device URI \"%s\".\n", device_uri); usage(1); } fd = open_device(device_uri); /* * Initialize the G-code response buffer and wait for the printer to send * us its firmware information, etc. */ memset(&buffer, 0, sizeof(buffer)); buffer.bufptr = buffer.buffer; while (gcode_fill(&buffer, fd, 15)) { const char *info; /* Information from printer */ while ((info = gcode_gets(&buffer)) != NULL) fprintf(stderr, "DEBUG: %s\n", info); } } /* * Do transform... */ status = xform_document(filename, output_type, num_options, options, &buffer, fd); gcode_puts(&buffer, fd, "", 1); if (fd != 1) close(fd); return (status); } /* * 'gcode_fill()' - Fill the G-code buffer with more data... */ static int /* O - 1 on success, 0 on failure */ gcode_fill(gcode_buffer_t *buf, /* I - Buffer */ int device_fd, /* I - Device file descriptor */ int wait_secs) /* I - Timeout in seconds */ { ssize_t bytes; /* Bytes read */ if (wait_secs > 0) { /* * Wait for data ready... */ fd_set input; /* select() mask */ struct timeval timeout; /* Timeout */ FD_ZERO(&input); FD_SET(device_fd, &input); timeout.tv_sec = wait_secs; timeout.tv_usec = 0; while (select(device_fd + 1, &input, NULL, NULL, &timeout) < 0) { if (errno != EINTR) return (0); } if (!FD_ISSET(device_fd, &input)) return (0); } if (buf->bufptr > buf->buffer) { /* * Compact remaining bytes in buffer... */ bytes = buf->bufptr - buf->buffer; if (bytes < buf->bytes) memmove(buf->buffer, buf->bufptr, buf->bytes - (size_t)bytes); buf->bufptr = buf->buffer; buf->bytes -= (size_t)bytes; } /* * Read more bytes into the buffer... */ while ((bytes = read(device_fd, buf->buffer + buf->bytes, sizeof(buf->buffer) - buf->bytes - 1)) < 0) { if (errno != EINTR) return (0); } buf->bytes += (size_t)bytes; buf->buffer[buf->bytes] = '\0'; return (1); } /* * 'gcode_gets()' - Get a line from the G-code buffer. */ static char * /* O - Line or NULL if no full line */ gcode_gets(gcode_buffer_t *buf) /* I - Buffer */ { char *start = buf->bufptr; char *end = strchr(start, '\n'); if (end) { *end++ = '\0'; buf->bufptr = end; return (start); } else if (start == buf->buffer && buf->bytes == (sizeof(buf->buffer) - 1)) { buf->bufptr = buf->buffer + buf->bytes; return (buf->buffer); } else return (NULL); } /* * 'gcode_puts()' - Write a line of G-code, complete with line number and checksum. */ static int /* O - Next line number */ gcode_puts(gcode_buffer_t *buf, /* I - G-code buffer */ int device_fd, /* I - Device file */ char *line, /* I - Line from G-code file */ int linenum) /* I - Line number in G-code file */ { char buffer[8192], /* Output buffer */ *ptr; /* Pointer into line/buffer */ unsigned char checksum; /* XOR checksum */ size_t len; /* Length of output buffer remaining */ ssize_t bytes; /* Bytes written */ int ok = 0; /* Line written OK? */ /* * First eliminate any trailing comments and whitespace... */ if ((ptr = strchr(line, ';')) != NULL) *ptr = '\0'; ptr = line + strlen(line) - 1; while (ptr >= line && isspace(*ptr & 255)) *ptr-- = '\0'; if (!line[0]) return (linenum); /* Nothing left... */ /* * Then compute a simple XOR checksum and format the output line... */ snprintf(buffer, sizeof(buffer), "N%d %s", linenum, line); for (ptr = buffer, checksum = 0; *ptr; ptr ++) checksum ^= (unsigned char)*ptr; snprintf(buffer, sizeof(buffer), "N%d %s*%d\n", linenum ++, line, checksum); fprintf(stderr, "DEBUG: >%s", buffer); /* * Finally, write the line to the output device and wait for an OK... */ do { char *resp; /* Response from printer */ for (ptr = buffer, len = strlen(buffer); len > 0;) { if ((bytes = write(device_fd, ptr, len)) < 0) { if (errno != EAGAIN && errno != EINTR && errno != ENOTTY) return (-1); } else { len -= (size_t)bytes; ptr += bytes; } } tcdrain(device_fd); do { while ((resp = gcode_gets(buf)) == NULL) { if (!gcode_fill(buf, device_fd, 30)) { fputs("DEBUG: No response from printer.\n", stderr); return (-1); } } fprintf(stderr, "DEBUG: %s\n", resp); if (!resp) { fputs("DEBUG: Unable to read response from printer.\n", stderr); return (-1); } } while (strcmp(resp, "ok") && strncmp(resp, "Resend:", 7)); if (!strncmp(resp, "Resend:", 7)) { if (atoi(resp + 7) != (linenum - 1)) { fprintf(stderr, "DEBUG: Printer asked us to resend a previous line (%s, on line %d)\n", resp + 7, linenum); return (-1); } ok = 0; } else ok = 1; } while (!ok); return (linenum); } /* * 'load_env_options()' - Load options from the environment. */ extern char **environ; static int /* O - Number of options */ load_env_options( cups_option_t **options) /* I - Options */ { int i; /* Looping var */ char name[256], /* Option name */ *nameptr, /* Pointer into name */ *envptr; /* Pointer into environment variable */ int num_options = 0; /* Number of options */ *options = NULL; /* * Load all of the IPP_xxx environment variables as options... */ for (i = 0; environ[i]; i ++) { envptr = environ[i]; if (strncmp(envptr, "IPP_", 4)) continue; for (nameptr = name, envptr += 4; *envptr && *envptr != '='; envptr ++) { if (nameptr > (name + sizeof(name) - 1)) continue; if (*envptr == '_') *nameptr++ = '-'; else *nameptr++ = (char)_cups_tolower(*envptr); } *nameptr = '\0'; if (*envptr == '=') envptr ++; num_options = cupsAddOption(name, envptr, num_options, options); } return (num_options); } /* * 'open_device()' - Open a serial port device... */ static int /* O - File descriptor or -1 on error */ open_device(const char *device_uri) /* I - Device URI */ { char filename[1024], /* Device filename */ *options; /* Pointer to options */ int device_fd, /* Serial device */ device_state; /* Serial control lines */ #ifdef __linux struct termios2 opts; /* Serial port options */ #else struct termios opts; /* Serial port options */ #endif /* __linux */ int baud = 250000; /* Baud rate */ /* * Open the serial port device... */ if (strncmp(device_uri, "usbserial:///dev/", 17)) return (-1); strlcpy(filename, device_uri + 12, sizeof(filename)); if ((options = strchr(filename, '?')) != NULL) *options++ = '\0'; do { if ((device_fd = open(filename, O_RDWR | O_NOCTTY | O_EXCL | O_NDELAY)) == -1) { if (errno == EBUSY) { fputs("INFO: Printer busy; will retry in 30 seconds.\n", stderr); sleep(30); } else { fprintf(stderr, "ERROR: Unable to open device file \"%s\": %s\n", filename, strerror(errno)); return (-1); } } } while (device_fd < 0); /* * Set any options provided... */ tcgetattr(device_fd, (struct termios *)&opts); cfmakeraw((struct termios *)&opts); opts.c_cflag |= CREAD | CLOCAL; /* Enable reader */ opts.c_cflag &= (unsigned)~CRTSCTS; /* No RTS/CTS flow control */ opts.c_cflag &= (unsigned)~CSIZE; /* 8-bits */ opts.c_cflag |= CS8; opts.c_cflag &= (unsigned)~PARENB; /* No parity */ opts.c_cflag &= (unsigned)~CSTOPB; /* 1 stop bit */ if (options && !strncasecmp(options, "baud=", 5)) { /* * Set the baud rate... */ baud = atoi(options + 5); } /* * Set serial port settings and then toggle DTR... */ #ifdef __APPLE__ /* USB serial doesn't follow POSIX, grrr... */ cfsetispeed(&opts, B9600); cfsetospeed(&opts, B9600); tcsetattr(device_fd, TCSANOW, &opts); ioctl(device_fd, IOSSIOSPEED, &baud); #elif defined(__linux) /* Linux needs to use non-POSIX termios2 ioctl, grrr... */ opts.c_cflag &= (unsigned)~CBAUD; // opts.c_cflag != BOTHER; opts.c_ospeed = opts.c_ispeed = (speed_t)baud; ioctl(device_fd, TCSETS2, &opts); #else /* Other platforms default to POSIX termios */ /* TODO: Add support for older platforms where B9600 != 9600, etc. */ cfsetispeed(&opts, baud); cfsetospeed(&opts, baud); tcsetattr(device_fd, TCSANOW, &opts); #endif /* __APPLE__ */ fcntl(device_fd, F_SETFL, 0); ioctl(device_fd, TIOCMGET, &device_state); device_state |= TIOCM_DTR; ioctl(device_fd, TIOCMSET, &device_state); usleep(100000); device_state &= ~TIOCM_DTR; ioctl(device_fd, TIOCMSET, &device_state); return (device_fd); } /* * 'usage()' - Show program usage. */ static void usage(int status) /* I - Exit status */ { puts("Usage: ipptransform [options] filename\n"); puts("Options:"); puts(" --help"); puts(" -d device-uri"); puts(" -i input/format"); puts(" -m output/format"); puts(" -o \"name=value [... name=value]\""); puts(" -v\n"); puts("Device URIs: usbserial:///dev/..."); puts("Input Formats: application/sla, model/3mf"); puts("Output Formats: application/g-code;machine=FOO"); puts("Options: materials-col, platform-temperature, print-accuracy, print-base, print-quality, print-supports"); exit(status); } /* * 'xform_document()' - Transform and print a document. */ static int /* O - 0 on success, 1 on failure */ xform_document( const char *filename, /* I - Input file */ const char *outformat, /* I - Output format */ int num_options, /* I - Number of options */ cups_option_t *options, /* I - Options */ gcode_buffer_t *buf, /* I - G-code response buffer */ int device_fd) /* I - Device file */ { #ifdef WIN32 return (0); #else int i; /* Looping var */ const char *val; /* Option value */ int pid, /* Process ID */ status; /* Exit status */ const char *myargv[100]; /* Command-line arguments */ int myargc; /* Number of arguments */ const char *machine; /* Machine name in output format */ char curapath[1024], /* CuraEngine path */ json[1024], /* JSON settings name */ material_temp[1024], /* Extruder temperature setting */ platform_temp[1024]; /* Platform temperature setting */ posix_spawn_file_actions_t actions; /* Spawn file actions */ int mystdout[2] = {-1, -1}; /* Pipe for stdout */ struct pollfd polldata[2]; /* Poll data */ int pollcount; /* Number of pipes to poll */ char data[32768], /* Data from stdout */ *dataptr, /* Pointer to end of data */ *ptr, /* Pointer into data */ *end; /* End of data */ ssize_t bytes; /* Bytes read */ int linenum = 1; /* G-code line number */ int platform, /* platform-temperature value */ material, /* material-temperature value */ quality; /* print-quality value */ const char *base, /* print-base value */ *supports; /* print-supports value */ /* * Look for the machine name in the output format... */ if ((machine = strstr(outformat, ";machine=")) != NULL) machine += 9; else machine = "ultimaker2"; strlcpy(curapath, CURAENGINE, sizeof(curapath)); if ((ptr = strstr(curapath, "Cura.app/")) != NULL) { /* * macOS bundle, locate the resources within the bundle... */ ptr[8] = '\0'; /* Trim at slash... */ snprintf(json, sizeof(json), "%s/Contents/Resources/resources/definitions/%s.def.json", curapath, machine); } else if ((ptr = strstr(curapath, "/bin/CuraEngine")) != NULL) { /* * Standard install, use the same prefix but look under "prefix/share/CuraEngine/"... */ *ptr = '\0'; snprintf(json, sizeof(json), "%s/share/CuraEngine/resources/definitions/%s.def.json", curapath, machine); } else { /* * Rely on CURA_ENGINE_SEARCH_PATH... */ snprintf(json, sizeof(json), "%s.def.json", machine); } /* * Setup the CuraEngine command-line arguments... */ myargv[0] = CURAENGINE; myargc = 1; myargv[myargc++] = "slice"; myargv[myargc++] = "-vv"; myargv[myargc++] = "-j"; myargv[myargc++] = json; myargv[myargc++] = "-s"; myargv[myargc++] = "machine_gcode_flavor=0"; /* * Get the extruder and build platform temperatures... */ if ((val = cupsGetOption("platform-temperature", num_options, options)) != NULL) platform = atoi(val); else if ((val = getenv("PRINTER_PLATFORM_TEMPERATURE_DEFAULT")) != NULL) platform = atoi(val); else platform = 0; if (platform > 0) { fprintf(stderr, "DEBUG: Build platform temperature is %dC...\n", platform); snprintf(platform_temp, sizeof(platform_temp), "material_bed_temperature=%d", platform); myargv[myargc++] = "-s"; myargv[myargc++] = platform_temp; } if ((val = cupsGetOption("materials-col", num_options, options)) == NULL) val = getenv("PRINTER_MATERIALS_COL_DEFAULT"); if (val) fprintf(stderr, "DEBUG: materials-col=%s\n", val); if (val && (ptr = strstr(val, "material-temperature=")) != NULL) { /* TODO: Support multiple materials */ material = atoi(ptr + 21); snprintf(material_temp, sizeof(material_temp), "material_print_temperature=%d", platform); fprintf(stderr, "DEBUG: Extruder temperature is %dC...\n", material); myargv[myargc++] = "-s"; myargv[myargc++] = material_temp; } /* * Get the print accuracy settings... */ /* TODO: Support print-accuracy */ /* * Get the print quality settings... */ if ((val = cupsGetOption("print-quality", num_options, options)) != NULL) quality = atoi(val); else if ((val = getenv("PRINTER_PRINT_QUALITY_DEFAULT")) != NULL) quality = atoi(val); else quality = 4; /* Normal */ /* TODO: Sigh, fix all of the print quality settings since the latest CuraEngine has renamed them all... */ switch (quality) { case 3 : /* Draft */ myargv[myargc++] = "-s"; myargv[myargc++] = "insetXSpeed=60"; myargv[myargc++] = "-s"; myargv[myargc++] = "inset0Speed=60"; myargv[myargc++] = "-s"; myargv[myargc++] = "extrusionWidth=500"; myargv[myargc++] = "-s"; myargv[myargc++] = "upSkinCount=3"; myargv[myargc++] = "-s"; myargv[myargc++] = "initialLayerSpeed=30"; myargv[myargc++] = "-s"; myargv[myargc++] = "minimalLayerTime=3"; myargv[myargc++] = "-s"; myargv[myargc++] = "infillSpeed=60"; myargv[myargc++] = "-s"; myargv[myargc++] = "initialLayerThickness=300"; myargv[myargc++] = "-s"; myargv[myargc++] = "layerThickness=200"; myargv[myargc++] = "-s"; myargv[myargc++] = "printSpeed=60"; myargv[myargc++] = "-s"; myargv[myargc++] = "layer0extrusionWidth=500"; myargv[myargc++] = "-s"; myargv[myargc++] = "sparseInfillLineDistance=5000"; myargv[myargc++] = "-s"; myargv[myargc++] = "downSkinCount=3"; break; case 5 : /* High */ myargv[myargc++] = "-s"; myargv[myargc++] = "insetXSpeed=50"; myargv[myargc++] = "-s"; myargv[myargc++] = "inset0Speed=50"; myargv[myargc++] = "-s"; myargv[myargc++] = "extrusionWidth=400"; myargv[myargc++] = "-s"; myargv[myargc++] = "upSkinCount=10"; myargv[myargc++] = "-s"; myargv[myargc++] = "initialLayerSpeed=15"; myargv[myargc++] = "-s"; myargv[myargc++] = "minimalLayerTime=5"; myargv[myargc++] = "-s"; myargv[myargc++] = "infillSpeed=50"; myargv[myargc++] = "-s"; myargv[myargc++] = "initialLayerThickness=300"; myargv[myargc++] = "-s"; myargv[myargc++] = "layerThickness=60"; myargv[myargc++] = "-s"; myargv[myargc++] = "printSpeed=50"; myargv[myargc++] = "-s"; myargv[myargc++] = "layer0extrusionWidth=400"; myargv[myargc++] = "-s"; myargv[myargc++] = "sparseInfillLineDistance=2000"; myargv[myargc++] = "-s"; myargv[myargc++] = "downSkinCount=10"; break; default : /* Normal/default */ myargv[myargc++] = "-s"; myargv[myargc++] = "insetXSpeed=50"; myargv[myargc++] = "-s"; myargv[myargc++] = "inset0Speed=50"; myargv[myargc++] = "-s"; myargv[myargc++] = "extrusionWidth=400"; myargv[myargc++] = "-s"; myargv[myargc++] = "upSkinCount=6"; myargv[myargc++] = "-s"; myargv[myargc++] = "initialLayerSpeed=20"; myargv[myargc++] = "-s"; myargv[myargc++] = "minimalLayerTime=5"; myargv[myargc++] = "-s"; myargv[myargc++] = "infillSpeed=50"; myargv[myargc++] = "-s"; myargv[myargc++] = "initialLayerThickness=300"; myargv[myargc++] = "-s"; myargv[myargc++] = "layerThickness=100"; myargv[myargc++] = "-s"; myargv[myargc++] = "endCode=M25"; myargv[myargc++] = "-s"; myargv[myargc++] = "printSpeed=50"; myargv[myargc++] = "-s"; myargv[myargc++] = "layer0extrusionWidth=400"; myargv[myargc++] = "-s"; myargv[myargc++] = "sparseInfillLineDistance=2000"; myargv[myargc++] = "-s downSkinCount=6"; break; } /* * Get the print base settings... */ if ((base = cupsGetOption("print-base", num_options, options)) == NULL) if ((base = getenv("PRINTER_PRINT_BASE_DEFAULT")) == NULL) base = "none"; if (!strcmp(base, "brim")) { /* * Print a brim... */ /* TODO: Add brim settings */ } else if (!strcmp(base, "raft")) { /* * Print a raft... */ myargv[myargc++] = "-s"; myargv[myargc++] = "raftSurfaceLineSpacing=400"; myargv[myargc++] = "-s"; myargv[myargc++] = "raftInterfaceLineSpacing=800"; myargv[myargc++] = "-s"; myargv[myargc++] = "raftSurfaceSpeed=20"; myargv[myargc++] = "-s"; myargv[myargc++] = "raftBaseSpeed=20"; myargv[myargc++] = "-s"; myargv[myargc++] = "raftFanSpeed=0"; myargv[myargc++] = "-s"; myargv[myargc++] = "raftSurfaceThickness=270"; myargv[myargc++] = "-s"; myargv[myargc++] = "raftBaseThickness=300"; myargv[myargc++] = "-s"; myargv[myargc++] = "raftMargin=5000"; myargv[myargc++] = "-s"; myargv[myargc++] = "raftAirGap=0"; myargv[myargc++] = "-s"; myargv[myargc++] = "raftInterfaceThickness=270"; myargv[myargc++] = "-s"; myargv[myargc++] = "raftSurfaceLayers=2"; myargv[myargc++] = "-s"; myargv[myargc++] = "raftSurfaceLinewidth=400"; myargv[myargc++] = "-s"; myargv[myargc++] = "raftInterfaceLinewidth=400"; myargv[myargc++] = "-s"; myargv[myargc++] = "raftBaseLinewidth=1000"; myargv[myargc++] = "-s"; myargv[myargc++] = "raftAirGapLayer0=220"; } else if (!strcmp(base, "skirt")) { /* * Print a skirt... */ /* TODO: Add skirt settings */ } if ((supports = cupsGetOption("print-supports", num_options, options)) == NULL) if ((supports = getenv("PRINTER_PRINT_SUPPORTS_DEFAULT")) == NULL) supports = "none"; if (strcmp(supports, "none")) { /* * Print supports... */ myargv[myargc++] = "-s"; myargv[myargc++] = "supportAngle=60"; myargv[myargc++] = "-s"; myargv[myargc++] = "supportXYDistance=700"; myargv[myargc++] = "-s"; myargv[myargc++] = "supportZDistance=150"; myargv[myargc++] = "-s"; myargv[myargc++] = "supportEverywhere=0"; myargv[myargc++] = "-s"; myargv[myargc++] = "supportLineDistance=3333"; myargv[myargc++] = "-s"; myargv[myargc++] = "supportType=0"; } myargv[myargc++] = "-l"; myargv[myargc++] = (char *)filename; myargv[myargc ] = NULL; fprintf(stderr, "DEBUG: %s", myargv[0]); for (i = 1; i < myargc; i ++) fprintf(stderr, " %s", myargv[i]); fputs("\n", stderr); if (pipe(mystdout)) { fprintf(stderr, "ERROR: Unable to create pipe for stdout: %s\n", strerror(errno)); return (1); } posix_spawn_file_actions_init(&actions); posix_spawn_file_actions_addopen(&actions, 0, "/dev/null", O_RDONLY, 0); if (mystdout[1] < 0) posix_spawn_file_actions_addopen(&actions, 1, "/dev/null", O_WRONLY, 0); else posix_spawn_file_actions_adddup2(&actions, mystdout[1], 1); if (posix_spawn(&pid, myargv[0], &actions, NULL, (char **)myargv, environ)) { fprintf(stderr, "ERROR: Unable to start CuraEngine command: %s", strerror(errno)); posix_spawn_file_actions_destroy(&actions); return (1); } fprintf(stderr, "DEBUG: Started CuraEngine command, pid=%d\n", pid); /* * Free memory used for command... */ posix_spawn_file_actions_destroy(&actions); /* * Read from the stdout and stderr pipes until EOF... */ close(mystdout[1]); pollcount = 0; polldata[pollcount].fd = mystdout[0]; polldata[pollcount].events = POLLIN; pollcount ++; polldata[pollcount].fd = device_fd; polldata[pollcount].events = POLLIN; pollcount ++; dataptr = data; while (poll(polldata, (nfds_t)pollcount, -1)) { if (polldata[1].revents & POLLIN) { /* * Read status info back (eventually do something with it...) */ if (gcode_fill(buf, device_fd, 0)) { while ((ptr = gcode_gets(buf)) != NULL) fprintf(stderr, "DEBUG: %s\n", ptr); } } if (polldata[0].revents & POLLIN) { /* * Read G-code... */ if ((bytes = read(mystdout[0], dataptr, sizeof(data) - (size_t)(dataptr - data + 1))) > 0) { dataptr += bytes; *dataptr = '\0'; for (end = data; (ptr = strchr(end, '\n')) != NULL; end = ptr) { /* * Send whole lines to the printer... */ *ptr++ = '\0'; if ((linenum = gcode_puts(buf, device_fd, end, linenum)) < 0) { perror("ERROR: Unable to write print data"); break; } } if (end > data) { /* * Copy remainder to beginning of buffer... */ dataptr -= (end - data); if (dataptr > data) memmove(data, end, (size_t)(dataptr - data)); } } } } close(mystdout[0]); /* * Wait for child to complete... */ # ifdef HAVE_WAITPID while (waitpid(pid, &status, 0) < 0); # else while (wait(&status) < 0); # endif /* HAVE_WAITPID */ return (status); #endif /* WIN32 */ } ippsample/tools/Makefile0000644000175000017500000000400513240604116014336 0ustar tilltill# # IPP tools makefile. # # Copyright © 2014-2018 by the IEEE-ISTO Printer Working Group. # Copyright © 2007-2018 by Apple Inc. # Copyright © 1997-2006 by Easy Software Products, all rights reserved. # # Licensed under Apache License v2.0. See the file "LICENSE" for more # information. # include ../Makedefs OBJS = \ ippfind.o \ ippproxy.o \ ipptool.o \ ipptransform.o \ ipptransform3d.o TARGETS = \ $(BIN_TARGETS) \ $(SBIN_TARGETS) BIN_TARGETS = \ $(IPPFIND_BIN) \ ipptool \ $(IPPTRANSFORM_BIN) \ $(IPPTRANSFORM3D_BIN) SBIN_TARGETS = \ ippproxy # # Make all targets... # all: $(TARGETS) # # Clean all object files... # clean: $(RM) $(TARGETS) $(OBJS) # # Update dependencies (without system header dependencies...) # depend: $(CC) -MM $(ALL_CFLAGS) $(OBJS:.o=.c) >Dependencies # # Install all tools. # install: all $(INSTALL_DIR) -m 755 $(BUILDROOT)$(bindir) for file in $(BIN_TARGETS); do \ destfile=`echo $$file | sed -e '1,$$s/^ipp/$(IPP)/'`; \ $(INSTALL_BIN) $$file $(BUILDROOT)$(bindir)/$$destfile; \ done $(INSTALL_DIR) -m 755 $(BUILDROOT)$(sbindir) for file in $(SBIN_TARGETS); do \ destfile=`echo $$file | sed -e '1,$$s/^ipp/$(IPP)/'`; \ $(INSTALL_BIN) $$file $(BUILDROOT)$(sbindir)/$$destfile; \ done # # Test all tools. # test: # # ippfind # ippfind: ippfind.o ../cups/libcups.a echo Linking $@... $(CC) $(LDFLAGS) -o $@ ippfind.o $(LIBS) # # ippproxy # ippproxy: ippproxy.o ../cups/libcups.a echo Linking $@... $(CC) $(LDFLAGS) -o $@ ippproxy.o $(LIBS) # # ipptool # ipptool: ipptool.o ../cups/libcups.a echo Linking $@... $(CC) $(LDFLAGS) -o $@ ipptool.o $(LIBS) # # ipptransform # ipptransform: ipptransform.o ../cups/libcups.a echo Linking $@... $(CC) $(LDFLAGS) -o $@ ipptransform.o $(LIBS) # # ipptransform3d # ipptransform3d: ipptransform3d.o ../cups/libcups.a echo Linking $@... $(CC) $(LDFLAGS) -o $@ ipptransform3d.o $(LIBS) # # Dependencies... # include Dependencies ippsample/tools/ippfind.c0000644000175000017500000022675513240604116014515 0ustar tilltill/* * Utility to find IPP printers via Bonjour/DNS-SD and optionally run * commands such as IPP and Bonjour conformance tests. This tool is * inspired by the UNIX "find" command, thus its name. * * Copyright 2008-2017 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ /* * Include necessary headers. */ #define _CUPS_NO_DEPRECATED #include #ifdef WIN32 # include # include #else # include #endif /* WIN32 */ #include #ifdef HAVE_DNSSD # include #elif defined(HAVE_AVAHI) # include # include # include # include # include # include # define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX #endif /* HAVE_DNSSD */ #ifndef WIN32 extern char **environ; /* Process environment variables */ #endif /* !WIN32 */ /* * Structures... */ typedef enum ippfind_exit_e /* Exit codes */ { IPPFIND_EXIT_TRUE = 0, /* OK and result is true */ IPPFIND_EXIT_FALSE, /* OK but result is false*/ IPPFIND_EXIT_BONJOUR, /* Browse/resolve failure */ IPPFIND_EXIT_SYNTAX, /* Bad option or syntax error */ IPPFIND_EXIT_MEMORY /* Out of memory */ } ippfind_exit_t; typedef enum ippfind_op_e /* Operations for expressions */ { /* "Evaluation" operations */ IPPFIND_OP_NONE, /* No operation */ IPPFIND_OP_AND, /* Logical AND of all children */ IPPFIND_OP_OR, /* Logical OR of all children */ IPPFIND_OP_TRUE, /* Always true */ IPPFIND_OP_FALSE, /* Always false */ IPPFIND_OP_IS_LOCAL, /* Is a local service */ IPPFIND_OP_IS_REMOTE, /* Is a remote service */ IPPFIND_OP_DOMAIN_REGEX, /* Domain matches regular expression */ IPPFIND_OP_NAME_REGEX, /* Name matches regular expression */ IPPFIND_OP_HOST_REGEX, /* Hostname matches regular expression */ IPPFIND_OP_PORT_RANGE, /* Port matches range */ IPPFIND_OP_PATH_REGEX, /* Path matches regular expression */ IPPFIND_OP_TXT_EXISTS, /* TXT record key exists */ IPPFIND_OP_TXT_REGEX, /* TXT record key matches regular expression */ IPPFIND_OP_URI_REGEX, /* URI matches regular expression */ /* "Output" operations */ IPPFIND_OP_EXEC, /* Execute when true */ IPPFIND_OP_LIST, /* List when true */ IPPFIND_OP_PRINT_NAME, /* Print URI when true */ IPPFIND_OP_PRINT_URI, /* Print name when true */ IPPFIND_OP_QUIET /* No output when true */ } ippfind_op_t; typedef struct ippfind_expr_s /* Expression */ { struct ippfind_expr_s *prev, /* Previous expression */ *next, /* Next expression */ *parent, /* Parent expressions */ *child; /* Child expressions */ ippfind_op_t op; /* Operation code (see above) */ int invert; /* Invert the result */ char *key; /* TXT record key */ regex_t re; /* Regular expression for matching */ int range[2]; /* Port number range */ int num_args; /* Number of arguments for exec */ char **args; /* Arguments for exec */ } ippfind_expr_t; typedef struct ippfind_srv_s /* Service information */ { #ifdef HAVE_DNSSD DNSServiceRef ref; /* Service reference for query */ #elif defined(HAVE_AVAHI) AvahiServiceResolver *ref; /* Resolver */ #endif /* HAVE_DNSSD */ char *name, /* Service name */ *domain, /* Domain name */ *regtype, /* Registration type */ *fullName, /* Full name */ *host, /* Hostname */ *resource, /* Resource path */ *uri; /* URI */ int num_txt; /* Number of TXT record keys */ cups_option_t *txt; /* TXT record keys */ int port, /* Port number */ is_local, /* Is a local service? */ is_processed, /* Did we process the service? */ is_resolved; /* Got the resolve data? */ } ippfind_srv_t; /* * Local globals... */ #ifdef HAVE_DNSSD static DNSServiceRef dnssd_ref; /* Master service reference */ #elif defined(HAVE_AVAHI) static AvahiClient *avahi_client = NULL;/* Client information */ static int avahi_got_data = 0; /* Got data from poll? */ static AvahiSimplePoll *avahi_poll = NULL; /* Poll information */ #endif /* HAVE_DNSSD */ static int address_family = AF_UNSPEC; /* Address family for LIST */ static int bonjour_error = 0; /* Error browsing/resolving? */ static double bonjour_timeout = 1.0; /* Timeout in seconds */ static int ipp_version = 20; /* IPP version for LIST */ /* * Local functions... */ #ifdef HAVE_DNSSD static void DNSSD_API browse_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) __attribute__((nonnull(1,5,6,7,8))); static void DNSSD_API browse_local_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) __attribute__((nonnull(1,5,6,7,8))); #elif defined(HAVE_AVAHI) static void browse_callback(AvahiServiceBrowser *browser, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *serviceName, const char *regtype, const char *replyDomain, AvahiLookupResultFlags flags, void *context); static void client_callback(AvahiClient *client, AvahiClientState state, void *context); #endif /* HAVE_AVAHI */ static int compare_services(ippfind_srv_t *a, ippfind_srv_t *b); static const char *dnssd_error_string(int error); static int eval_expr(ippfind_srv_t *service, ippfind_expr_t *expressions); static int exec_program(ippfind_srv_t *service, int num_args, char **args); static ippfind_srv_t *get_service(cups_array_t *services, const char *serviceName, const char *regtype, const char *replyDomain) __attribute__((nonnull(1,2,3,4))); static double get_time(void); static int list_service(ippfind_srv_t *service); static ippfind_expr_t *new_expr(ippfind_op_t op, int invert, const char *value, const char *regex, char **args); #ifdef HAVE_DNSSD static void DNSSD_API resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullName, const char *hostTarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context) __attribute__((nonnull(1,5,6,9, 10))); #elif defined(HAVE_AVAHI) static int poll_callback(struct pollfd *pollfds, unsigned int num_pollfds, int timeout, void *context); static void resolve_callback(AvahiServiceResolver *res, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *serviceName, const char *regtype, const char *replyDomain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *context); #endif /* HAVE_DNSSD */ static void set_service_uri(ippfind_srv_t *service); static void show_usage(void) __attribute__((noreturn)); static void show_version(void) __attribute__((noreturn)); /* * 'main()' - Browse for printers. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line arguments */ { int i, /* Looping var */ have_output = 0,/* Have output expression */ status = IPPFIND_EXIT_FALSE; /* Exit status */ const char *opt, /* Option character */ *search; /* Current browse/resolve string */ cups_array_t *searches; /* Things to browse/resolve */ cups_array_t *services; /* Service array */ ippfind_srv_t *service; /* Current service */ ippfind_expr_t *expressions = NULL, /* Expression tree */ *temp = NULL, /* New expression */ *parent = NULL, /* Parent expression */ *current = NULL,/* Current expression */ *parens[100]; /* Markers for parenthesis */ int num_parens = 0; /* Number of parenthesis */ ippfind_op_t logic = IPPFIND_OP_AND; /* Logic for next expression */ int invert = 0; /* Invert expression? */ int err; /* DNS-SD error */ #ifdef HAVE_DNSSD fd_set sinput; /* Input set for select() */ struct timeval stimeout; /* Timeout for select() */ #endif /* HAVE_DNSSD */ double endtime; /* End time */ static const char * const ops[] = /* Node operation names */ { "NONE", "AND", "OR", "TRUE", "FALSE", "IS_LOCAL", "IS_REMOTE", "DOMAIN_REGEX", "NAME_REGEX", "HOST_REGEX", "PORT_RANGE", "PATH_REGEX", "TXT_EXISTS", "TXT_REGEX", "URI_REGEX", "EXEC", "LIST", "PRINT_NAME", "PRINT_URI", "QUIET" }; /* * Initialize the locale... */ _cupsSetLocale(argv); /* * Create arrays to track services and things we want to browse/resolve... */ searches = cupsArrayNew(NULL, NULL); services = cupsArrayNew((cups_array_func_t)compare_services, NULL); /* * Parse command-line... */ if (getenv("IPPFIND_DEBUG")) for (i = 1; i < argc; i ++) fprintf(stderr, "argv[%d]=\"%s\"\n", i, argv[i]); for (i = 1; i < argc; i ++) { if (argv[i][0] == '-') { if (argv[i][1] == '-') { /* * Parse --option options... */ if (!strcmp(argv[i], "--and")) { if (logic == IPPFIND_OP_OR) { _cupsLangPuts(stderr, _("ippfind: Cannot use --and after --or.")); show_usage(); } if (!current) { _cupsLangPuts(stderr, _("ippfind: Missing expression before \"--and\".")); show_usage(); } temp = NULL; } else if (!strcmp(argv[i], "--domain")) { i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Missing regular expression after %s."), "--domain"); show_usage(); } if ((temp = new_expr(IPPFIND_OP_DOMAIN_REGEX, invert, NULL, argv[i], NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); } else if (!strcmp(argv[i], "--exec")) { i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Expected program after %s."), "--exec"); show_usage(); } if ((temp = new_expr(IPPFIND_OP_EXEC, invert, NULL, NULL, argv + i)) == NULL) return (IPPFIND_EXIT_MEMORY); while (i < argc) if (!strcmp(argv[i], ";")) break; else i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Expected semi-colon after %s."), "--exec"); show_usage(); } have_output = 1; } else if (!strcmp(argv[i], "--false")) { if ((temp = new_expr(IPPFIND_OP_FALSE, invert, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); } else if (!strcmp(argv[i], "--help")) { show_usage(); } else if (!strcmp(argv[i], "--host")) { i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Missing regular expression after %s."), "--host"); show_usage(); } if ((temp = new_expr(IPPFIND_OP_HOST_REGEX, invert, NULL, argv[i], NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); } else if (!strcmp(argv[i], "--ls")) { if ((temp = new_expr(IPPFIND_OP_LIST, invert, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); have_output = 1; } else if (!strcmp(argv[i], "--local")) { if ((temp = new_expr(IPPFIND_OP_IS_LOCAL, invert, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); } else if (!strcmp(argv[i], "--name")) { i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Missing regular expression after %s."), "--name"); show_usage(); } if ((temp = new_expr(IPPFIND_OP_NAME_REGEX, invert, NULL, argv[i], NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); } else if (!strcmp(argv[i], "--not")) { invert = 1; } else if (!strcmp(argv[i], "--or")) { if (!current) { _cupsLangPuts(stderr, _("ippfind: Missing expression before \"--or\".")); show_usage(); } logic = IPPFIND_OP_OR; if (parent && parent->op == IPPFIND_OP_OR) { /* * Already setup to do "foo --or bar --or baz"... */ temp = NULL; } else if (!current->prev && parent) { /* * Change parent node into an OR node... */ parent->op = IPPFIND_OP_OR; temp = NULL; } else if (!current->prev) { /* * Need to group "current" in a new OR node... */ if ((temp = new_expr(IPPFIND_OP_OR, 0, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); temp->parent = parent; temp->child = current; current->parent = temp; if (parent) parent->child = temp; else expressions = temp; parent = temp; temp = NULL; } else { /* * Need to group previous expressions in an AND node, and then * put that in an OR node... */ if ((temp = new_expr(IPPFIND_OP_AND, 0, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); while (current->prev) { current->parent = temp; current = current->prev; } current->parent = temp; temp->child = current; current = temp; if ((temp = new_expr(IPPFIND_OP_OR, 0, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); temp->parent = parent; current->parent = temp; if (parent) parent->child = temp; else expressions = temp; parent = temp; temp = NULL; } } else if (!strcmp(argv[i], "--path")) { i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Missing regular expression after %s."), "--path"); show_usage(); } if ((temp = new_expr(IPPFIND_OP_PATH_REGEX, invert, NULL, argv[i], NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); } else if (!strcmp(argv[i], "--port")) { i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Expected port range after %s."), "--port"); show_usage(); } if ((temp = new_expr(IPPFIND_OP_PORT_RANGE, invert, argv[i], NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); } else if (!strcmp(argv[i], "--print")) { if ((temp = new_expr(IPPFIND_OP_PRINT_URI, invert, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); have_output = 1; } else if (!strcmp(argv[i], "--print-name")) { if ((temp = new_expr(IPPFIND_OP_PRINT_NAME, invert, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); have_output = 1; } else if (!strcmp(argv[i], "--quiet")) { if ((temp = new_expr(IPPFIND_OP_QUIET, invert, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); have_output = 1; } else if (!strcmp(argv[i], "--remote")) { if ((temp = new_expr(IPPFIND_OP_IS_REMOTE, invert, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); } else if (!strcmp(argv[i], "--true")) { if ((temp = new_expr(IPPFIND_OP_TRUE, invert, NULL, argv[i], NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); } else if (!strcmp(argv[i], "--txt")) { i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Expected key name after %s."), "--txt"); show_usage(); } if ((temp = new_expr(IPPFIND_OP_TXT_EXISTS, invert, argv[i], NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); } else if (!strncmp(argv[i], "--txt-", 6)) { const char *key = argv[i] + 6;/* TXT key */ i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Missing regular expression after %s."), argv[i - 1]); show_usage(); } if ((temp = new_expr(IPPFIND_OP_TXT_REGEX, invert, key, argv[i], NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); } else if (!strcmp(argv[i], "--uri")) { i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Missing regular expression after %s."), "--uri"); show_usage(); } if ((temp = new_expr(IPPFIND_OP_URI_REGEX, invert, NULL, argv[i], NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); } else if (!strcmp(argv[i], "--version")) { show_version(); } else { _cupsLangPrintf(stderr, _("%s: Unknown option \"%s\"."), "ippfind", argv[i]); show_usage(); } if (temp) { /* * Add new expression... */ if (logic == IPPFIND_OP_AND && current && current->prev && parent && parent->op != IPPFIND_OP_AND) { /* * Need to re-group "current" in a new AND node... */ ippfind_expr_t *tempand; /* Temporary AND node */ if ((tempand = new_expr(IPPFIND_OP_AND, 0, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); /* * Replace "current" with new AND node at the end of this list... */ current->prev->next = tempand; tempand->prev = current->prev; tempand->parent = parent; /* * Add "current to the new AND node... */ tempand->child = current; current->parent = tempand; current->prev = NULL; parent = tempand; } /* * Add the new node at current level... */ temp->parent = parent; temp->prev = current; if (current) current->next = temp; else if (parent) parent->child = temp; else expressions = temp; current = temp; invert = 0; logic = IPPFIND_OP_AND; temp = NULL; } } else { /* * Parse -o options */ for (opt = argv[i] + 1; *opt; opt ++) { switch (*opt) { case '4' : address_family = AF_INET; break; case '6' : address_family = AF_INET6; break; case 'P' : i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Expected port range after %s."), "-P"); show_usage(); } if ((temp = new_expr(IPPFIND_OP_PORT_RANGE, invert, argv[i], NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); break; case 'T' : i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("%s: Missing timeout for \"-T\"."), "ippfind"); show_usage(); } bonjour_timeout = atof(argv[i]); break; case 'V' : i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("%s: Missing version for \"-V\"."), "ippfind"); show_usage(); } if (!strcmp(argv[i], "1.1")) ipp_version = 11; else if (!strcmp(argv[i], "2.0")) ipp_version = 20; else if (!strcmp(argv[i], "2.1")) ipp_version = 21; else if (!strcmp(argv[i], "2.2")) ipp_version = 22; else { _cupsLangPrintf(stderr, _("%s: Bad version %s for \"-V\"."), "ippfind", argv[i]); show_usage(); } break; case 'd' : i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Missing regular expression after " "%s."), "-d"); show_usage(); } if ((temp = new_expr(IPPFIND_OP_DOMAIN_REGEX, invert, NULL, argv[i], NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); break; case 'h' : i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Missing regular expression after " "%s."), "-h"); show_usage(); } if ((temp = new_expr(IPPFIND_OP_HOST_REGEX, invert, NULL, argv[i], NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); break; case 'l' : if ((temp = new_expr(IPPFIND_OP_LIST, invert, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); have_output = 1; break; case 'n' : i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Missing regular expression after " "%s."), "-n"); show_usage(); } if ((temp = new_expr(IPPFIND_OP_NAME_REGEX, invert, NULL, argv[i], NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); break; case 'p' : if ((temp = new_expr(IPPFIND_OP_PRINT_URI, invert, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); have_output = 1; break; case 'q' : if ((temp = new_expr(IPPFIND_OP_QUIET, invert, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); have_output = 1; break; case 'r' : if ((temp = new_expr(IPPFIND_OP_IS_REMOTE, invert, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); break; case 's' : if ((temp = new_expr(IPPFIND_OP_PRINT_NAME, invert, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); have_output = 1; break; case 't' : i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Missing key name after %s."), "-t"); show_usage(); } if ((temp = new_expr(IPPFIND_OP_TXT_EXISTS, invert, argv[i], NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); break; case 'u' : i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Missing regular expression after " "%s."), "-u"); show_usage(); } if ((temp = new_expr(IPPFIND_OP_URI_REGEX, invert, NULL, argv[i], NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); break; case 'x' : i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Missing program after %s."), "-x"); show_usage(); } if ((temp = new_expr(IPPFIND_OP_EXEC, invert, NULL, NULL, argv + i)) == NULL) return (IPPFIND_EXIT_MEMORY); while (i < argc) if (!strcmp(argv[i], ";")) break; else i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("ippfind: Missing semi-colon after %s."), "-x"); show_usage(); } have_output = 1; break; default : _cupsLangPrintf(stderr, _("%s: Unknown option \"-%c\"."), "ippfind", *opt); show_usage(); } if (temp) { /* * Add new expression... */ if (logic == IPPFIND_OP_AND && current && current->prev && parent && parent->op != IPPFIND_OP_AND) { /* * Need to re-group "current" in a new AND node... */ ippfind_expr_t *tempand; /* Temporary AND node */ if ((tempand = new_expr(IPPFIND_OP_AND, 0, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); /* * Replace "current" with new AND node at the end of this list... */ current->prev->next = tempand; tempand->prev = current->prev; tempand->parent = parent; /* * Add "current to the new AND node... */ tempand->child = current; current->parent = tempand; current->prev = NULL; parent = tempand; } /* * Add the new node at current level... */ temp->parent = parent; temp->prev = current; if (current) current->next = temp; else if (parent) parent->child = temp; else expressions = temp; current = temp; invert = 0; logic = IPPFIND_OP_AND; temp = NULL; } } } } else if (!strcmp(argv[i], "(")) { if (num_parens >= 100) { _cupsLangPuts(stderr, _("ippfind: Too many parenthesis.")); show_usage(); } if ((temp = new_expr(IPPFIND_OP_AND, invert, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); parens[num_parens++] = temp; if (current) { temp->parent = current->parent; current->next = temp; temp->prev = current; } else expressions = temp; parent = temp; current = NULL; invert = 0; logic = IPPFIND_OP_AND; } else if (!strcmp(argv[i], ")")) { if (num_parens <= 0) { _cupsLangPuts(stderr, _("ippfind: Missing open parenthesis.")); show_usage(); } current = parens[--num_parens]; parent = current->parent; invert = 0; logic = IPPFIND_OP_AND; } else if (!strcmp(argv[i], "!")) { invert = 1; } else { /* * _regtype._tcp[,subtype][.domain] * * OR * * service-name[._regtype._tcp[.domain]] */ cupsArrayAdd(searches, argv[i]); } } if (num_parens > 0) { _cupsLangPuts(stderr, _("ippfind: Missing close parenthesis.")); show_usage(); } if (!have_output) { /* * Add an implicit --print-uri to the end... */ if ((temp = new_expr(IPPFIND_OP_PRINT_URI, 0, NULL, NULL, NULL)) == NULL) return (IPPFIND_EXIT_MEMORY); if (current) { while (current->parent) current = current->parent; current->next = temp; temp->prev = current; } else expressions = temp; } if (cupsArrayCount(searches) == 0) { /* * Add an implicit browse for IPP printers ("_ipp._tcp")... */ cupsArrayAdd(searches, "_ipp._tcp"); } if (getenv("IPPFIND_DEBUG")) { int indent = 4; /* Indentation */ puts("Expression tree:"); current = expressions; while (current) { /* * Print the current node... */ printf("%*s%s%s\n", indent, "", current->invert ? "!" : "", ops[current->op]); /* * Advance to the next node... */ if (current->child) { current = current->child; indent += 4; } else if (current->next) current = current->next; else if (current->parent) { while (current->parent) { indent -= 4; current = current->parent; if (current->next) break; } current = current->next; } else current = NULL; } puts("\nSearch items:"); for (search = (const char *)cupsArrayFirst(searches); search; search = (const char *)cupsArrayNext(searches)) printf(" %s\n", search); } /* * Start up browsing/resolving... */ #ifdef HAVE_DNSSD if ((err = DNSServiceCreateConnection(&dnssd_ref)) != kDNSServiceErr_NoError) { _cupsLangPrintf(stderr, _("ippfind: Unable to use Bonjour: %s"), dnssd_error_string(err)); return (IPPFIND_EXIT_BONJOUR); } #elif defined(HAVE_AVAHI) if ((avahi_poll = avahi_simple_poll_new()) == NULL) { _cupsLangPrintf(stderr, _("ippfind: Unable to use Bonjour: %s"), strerror(errno)); return (IPPFIND_EXIT_BONJOUR); } avahi_simple_poll_set_func(avahi_poll, poll_callback, NULL); avahi_client = avahi_client_new(avahi_simple_poll_get(avahi_poll), 0, client_callback, avahi_poll, &err); if (!avahi_client) { _cupsLangPrintf(stderr, _("ippfind: Unable to use Bonjour: %s"), dnssd_error_string(err)); return (IPPFIND_EXIT_BONJOUR); } #endif /* HAVE_DNSSD */ for (search = (const char *)cupsArrayFirst(searches); search; search = (const char *)cupsArrayNext(searches)) { char buf[1024], /* Full name string */ *name = NULL, /* Service instance name */ *regtype, /* Registration type */ *domain; /* Domain, if any */ strlcpy(buf, search, sizeof(buf)); if ((regtype = strstr(buf, "._")) != NULL) { if (strcmp(regtype, "._tcp")) { /* * "something._protocol._tcp" -> search for something with the given * protocol... */ name = buf; *regtype++ = '\0'; } else { /* * "_protocol._tcp" -> search for everything with the given protocol... */ /* name = NULL; */ regtype = buf; } } else { /* * "something" -> search for something with IPP protocol... */ name = buf; regtype = "_ipp._tcp"; } for (domain = regtype; *domain; domain ++) { if (*domain == '.' && domain[1] != '_') { *domain++ = '\0'; break; } } if (!*domain) domain = NULL; if (name) { /* * Resolve the given service instance name, regtype, and domain... */ if (!domain) domain = "local."; service = get_service(services, name, regtype, domain); #ifdef HAVE_DNSSD service->ref = dnssd_ref; err = DNSServiceResolve(&(service->ref), kDNSServiceFlagsShareConnection, 0, name, regtype, domain, resolve_callback, service); #elif defined(HAVE_AVAHI) service->ref = avahi_service_resolver_new(avahi_client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, name, regtype, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, service); if (service->ref) err = 0; else err = avahi_client_errno(avahi_client); #endif /* HAVE_DNSSD */ } else { /* * Browse for services of the given type... */ #ifdef HAVE_DNSSD DNSServiceRef ref; /* Browse reference */ ref = dnssd_ref; err = DNSServiceBrowse(&ref, kDNSServiceFlagsShareConnection, 0, regtype, domain, browse_callback, services); if (!err) { ref = dnssd_ref; err = DNSServiceBrowse(&ref, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexLocalOnly, regtype, domain, browse_local_callback, services); } #elif defined(HAVE_AVAHI) if (avahi_service_browser_new(avahi_client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, regtype, domain, 0, browse_callback, services)) err = 0; else err = avahi_client_errno(avahi_client); #endif /* HAVE_DNSSD */ } if (err) { _cupsLangPrintf(stderr, _("ippfind: Unable to browse or resolve: %s"), dnssd_error_string(err)); return (IPPFIND_EXIT_BONJOUR); } } /* * Process browse/resolve requests... */ if (bonjour_timeout > 1.0) endtime = get_time() + bonjour_timeout; else endtime = get_time() + 300.0; while (get_time() < endtime) { int process = 0; /* Process services? */ #ifdef HAVE_DNSSD int fd = DNSServiceRefSockFD(dnssd_ref); /* File descriptor for DNS-SD */ FD_ZERO(&sinput); FD_SET(fd, &sinput); stimeout.tv_sec = 0; stimeout.tv_usec = 500000; if (select(fd + 1, &sinput, NULL, NULL, &stimeout) < 0) continue; if (FD_ISSET(fd, &sinput)) { /* * Process responses... */ DNSServiceProcessResult(dnssd_ref); } else { /* * Time to process services... */ process = 1; } #elif defined(HAVE_AVAHI) avahi_got_data = 0; if (avahi_simple_poll_iterate(avahi_poll, 500) > 0) { /* * We've been told to exit the loop. Perhaps the connection to * Avahi failed. */ return (IPPFIND_EXIT_BONJOUR); } if (!avahi_got_data) { /* * Time to process services... */ process = 1; } #endif /* HAVE_DNSSD */ if (process) { /* * Process any services that we have found... */ int active = 0, /* Number of active resolves */ resolved = 0, /* Number of resolved services */ processed = 0; /* Number of processed services */ for (service = (ippfind_srv_t *)cupsArrayFirst(services); service; service = (ippfind_srv_t *)cupsArrayNext(services)) { if (service->is_processed) processed ++; if (service->is_resolved) resolved ++; if (!service->ref && !service->is_resolved) { /* * Found a service, now resolve it (but limit to 50 active resolves...) */ if (active < 50) { #ifdef HAVE_DNSSD service->ref = dnssd_ref; err = DNSServiceResolve(&(service->ref), kDNSServiceFlagsShareConnection, 0, service->name, service->regtype, service->domain, resolve_callback, service); #elif defined(HAVE_AVAHI) service->ref = avahi_service_resolver_new(avahi_client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, service->name, service->regtype, service->domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, service); if (service->ref) err = 0; else err = avahi_client_errno(avahi_client); #endif /* HAVE_DNSSD */ if (err) { _cupsLangPrintf(stderr, _("ippfind: Unable to browse or resolve: %s"), dnssd_error_string(err)); return (IPPFIND_EXIT_BONJOUR); } active ++; } } else if (service->is_resolved && !service->is_processed) { /* * Resolved, not process this service against the expressions... */ if (service->ref) { #ifdef HAVE_DNSSD DNSServiceRefDeallocate(service->ref); #else avahi_service_resolver_free(service->ref); #endif /* HAVE_DNSSD */ service->ref = NULL; } if (eval_expr(service, expressions)) status = IPPFIND_EXIT_TRUE; service->is_processed = 1; } else if (service->ref) active ++; } /* * If we have processed all services we have discovered, then we are done. */ if (processed == cupsArrayCount(services) && bonjour_timeout <= 1.0) break; } } if (bonjour_error) return (IPPFIND_EXIT_BONJOUR); else return (status); } #ifdef HAVE_DNSSD /* * 'browse_callback()' - Browse devices. */ static void DNSSD_API browse_callback( DNSServiceRef sdRef, /* I - Service reference */ DNSServiceFlags flags, /* I - Option flags */ uint32_t interfaceIndex, /* I - Interface number */ DNSServiceErrorType errorCode, /* I - Error, if any */ const char *serviceName, /* I - Name of service/device */ const char *regtype, /* I - Type of service */ const char *replyDomain, /* I - Service domain */ void *context) /* I - Services array */ { /* * Only process "add" data... */ (void)sdRef; (void)interfaceIndex; if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd)) return; /* * Get the device... */ get_service((cups_array_t *)context, serviceName, regtype, replyDomain); } /* * 'browse_local_callback()' - Browse local devices. */ static void DNSSD_API browse_local_callback( DNSServiceRef sdRef, /* I - Service reference */ DNSServiceFlags flags, /* I - Option flags */ uint32_t interfaceIndex, /* I - Interface number */ DNSServiceErrorType errorCode, /* I - Error, if any */ const char *serviceName, /* I - Name of service/device */ const char *regtype, /* I - Type of service */ const char *replyDomain, /* I - Service domain */ void *context) /* I - Services array */ { ippfind_srv_t *service; /* Service */ /* * Only process "add" data... */ (void)sdRef; (void)interfaceIndex; if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd)) return; /* * Get the device... */ service = get_service((cups_array_t *)context, serviceName, regtype, replyDomain); service->is_local = 1; } #endif /* HAVE_DNSSD */ #ifdef HAVE_AVAHI /* * 'browse_callback()' - Browse devices. */ static void browse_callback( AvahiServiceBrowser *browser, /* I - Browser */ AvahiIfIndex interface, /* I - Interface index (unused) */ AvahiProtocol protocol, /* I - Network protocol (unused) */ AvahiBrowserEvent event, /* I - What happened */ const char *name, /* I - Service name */ const char *type, /* I - Registration type */ const char *domain, /* I - Domain */ AvahiLookupResultFlags flags, /* I - Flags */ void *context) /* I - Services array */ { AvahiClient *client = avahi_service_browser_get_client(browser); /* Client information */ ippfind_srv_t *service; /* Service information */ (void)interface; (void)protocol; (void)context; switch (event) { case AVAHI_BROWSER_FAILURE: fprintf(stderr, "DEBUG: browse_callback: %s\n", avahi_strerror(avahi_client_errno(client))); bonjour_error = 1; avahi_simple_poll_quit(avahi_poll); break; case AVAHI_BROWSER_NEW: /* * This object is new on the network. Create a device entry for it if * it doesn't yet exist. */ service = get_service((cups_array_t *)context, name, type, domain); if (flags & AVAHI_LOOKUP_RESULT_LOCAL) service->is_local = 1; break; case AVAHI_BROWSER_REMOVE: case AVAHI_BROWSER_ALL_FOR_NOW: case AVAHI_BROWSER_CACHE_EXHAUSTED: break; } } /* * 'client_callback()' - Avahi client callback function. */ static void client_callback( AvahiClient *client, /* I - Client information (unused) */ AvahiClientState state, /* I - Current state */ void *context) /* I - User data (unused) */ { (void)client; (void)context; /* * If the connection drops, quit. */ if (state == AVAHI_CLIENT_FAILURE) { fputs("DEBUG: Avahi connection failed.\n", stderr); bonjour_error = 1; avahi_simple_poll_quit(avahi_poll); } } #endif /* HAVE_AVAHI */ /* * 'compare_services()' - Compare two devices. */ static int /* O - Result of comparison */ compare_services(ippfind_srv_t *a, /* I - First device */ ippfind_srv_t *b) /* I - Second device */ { return (strcmp(a->name, b->name)); } /* * 'dnssd_error_string()' - Return an error string for an error code. */ static const char * /* O - Error message */ dnssd_error_string(int error) /* I - Error number */ { # ifdef HAVE_DNSSD switch (error) { case kDNSServiceErr_NoError : return ("OK."); default : case kDNSServiceErr_Unknown : return ("Unknown error."); case kDNSServiceErr_NoSuchName : return ("Service not found."); case kDNSServiceErr_NoMemory : return ("Out of memory."); case kDNSServiceErr_BadParam : return ("Bad parameter."); case kDNSServiceErr_BadReference : return ("Bad service reference."); case kDNSServiceErr_BadState : return ("Bad state."); case kDNSServiceErr_BadFlags : return ("Bad flags."); case kDNSServiceErr_Unsupported : return ("Unsupported."); case kDNSServiceErr_NotInitialized : return ("Not initialized."); case kDNSServiceErr_AlreadyRegistered : return ("Already registered."); case kDNSServiceErr_NameConflict : return ("Name conflict."); case kDNSServiceErr_Invalid : return ("Invalid name."); case kDNSServiceErr_Firewall : return ("Firewall prevents registration."); case kDNSServiceErr_Incompatible : return ("Client library incompatible."); case kDNSServiceErr_BadInterfaceIndex : return ("Bad interface index."); case kDNSServiceErr_Refused : return ("Server prevents registration."); case kDNSServiceErr_NoSuchRecord : return ("Record not found."); case kDNSServiceErr_NoAuth : return ("Authentication required."); case kDNSServiceErr_NoSuchKey : return ("Encryption key not found."); case kDNSServiceErr_NATTraversal : return ("Unable to traverse NAT boundary."); case kDNSServiceErr_DoubleNAT : return ("Unable to traverse double-NAT boundary."); case kDNSServiceErr_BadTime : return ("Bad system time."); case kDNSServiceErr_BadSig : return ("Bad signature."); case kDNSServiceErr_BadKey : return ("Bad encryption key."); case kDNSServiceErr_Transient : return ("Transient error occurred - please try again."); case kDNSServiceErr_ServiceNotRunning : return ("Server not running."); case kDNSServiceErr_NATPortMappingUnsupported : return ("NAT doesn't support NAT-PMP or UPnP."); case kDNSServiceErr_NATPortMappingDisabled : return ("NAT supports NAT-PNP or UPnP but it is disabled."); case kDNSServiceErr_NoRouter : return ("No Internet/default router configured."); case kDNSServiceErr_PollingMode : return ("Service polling mode error."); #ifndef WIN32 case kDNSServiceErr_Timeout : return ("Service timeout."); #endif /* !WIN32 */ } # elif defined(HAVE_AVAHI) return (avahi_strerror(error)); # endif /* HAVE_DNSSD */ } /* * 'eval_expr()' - Evaluate the expressions against the specified service. * * Returns 1 for true and 0 for false. */ static int /* O - Result of evaluation */ eval_expr(ippfind_srv_t *service, /* I - Service */ ippfind_expr_t *expressions) /* I - Expressions */ { int logic, /* Logical operation */ result; /* Result of current expression */ ippfind_expr_t *expression; /* Current expression */ const char *val; /* TXT value */ /* * Loop through the expressions... */ if (expressions && expressions->parent) logic = expressions->parent->op; else logic = IPPFIND_OP_AND; for (expression = expressions; expression; expression = expression->next) { switch (expression->op) { default : case IPPFIND_OP_AND : case IPPFIND_OP_OR : if (expression->child) result = eval_expr(service, expression->child); else result = expression->op == IPPFIND_OP_AND; break; case IPPFIND_OP_TRUE : result = 1; break; case IPPFIND_OP_FALSE : result = 0; break; case IPPFIND_OP_IS_LOCAL : result = service->is_local; break; case IPPFIND_OP_IS_REMOTE : result = !service->is_local; break; case IPPFIND_OP_DOMAIN_REGEX : result = !regexec(&(expression->re), service->domain, 0, NULL, 0); break; case IPPFIND_OP_NAME_REGEX : result = !regexec(&(expression->re), service->name, 0, NULL, 0); break; case IPPFIND_OP_HOST_REGEX : result = !regexec(&(expression->re), service->host, 0, NULL, 0); break; case IPPFIND_OP_PORT_RANGE : result = service->port >= expression->range[0] && service->port <= expression->range[1]; break; case IPPFIND_OP_PATH_REGEX : result = !regexec(&(expression->re), service->resource, 0, NULL, 0); break; case IPPFIND_OP_TXT_EXISTS : result = cupsGetOption(expression->key, service->num_txt, service->txt) != NULL; break; case IPPFIND_OP_TXT_REGEX : val = cupsGetOption(expression->key, service->num_txt, service->txt); if (val) result = !regexec(&(expression->re), val, 0, NULL, 0); else result = 0; if (getenv("IPPFIND_DEBUG")) printf("TXT_REGEX of \"%s\": %d\n", val, result); break; case IPPFIND_OP_URI_REGEX : result = !regexec(&(expression->re), service->uri, 0, NULL, 0); break; case IPPFIND_OP_EXEC : result = exec_program(service, expression->num_args, expression->args); break; case IPPFIND_OP_LIST : result = list_service(service); break; case IPPFIND_OP_PRINT_NAME : _cupsLangPuts(stdout, service->name); result = 1; break; case IPPFIND_OP_PRINT_URI : _cupsLangPuts(stdout, service->uri); result = 1; break; case IPPFIND_OP_QUIET : result = 1; break; } if (expression->invert) result = !result; if (logic == IPPFIND_OP_AND && !result) return (0); else if (logic == IPPFIND_OP_OR && result) return (1); } return (logic == IPPFIND_OP_AND); } /* * 'exec_program()' - Execute a program for a service. */ static int /* O - 1 if program terminated successfully, 0 otherwise. */ exec_program(ippfind_srv_t *service, /* I - Service */ int num_args, /* I - Number of command-line args */ char **args) /* I - Command-line arguments */ { char **myargv, /* Command-line arguments */ **myenvp, /* Environment variables */ *ptr, /* Pointer into variable */ domain[1024], /* IPPFIND_SERVICE_DOMAIN */ hostname[1024], /* IPPFIND_SERVICE_HOSTNAME */ name[256], /* IPPFIND_SERVICE_NAME */ port[32], /* IPPFIND_SERVICE_PORT */ regtype[256], /* IPPFIND_SERVICE_REGTYPE */ scheme[128], /* IPPFIND_SERVICE_SCHEME */ uri[1024], /* IPPFIND_SERVICE_URI */ txt[100][256]; /* IPPFIND_TXT_foo */ int i, /* Looping var */ myenvc, /* Number of environment variables */ status; /* Exit status of program */ #ifndef WIN32 char program[1024]; /* Program to execute */ int pid; /* Process ID */ #endif /* !WIN32 */ /* * Environment variables... */ snprintf(domain, sizeof(domain), "IPPFIND_SERVICE_DOMAIN=%s", service->domain); snprintf(hostname, sizeof(hostname), "IPPFIND_SERVICE_HOSTNAME=%s", service->host); snprintf(name, sizeof(name), "IPPFIND_SERVICE_NAME=%s", service->name); snprintf(port, sizeof(port), "IPPFIND_SERVICE_PORT=%d", service->port); snprintf(regtype, sizeof(regtype), "IPPFIND_SERVICE_REGTYPE=%s", service->regtype); snprintf(scheme, sizeof(scheme), "IPPFIND_SERVICE_SCHEME=%s", !strncmp(service->regtype, "_http._tcp", 10) ? "http" : !strncmp(service->regtype, "_https._tcp", 11) ? "https" : !strncmp(service->regtype, "_ipp._tcp", 9) ? "ipp" : !strncmp(service->regtype, "_ipps._tcp", 10) ? "ipps" : "lpd"); snprintf(uri, sizeof(uri), "IPPFIND_SERVICE_URI=%s", service->uri); for (i = 0; i < service->num_txt && i < 100; i ++) { snprintf(txt[i], sizeof(txt[i]), "IPPFIND_TXT_%s=%s", service->txt[i].name, service->txt[i].value); for (ptr = txt[i] + 12; *ptr && *ptr != '='; ptr ++) *ptr = (char)_cups_toupper(*ptr); } for (i = 0, myenvc = 7 + service->num_txt; environ[i]; i ++) if (strncmp(environ[i], "IPPFIND_", 8)) myenvc ++; if ((myenvp = calloc(sizeof(char *), (size_t)(myenvc + 1))) == NULL) { _cupsLangPuts(stderr, _("ippfind: Out of memory.")); exit(IPPFIND_EXIT_MEMORY); } for (i = 0, myenvc = 0; environ[i]; i ++) if (strncmp(environ[i], "IPPFIND_", 8)) myenvp[myenvc++] = environ[i]; myenvp[myenvc++] = domain; myenvp[myenvc++] = hostname; myenvp[myenvc++] = name; myenvp[myenvc++] = port; myenvp[myenvc++] = regtype; myenvp[myenvc++] = scheme; myenvp[myenvc++] = uri; for (i = 0; i < service->num_txt && i < 100; i ++) myenvp[myenvc++] = txt[i]; /* * Allocate and copy command-line arguments... */ if ((myargv = calloc(sizeof(char *), (size_t)(num_args + 1))) == NULL) { _cupsLangPuts(stderr, _("ippfind: Out of memory.")); exit(IPPFIND_EXIT_MEMORY); } for (i = 0; i < num_args; i ++) { if (strchr(args[i], '{')) { char temp[2048], /* Temporary string */ *tptr, /* Pointer into temporary string */ keyword[256], /* {keyword} */ *kptr; /* Pointer into keyword */ for (ptr = args[i], tptr = temp; *ptr; ptr ++) { if (*ptr == '{') { /* * Do a {var} substitution... */ for (kptr = keyword, ptr ++; *ptr && *ptr != '}'; ptr ++) if (kptr < (keyword + sizeof(keyword) - 1)) *kptr++ = *ptr; if (*ptr != '}') { _cupsLangPuts(stderr, _("ippfind: Missing close brace in substitution.")); exit(IPPFIND_EXIT_SYNTAX); } *kptr = '\0'; if (!keyword[0] || !strcmp(keyword, "service_uri")) strlcpy(tptr, service->uri, sizeof(temp) - (size_t)(tptr - temp)); else if (!strcmp(keyword, "service_domain")) strlcpy(tptr, service->domain, sizeof(temp) - (size_t)(tptr - temp)); else if (!strcmp(keyword, "service_hostname")) strlcpy(tptr, service->host, sizeof(temp) - (size_t)(tptr - temp)); else if (!strcmp(keyword, "service_name")) strlcpy(tptr, service->name, sizeof(temp) - (size_t)(tptr - temp)); else if (!strcmp(keyword, "service_path")) strlcpy(tptr, service->resource, sizeof(temp) - (size_t)(tptr - temp)); else if (!strcmp(keyword, "service_port")) strlcpy(tptr, port + 21, sizeof(temp) - (size_t)(tptr - temp)); else if (!strcmp(keyword, "service_scheme")) strlcpy(tptr, scheme + 22, sizeof(temp) - (size_t)(tptr - temp)); else if (!strncmp(keyword, "txt_", 4)) { const char *val = cupsGetOption(keyword + 4, service->num_txt, service->txt); if (val) strlcpy(tptr, val, sizeof(temp) - (size_t)(tptr - temp)); else *tptr = '\0'; } else { _cupsLangPrintf(stderr, _("ippfind: Unknown variable \"{%s}\"."), keyword); exit(IPPFIND_EXIT_SYNTAX); } tptr += strlen(tptr); } else if (tptr < (temp + sizeof(temp) - 1)) *tptr++ = *ptr; } *tptr = '\0'; myargv[i] = strdup(temp); } else myargv[i] = strdup(args[i]); } #ifdef WIN32 if (getenv("IPPFIND_DEBUG")) { printf("\nProgram:\n %s\n", args[0]); puts("\nArguments:"); for (i = 0; i < num_args; i ++) printf(" %s\n", myargv[i]); puts("\nEnvironment:"); for (i = 0; i < myenvc; i ++) printf(" %s\n", myenvp[i]); } status = _spawnvpe(_P_WAIT, args[0], myargv, myenvp); #else /* * Execute the program... */ if (strchr(args[0], '/') && !access(args[0], X_OK)) strlcpy(program, args[0], sizeof(program)); else if (!cupsFileFind(args[0], getenv("PATH"), 1, program, sizeof(program))) { _cupsLangPrintf(stderr, _("ippfind: Unable to execute \"%s\": %s"), args[0], strerror(ENOENT)); exit(IPPFIND_EXIT_SYNTAX); } if (getenv("IPPFIND_DEBUG")) { printf("\nProgram:\n %s\n", program); puts("\nArguments:"); for (i = 0; i < num_args; i ++) printf(" %s\n", myargv[i]); puts("\nEnvironment:"); for (i = 0; i < myenvc; i ++) printf(" %s\n", myenvp[i]); } if ((pid = fork()) == 0) { /* * Child comes here... */ execve(program, myargv, myenvp); exit(1); } else if (pid < 0) { _cupsLangPrintf(stderr, _("ippfind: Unable to execute \"%s\": %s"), args[0], strerror(errno)); exit(IPPFIND_EXIT_SYNTAX); } else { /* * Wait for it to complete... */ while (wait(&status) != pid) ; } #endif /* WIN32 */ /* * Free memory... */ for (i = 0; i < num_args; i ++) free(myargv[i]); free(myargv); free(myenvp); /* * Return whether the program succeeded or crashed... */ if (getenv("IPPFIND_DEBUG")) { #ifdef WIN32 printf("Exit Status: %d\n", status); #else if (WIFEXITED(status)) printf("Exit Status: %d\n", WEXITSTATUS(status)); else printf("Terminating Signal: %d\n", WTERMSIG(status)); #endif /* WIN32 */ } return (status == 0); } /* * 'get_service()' - Create or update a device. */ static ippfind_srv_t * /* O - Service */ get_service(cups_array_t *services, /* I - Service array */ const char *serviceName, /* I - Name of service/device */ const char *regtype, /* I - Type of service */ const char *replyDomain) /* I - Service domain */ { ippfind_srv_t key, /* Search key */ *service; /* Service */ char fullName[kDNSServiceMaxDomainName]; /* Full name for query */ /* * See if this is a new device... */ key.name = (char *)serviceName; key.regtype = (char *)regtype; for (service = cupsArrayFind(services, &key); service; service = cupsArrayNext(services)) if (_cups_strcasecmp(service->name, key.name)) break; else if (!strcmp(service->regtype, key.regtype)) return (service); /* * Yes, add the service... */ service = calloc(sizeof(ippfind_srv_t), 1); service->name = strdup(serviceName); service->domain = strdup(replyDomain); service->regtype = strdup(regtype); cupsArrayAdd(services, service); /* * Set the "full name" of this service, which is used for queries and * resolves... */ #ifdef HAVE_DNSSD DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain); #else /* HAVE_AVAHI */ avahi_service_name_join(fullName, kDNSServiceMaxDomainName, serviceName, regtype, replyDomain); #endif /* HAVE_DNSSD */ service->fullName = strdup(fullName); return (service); } /* * 'get_time()' - Get the current time-of-day in seconds. */ static double get_time(void) { #ifdef WIN32 struct _timeb curtime; /* Current Windows time */ _ftime(&curtime); return (curtime.time + 0.001 * curtime.millitm); #else struct timeval curtime; /* Current UNIX time */ if (gettimeofday(&curtime, NULL)) return (0.0); else return (curtime.tv_sec + 0.000001 * curtime.tv_usec); #endif /* WIN32 */ } /* * 'list_service()' - List the contents of a service. */ static int /* O - 1 if successful, 0 otherwise */ list_service(ippfind_srv_t *service) /* I - Service */ { http_addrlist_t *addrlist; /* Address(es) of service */ char port[10]; /* Port number of service */ snprintf(port, sizeof(port), "%d", service->port); if ((addrlist = httpAddrGetList(service->host, address_family, port)) == NULL) { _cupsLangPrintf(stdout, "%s unreachable", service->uri); return (0); } if (!strncmp(service->regtype, "_ipp._tcp", 9) || !strncmp(service->regtype, "_ipps._tcp", 10)) { /* * IPP/IPPS printer */ http_t *http; /* HTTP connection */ ipp_t *request, /* IPP request */ *response; /* IPP response */ ipp_attribute_t *attr; /* IPP attribute */ int i, /* Looping var */ count, /* Number of values */ version, /* IPP version */ paccepting; /* printer-is-accepting-jobs value */ ipp_pstate_t pstate; /* printer-state value */ char preasons[1024], /* Comma-delimited printer-state-reasons */ *ptr, /* Pointer into reasons */ *end; /* End of reasons buffer */ static const char * const rattrs[] =/* Requested attributes */ { "printer-is-accepting-jobs", "printer-state", "printer-state-reasons" }; /* * Connect to the printer... */ http = httpConnect2(service->host, service->port, addrlist, address_family, !strncmp(service->regtype, "_ipps._tcp", 10) ? HTTP_ENCRYPTION_ALWAYS : HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL); httpAddrFreeList(addrlist); if (!http) { _cupsLangPrintf(stdout, "%s unavailable", service->uri); return (0); } /* * Get the current printer state... */ response = NULL; version = ipp_version; do { request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); ippSetVersion(request, version / 10, version % 10); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, service->uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(rattrs) / sizeof(rattrs[0])), NULL, rattrs); response = cupsDoRequest(http, request, service->resource); if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST && version > 11) version = 11; } while (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE && version > 11); /* * Show results... */ if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) { _cupsLangPrintf(stdout, "%s: unavailable", service->uri); return (0); } if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) pstate = (ipp_pstate_t)ippGetInteger(attr, 0); else pstate = IPP_PSTATE_STOPPED; if ((attr = ippFindAttribute(response, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN)) != NULL) paccepting = ippGetBoolean(attr, 0); else paccepting = 0; if ((attr = ippFindAttribute(response, "printer-state-reasons", IPP_TAG_KEYWORD)) != NULL) { strlcpy(preasons, ippGetString(attr, 0, NULL), sizeof(preasons)); for (i = 1, count = ippGetCount(attr), ptr = preasons + strlen(preasons), end = preasons + sizeof(preasons) - 1; i < count && ptr < end; i ++, ptr += strlen(ptr)) { *ptr++ = ','; strlcpy(ptr, ippGetString(attr, i, NULL), (size_t)(end - ptr + 1)); } } else strlcpy(preasons, "none", sizeof(preasons)); ippDelete(response); httpClose(http); _cupsLangPrintf(stdout, "%s %s %s %s", service->uri, ippEnumString("printer-state", pstate), paccepting ? "accepting-jobs" : "not-accepting-jobs", preasons); } else if (!strncmp(service->regtype, "_http._tcp", 10) || !strncmp(service->regtype, "_https._tcp", 11)) { /* * HTTP/HTTPS web page */ http_t *http; /* HTTP connection */ http_status_t status; /* HEAD status */ /* * Connect to the web server... */ http = httpConnect2(service->host, service->port, addrlist, address_family, !strncmp(service->regtype, "_ipps._tcp", 10) ? HTTP_ENCRYPTION_ALWAYS : HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL); httpAddrFreeList(addrlist); if (!http) { _cupsLangPrintf(stdout, "%s unavailable", service->uri); return (0); } if (httpGet(http, service->resource)) { _cupsLangPrintf(stdout, "%s unavailable", service->uri); return (0); } do { status = httpUpdate(http); } while (status == HTTP_STATUS_CONTINUE); httpFlush(http); httpClose(http); if (status >= HTTP_STATUS_BAD_REQUEST) { _cupsLangPrintf(stdout, "%s unavailable", service->uri); return (0); } _cupsLangPrintf(stdout, "%s available", service->uri); } else if (!strncmp(service->regtype, "_printer._tcp", 13)) { /* * LPD printer */ int sock; /* Socket */ if (!httpAddrConnect(addrlist, &sock)) { _cupsLangPrintf(stdout, "%s unavailable", service->uri); httpAddrFreeList(addrlist); return (0); } _cupsLangPrintf(stdout, "%s available", service->uri); httpAddrFreeList(addrlist); httpAddrClose(NULL, sock); } else { _cupsLangPrintf(stdout, "%s unsupported", service->uri); httpAddrFreeList(addrlist); return (0); } return (1); } /* * 'new_expr()' - Create a new expression. */ static ippfind_expr_t * /* O - New expression */ new_expr(ippfind_op_t op, /* I - Operation */ int invert, /* I - Invert result? */ const char *value, /* I - TXT key or port range */ const char *regex, /* I - Regular expression */ char **args) /* I - Pointer to argument strings */ { ippfind_expr_t *temp; /* New expression */ if ((temp = calloc(1, sizeof(ippfind_expr_t))) == NULL) return (NULL); temp->op = op; temp->invert = invert; if (op == IPPFIND_OP_TXT_EXISTS || op == IPPFIND_OP_TXT_REGEX) temp->key = (char *)value; else if (op == IPPFIND_OP_PORT_RANGE) { /* * Pull port number range of the form "number", "-number" (0-number), * "number-" (number-65535), and "number-number". */ if (*value == '-') { temp->range[1] = atoi(value + 1); } else if (strchr(value, '-')) { if (sscanf(value, "%d-%d", temp->range, temp->range + 1) == 1) temp->range[1] = 65535; } else { temp->range[0] = temp->range[1] = atoi(value); } } if (regex) { int err = regcomp(&(temp->re), regex, REG_NOSUB | REG_ICASE | REG_EXTENDED); if (err) { char message[256]; /* Error message */ regerror(err, &(temp->re), message, sizeof(message)); _cupsLangPrintf(stderr, _("ippfind: Bad regular expression: %s"), message); exit(IPPFIND_EXIT_SYNTAX); } } if (args) { int num_args; /* Number of arguments */ for (num_args = 1; args[num_args]; num_args ++) if (!strcmp(args[num_args], ";")) break; temp->num_args = num_args; temp->args = malloc((size_t)num_args * sizeof(char *)); memcpy(temp->args, args, (size_t)num_args * sizeof(char *)); } return (temp); } #ifdef HAVE_AVAHI /* * 'poll_callback()' - Wait for input on the specified file descriptors. * * Note: This function is needed because avahi_simple_poll_iterate is broken * and always uses a timeout of 0 (!) milliseconds. * (Avahi Ticket #364) */ static int /* O - Number of file descriptors matching */ poll_callback( struct pollfd *pollfds, /* I - File descriptors */ unsigned int num_pollfds, /* I - Number of file descriptors */ int timeout, /* I - Timeout in milliseconds (unused) */ void *context) /* I - User data (unused) */ { int val; /* Return value */ (void)timeout; (void)context; val = poll(pollfds, num_pollfds, 500); if (val > 0) avahi_got_data = 1; return (val); } #endif /* HAVE_AVAHI */ /* * 'resolve_callback()' - Process resolve data. */ #ifdef HAVE_DNSSD static void DNSSD_API resolve_callback( DNSServiceRef sdRef, /* I - Service reference */ DNSServiceFlags flags, /* I - Data flags */ uint32_t interfaceIndex, /* I - Interface */ DNSServiceErrorType errorCode, /* I - Error, if any */ const char *fullName, /* I - Full service name */ const char *hostTarget, /* I - Hostname */ uint16_t port, /* I - Port number (network byte order) */ uint16_t txtLen, /* I - Length of TXT record data */ const unsigned char *txtRecord, /* I - TXT record data */ void *context) /* I - Service */ { char key[256], /* TXT key value */ *value; /* Value from TXT record */ const unsigned char *txtEnd; /* End of TXT record */ uint8_t valueLen; /* Length of value */ ippfind_srv_t *service = (ippfind_srv_t *)context; /* Service */ /* * Only process "add" data... */ (void)sdRef; (void)flags; (void)interfaceIndex; (void)fullName; if (errorCode != kDNSServiceErr_NoError) { _cupsLangPrintf(stderr, _("ippfind: Unable to browse or resolve: %s"), dnssd_error_string(errorCode)); bonjour_error = 1; return; } service->is_resolved = 1; service->host = strdup(hostTarget); service->port = ntohs(port); value = service->host + strlen(service->host) - 1; if (value >= service->host && *value == '.') *value = '\0'; /* * Loop through the TXT key/value pairs and add them to an array... */ for (txtEnd = txtRecord + txtLen; txtRecord < txtEnd; txtRecord += valueLen) { /* * Ignore bogus strings... */ valueLen = *txtRecord++; memcpy(key, txtRecord, valueLen); key[valueLen] = '\0'; if ((value = strchr(key, '=')) == NULL) continue; *value++ = '\0'; /* * Add to array of TXT values... */ service->num_txt = cupsAddOption(key, value, service->num_txt, &(service->txt)); } set_service_uri(service); } #elif defined(HAVE_AVAHI) static void resolve_callback( AvahiServiceResolver *resolver, /* I - Resolver */ AvahiIfIndex interface, /* I - Interface */ AvahiProtocol protocol, /* I - Address protocol */ AvahiResolverEvent event, /* I - Event */ const char *serviceName,/* I - Service name */ const char *regtype, /* I - Registration type */ const char *replyDomain,/* I - Domain name */ const char *hostTarget, /* I - FQDN */ const AvahiAddress *address, /* I - Address */ uint16_t port, /* I - Port number */ AvahiStringList *txt, /* I - TXT records */ AvahiLookupResultFlags flags, /* I - Lookup flags */ void *context) /* I - Service */ { char key[256], /* TXT key */ *value; /* TXT value */ ippfind_srv_t *service = (ippfind_srv_t *)context; /* Service */ AvahiStringList *current; /* Current TXT key/value pair */ (void)address; if (event != AVAHI_RESOLVER_FOUND) { bonjour_error = 1; avahi_service_resolver_free(resolver); avahi_simple_poll_quit(avahi_poll); return; } service->is_resolved = 1; service->host = strdup(hostTarget); service->port = port; value = service->host + strlen(service->host) - 1; if (value >= service->host && *value == '.') *value = '\0'; /* * Loop through the TXT key/value pairs and add them to an array... */ for (current = txt; current; current = current->next) { /* * Ignore bogus strings... */ if (current->size > (sizeof(key) - 1)) continue; memcpy(key, current->text, current->size); key[current->size] = '\0'; if ((value = strchr(key, '=')) == NULL) continue; *value++ = '\0'; /* * Add to array of TXT values... */ service->num_txt = cupsAddOption(key, value, service->num_txt, &(service->txt)); } set_service_uri(service); } #endif /* HAVE_DNSSD */ /* * 'set_service_uri()' - Set the URI of the service. */ static void set_service_uri(ippfind_srv_t *service) /* I - Service */ { char uri[1024]; /* URI */ const char *path, /* Resource path */ *scheme; /* URI scheme */ if (!strncmp(service->regtype, "_http.", 6)) { scheme = "http"; path = cupsGetOption("path", service->num_txt, service->txt); } else if (!strncmp(service->regtype, "_https.", 7)) { scheme = "https"; path = cupsGetOption("path", service->num_txt, service->txt); } else if (!strncmp(service->regtype, "_ipp.", 5)) { scheme = "ipp"; path = cupsGetOption("rp", service->num_txt, service->txt); } else if (!strncmp(service->regtype, "_ipps.", 6)) { scheme = "ipps"; path = cupsGetOption("rp", service->num_txt, service->txt); } else if (!strncmp(service->regtype, "_printer.", 9)) { scheme = "lpd"; path = cupsGetOption("rp", service->num_txt, service->txt); } else return; if (!path || !*path) path = "/"; if (*path == '/') { service->resource = strdup(path); } else { snprintf(uri, sizeof(uri), "/%s", path); service->resource = strdup(uri); } httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), scheme, NULL, service->host, service->port, service->resource); service->uri = strdup(uri); } /* * 'show_usage()' - Show program usage. */ static void show_usage(void) { _cupsLangPuts(stderr, _("Usage: ippfind [options] regtype[,subtype]" "[.domain.] ... [expression]\n" " ippfind [options] name[.regtype[.domain.]] " "... [expression]\n" " ippfind --help\n" " ippfind --version")); _cupsLangPuts(stderr, ""); _cupsLangPuts(stderr, _("Options:")); _cupsLangPuts(stderr, _(" -4 Connect using IPv4.")); _cupsLangPuts(stderr, _(" -6 Connect using IPv6.")); _cupsLangPuts(stderr, _(" -T seconds Set the browse timeout in " "seconds.")); _cupsLangPuts(stderr, _(" -V version Set default IPP " "version.")); _cupsLangPuts(stderr, _(" --help Show this help.")); _cupsLangPuts(stderr, _(" --version Show program version.")); _cupsLangPuts(stderr, ""); _cupsLangPuts(stderr, _("Expressions:")); _cupsLangPuts(stderr, _(" -P number[-number] Match port to number or range.")); _cupsLangPuts(stderr, _(" -d regex Match domain to regular expression.")); _cupsLangPuts(stderr, _(" -h regex Match hostname to regular expression.")); _cupsLangPuts(stderr, _(" -l List attributes.")); _cupsLangPuts(stderr, _(" -n regex Match service name to regular expression.")); _cupsLangPuts(stderr, _(" -p Print URI if true.")); _cupsLangPuts(stderr, _(" -q Quietly report match via exit code.")); _cupsLangPuts(stderr, _(" -r True if service is remote.")); _cupsLangPuts(stderr, _(" -s Print service name if true.")); _cupsLangPuts(stderr, _(" -t key True if the TXT record contains the key.")); _cupsLangPuts(stderr, _(" -u regex Match URI to regular expression.")); _cupsLangPuts(stderr, _(" -x utility [argument ...] ;\n" " Execute program if true.")); _cupsLangPuts(stderr, _(" --domain regex Match domain to regular expression.")); _cupsLangPuts(stderr, _(" --exec utility [argument ...] ;\n" " Execute program if true.")); _cupsLangPuts(stderr, _(" --host regex Match hostname to regular expression.")); _cupsLangPuts(stderr, _(" --ls List attributes.")); _cupsLangPuts(stderr, _(" --local True if service is local.")); _cupsLangPuts(stderr, _(" --name regex Match service name to regular expression.")); _cupsLangPuts(stderr, _(" --path regex Match resource path to regular expression.")); _cupsLangPuts(stderr, _(" --port number[-number] Match port to number or range.")); _cupsLangPuts(stderr, _(" --print Print URI if true.")); _cupsLangPuts(stderr, _(" --print-name Print service name if true.")); _cupsLangPuts(stderr, _(" --quiet Quietly report match via exit code.")); _cupsLangPuts(stderr, _(" --remote True if service is remote.")); _cupsLangPuts(stderr, _(" --txt key True if the TXT record contains the key.")); _cupsLangPuts(stderr, _(" --txt-* regex Match TXT record key to regular expression.")); _cupsLangPuts(stderr, _(" --uri regex Match URI to regular expression.")); _cupsLangPuts(stderr, ""); _cupsLangPuts(stderr, _("Modifiers:")); _cupsLangPuts(stderr, _(" ( expressions ) Group expressions.")); _cupsLangPuts(stderr, _(" ! expression Unary NOT of expression.")); _cupsLangPuts(stderr, _(" --not expression Unary NOT of expression.")); _cupsLangPuts(stderr, _(" --false Always false.")); _cupsLangPuts(stderr, _(" --true Always true.")); _cupsLangPuts(stderr, _(" expression expression Logical AND.")); _cupsLangPuts(stderr, _(" expression --and expression\n" " Logical AND.")); _cupsLangPuts(stderr, _(" expression --or expression\n" " Logical OR.")); _cupsLangPuts(stderr, ""); _cupsLangPuts(stderr, _("Substitutions:")); _cupsLangPuts(stderr, _(" {} URI")); _cupsLangPuts(stderr, _(" {service_domain} Domain name")); _cupsLangPuts(stderr, _(" {service_hostname} Fully-qualified domain name")); _cupsLangPuts(stderr, _(" {service_name} Service instance name")); _cupsLangPuts(stderr, _(" {service_port} Port number")); _cupsLangPuts(stderr, _(" {service_regtype} DNS-SD registration type")); _cupsLangPuts(stderr, _(" {service_scheme} URI scheme")); _cupsLangPuts(stderr, _(" {service_uri} URI")); _cupsLangPuts(stderr, _(" {txt_*} Value of TXT record key")); _cupsLangPuts(stderr, ""); _cupsLangPuts(stderr, _("Environment Variables:")); _cupsLangPuts(stderr, _(" IPPFIND_SERVICE_DOMAIN Domain name")); _cupsLangPuts(stderr, _(" IPPFIND_SERVICE_HOSTNAME\n" " Fully-qualified domain name")); _cupsLangPuts(stderr, _(" IPPFIND_SERVICE_NAME Service instance name")); _cupsLangPuts(stderr, _(" IPPFIND_SERVICE_PORT Port number")); _cupsLangPuts(stderr, _(" IPPFIND_SERVICE_REGTYPE DNS-SD registration type")); _cupsLangPuts(stderr, _(" IPPFIND_SERVICE_SCHEME URI scheme")); _cupsLangPuts(stderr, _(" IPPFIND_SERVICE_URI URI")); _cupsLangPuts(stderr, _(" IPPFIND_TXT_* Value of TXT record key")); exit(IPPFIND_EXIT_TRUE); } /* * 'show_version()' - Show program version. */ static void show_version(void) { _cupsLangPuts(stderr, CUPS_SVERSION); exit(IPPFIND_EXIT_TRUE); } ippsample/tools/dither.h0000644000175000017500000005073113240604116014335 0ustar tilltill/* Simple ordered dither threshold matrix */ const unsigned char threshold[64][64] = { { 0, 235, 138, 22, 45, 98, 217, 2, 45, 98, 7, 185, 45, 97, 6, 192, 110, 37, 110, 37, 97, 45, 18, 148, 109, 37, 97, 45, 7, 185, 45, 97, 6, 192, 109, 37, 57, 82, 165, 12, 26, 130, 190, 6, 119, 31, 97, 45, 179, 8, 109, 37, 97, 45, 140, 22, 109, 37, 57, 82, 9, 177, 24, 135 }, { 109, 37, 57, 82, 20, 143, 57, 82, 146, 19, 57, 82, 15, 158, 87, 53, 20, 144, 13, 162, 138, 22, 53, 87, 162, 13, 138, 22, 57, 82, 22, 140, 57, 82, 153, 16, 119, 31, 109, 37, 109, 37, 57, 81, 19, 147, 213, 2, 53, 87, 21, 142, 13, 164, 53, 87, 187, 6, 152, 17, 119, 32, 110, 37 }, { 24, 135, 12, 167, 97, 45, 17, 151, 45, 97, 32, 119, 26, 130, 119, 32, 81, 58, 30, 121, 81, 58, 181, 8, 119, 32, 97, 45, 17, 151, 45, 97, 161, 14, 45, 97, 213, 2, 135, 24, 7, 183, 138, 22, 109, 37, 58, 81, 121, 30, 109, 37, 58, 81, 30, 121, 58, 81, 127, 27, 58, 81, 165, 12 }, { 58, 81, 31, 119, 5, 197, 58, 81, 9, 175, 206, 3, 58, 81, 10, 174, 222, 1, 45, 97, 206, 3, 124, 29, 58, 81, 4, 200, 58, 81, 2, 217, 58, 81, 27, 127, 108, 37, 58, 81, 30, 121, 58, 81, 167, 12, 25, 132, 15, 158, 5, 197, 135, 24, 206, 3, 142, 21, 45, 97, 203, 3, 119, 32 }, { 6, 190, 108, 38, 97, 45, 143, 20, 108, 38, 97, 45, 148, 18, 108, 38, 58, 81, 148, 18, 119, 32, 97, 45, 16, 153, 97, 45, 143, 20, 46, 97, 32, 119, 6, 187, 25, 132, 13, 164, 46, 97, 1, 222, 119, 32, 108, 38, 108, 38, 108, 38, 108, 38, 108, 38, 58, 81, 8, 179, 123, 29, 97, 46 }, { 58, 81, 161, 14, 147, 19, 53, 87, 22, 138, 14, 159, 87, 53, 22, 138, 14, 159, 108, 38, 87, 53, 177, 9, 53, 87, 14, 161, 58, 81, 22, 137, 12, 167, 108, 38, 108, 38, 81, 58, 153, 16, 123, 29, 53, 87, 187, 6, 162, 13, 132, 25, 11, 168, 25, 132, 12, 165, 119, 32, 81, 58, 14, 161 }, { 140, 22, 108, 38, 81, 58, 8, 181, 108, 38, 97, 46, 8, 181, 58, 81, 31, 119, 7, 185, 147, 19, 58, 81, 127, 27, 97, 46, 8, 179, 108, 38, 58, 81, 21, 142, 13, 162, 5, 194, 108, 38, 58, 81, 15, 156, 87, 53, 30, 121, 108, 38, 108, 38, 58, 81, 127, 27, 97, 46, 16, 153, 97, 46 }, { 58, 81, 2, 217, 123, 29, 36, 111, 1, 227, 138, 22, 97, 46, 4, 203, 108, 38, 108, 38, 97, 46, 23, 137, 222, 1, 112, 36, 58, 81, 6, 192, 137, 23, 53, 87, 30, 121, 58, 80, 23, 137, 183, 7, 36, 111, 26, 130, 59, 80, 0, 235, 130, 26, 192, 6, 46, 97, 222, 1, 53, 87, 194, 5 }, { 17, 151, 46, 97, 172, 10, 59, 80, 27, 127, 59, 80, 18, 148, 59, 80, 172, 10, 24, 135, 4, 200, 80, 59, 36, 112, 167, 12, 137, 23, 108, 38, 97, 46, 0, 235, 46, 97, 144, 20, 46, 97, 127, 27, 53, 87, 3, 206, 147, 19, 108, 38, 108, 38, 80, 59, 151, 17, 80, 59, 27, 127, 96, 46 }, { 58, 81, 126, 27, 96, 46, 15, 156, 46, 97, 172, 10, 46, 96, 14, 159, 119, 32, 59, 80, 32, 119, 156, 15, 53, 87, 27, 127, 59, 80, 21, 142, 10, 172, 80, 59, 177, 9, 80, 59, 2, 213, 59, 80, 14, 161, 108, 38, 59, 79, 23, 137, 11, 168, 137, 23, 46, 96, 32, 119, 13, 164, 140, 22 }, { 6, 190, 152, 17, 112, 36, 59, 79, 6, 187, 59, 79, 30, 121, 108, 38, 96, 46, 15, 156, 46, 96, 29, 123, 183, 7, 46, 96, 209, 3, 46, 96, 32, 118, 26, 130, 96, 46, 15, 158, 46, 96, 16, 153, 46, 96, 32, 118, 10, 172, 108, 38, 108, 38, 59, 79, 179, 8, 141, 21, 59, 79, 32, 119 }, { 87, 53, 36, 112, 203, 4, 137, 23, 96, 46, 23, 137, 4, 200, 24, 135, 235, 0, 87, 53, 8, 179, 108, 38, 87, 53, 15, 156, 53, 87, 156, 15, 59, 79, 156, 15, 119, 32, 59, 79, 30, 121, 59, 79, 6, 190, 151, 17, 59, 79, 187, 6, 26, 130, 3, 206, 108, 38, 96, 46, 206, 3, 110, 37 }, { 142, 21, 59, 79, 28, 126, 59, 79, 144, 20, 59, 79, 119, 32, 60, 79, 32, 118, 27, 129, 87, 53, 3, 209, 118, 32, 60, 79, 126, 28, 96, 46, 5, 194, 46, 96, 197, 5, 134, 24, 7, 183, 137, 23, 46, 96, 36, 112, 28, 126, 108, 38, 108, 38, 60, 79, 148, 18, 118, 32, 60, 79, 167, 12 }, { 37, 109, 174, 10, 46, 95, 10, 174, 47, 95, 170, 11, 47, 95, 9, 177, 47, 95, 14, 159, 118, 32, 60, 79, 170, 11, 134, 24, 183, 7, 112, 36, 79, 60, 140, 22, 108, 38, 107, 38, 107, 39, 79, 60, 17, 149, 60, 79, 213, 2, 24, 135, 177, 9, 159, 14, 47, 95, 9, 175, 137, 23, 47, 95 }, { 0, 235, 60, 79, 18, 149, 87, 53, 217, 2, 53, 87, 156, 15, 86, 53, 16, 153, 54, 86, 167, 12, 137, 23, 107, 39, 60, 79, 36, 112, 172, 10, 147, 19, 47, 95, 19, 147, 9, 175, 132, 25, 1, 227, 36, 110, 9, 175, 112, 36, 60, 79, 30, 121, 60, 79, 126, 28, 112, 36, 60, 79, 19, 147 }, { 37, 109, 140, 22, 47, 95, 30, 121, 60, 78, 30, 121, 61, 78, 32, 118, 61, 78, 200, 4, 112, 36, 61, 78, 19, 147, 227, 1, 47, 95, 27, 129, 86, 54, 2, 217, 54, 86, 28, 126, 61, 78, 126, 28, 61, 78, 129, 26, 95, 47, 15, 158, 47, 95, 20, 144, 1, 222, 95, 47, 6, 190, 47, 95 }, { 13, 164, 61, 78, 4, 200, 162, 13, 24, 134, 183, 7, 24, 134, 213, 2, 142, 21, 123, 29, 95, 47, 192, 6, 107, 39, 86, 54, 153, 16, 54, 86, 30, 121, 61, 78, 30, 121, 95, 47, 170, 11, 47, 95, 10, 172, 47, 94, 179, 8, 61, 78, 4, 200, 107, 39, 61, 78, 22, 140, 61, 78, 23, 137 }, { 37, 109, 31, 120, 107, 39, 107, 39, 107, 39, 107, 39, 61, 78, 121, 30, 107, 39, 61, 78, 19, 146, 86, 54, 23, 137, 13, 164, 61, 77, 200, 4, 159, 14, 131, 25, 13, 164, 4, 200, 86, 54, 18, 148, 54, 86, 203, 4, 94, 47, 19, 146, 47, 94, 23, 137, 13, 161, 47, 94, 17, 151, 47, 94 }, { 26, 131, 6, 187, 158, 15, 26, 131, 4, 203, 26, 131, 177, 9, 47, 94, 14, 159, 10, 174, 94, 47, 151, 17, 61, 77, 32, 118, 27, 129, 118, 32, 107, 39, 107, 39, 86, 54, 126, 28, 118, 32, 61, 77, 31, 120, 77, 61, 126, 28, 86, 54, 14, 161, 107, 39, 77, 61, 6, 190, 61, 77, 3, 206 }, { 107, 39, 61, 77, 121, 30, 86, 54, 121, 30, 107, 39, 61, 77, 16, 153, 107, 39, 86, 54, 1, 222, 94, 47, 8, 179, 47, 94, 174, 10, 54, 86, 11, 168, 5, 194, 144, 20, 86, 54, 17, 152, 3, 209, 162, 13, 134, 24, 12, 167, 123, 29, 61, 77, 7, 185, 136, 23, 47, 94, 32, 118, 27, 127 }, { 164, 13, 144, 20, 94, 47, 174, 10, 61, 77, 11, 170, 123, 29, 37, 110, 5, 194, 123, 29, 86, 54, 20, 143, 61, 77, 3, 206, 61, 77, 18, 148, 118, 32, 85, 54, 32, 118, 177, 9, 85, 55, 28, 126, 106, 39, 106, 39, 61, 77, 0, 235, 118, 32, 106, 39, 61, 77, 19, 147, 177, 9, 81, 58 }, { 106, 39, 77, 61, 222, 1, 94, 47, 18, 149, 48, 93, 227, 1, 85, 55, 29, 123, 168, 11, 112, 36, 85, 55, 33, 117, 27, 129, 117, 33, 106, 39, 94, 47, 149, 18, 77, 61, 27, 129, 117, 33, 61, 77, 20, 144, 6, 190, 117, 33, 55, 85, 159, 14, 26, 131, 3, 209, 117, 32, 94, 47, 16, 153 }, { 5, 194, 123, 29, 55, 85, 19, 146, 62, 77, 126, 28, 37, 110, 156, 15, 62, 77, 36, 112, 17, 151, 194, 5, 151, 17, 77, 62, 17, 152, 2, 217, 175, 9, 93, 47, 227, 0, 48, 93, 6, 192, 168, 11, 117, 33, 77, 62, 161, 14, 140, 22, 106, 39, 106, 39, 106, 39, 62, 77, 28, 126, 81, 58 }, { 47, 94, 153, 16, 123, 29, 85, 55, 5, 197, 152, 17, 62, 77, 29, 123, 10, 174, 48, 93, 28, 126, 106, 39, 93, 48, 8, 181, 106, 39, 62, 77, 33, 117, 144, 20, 62, 77, 18, 148, 106, 39, 106, 39, 93, 48, 18, 147, 48, 93, 33, 117, 192, 6, 164, 13, 131, 26, 14, 158, 227, 1, 140, 22 }, { 13, 164, 85, 55, 10, 174, 117, 33, 106, 39, 93, 48, 10, 172, 106, 39, 62, 77, 2, 209, 62, 77, 161, 14, 142, 21, 62, 77, 33, 117, 143, 20, 106, 39, 93, 48, 22, 138, 48, 93, 158, 15, 131, 26, 1, 217, 85, 55, 200, 4, 106, 39, 105, 39, 105, 40, 105, 40, 105, 40, 105, 40, 87, 53 }, { 85, 55, 120, 31, 62, 77, 6, 187, 142, 21, 123, 29, 85, 55, 5, 194, 123, 29, 37, 110, 179, 8, 117, 33, 85, 55, 23, 136, 6, 192, 62, 77, 10, 174, 5, 197, 62, 77, 8, 179, 105, 40, 105, 40, 85, 55, 120, 31, 62, 77, 167, 12, 26, 131, 15, 158, 5, 194, 168, 11, 147, 19, 118, 32 }, { 135, 24, 3, 209, 136, 23, 105, 40, 62, 76, 209, 3, 123, 29, 63, 76, 15, 155, 63, 76, 27, 129, 93, 48, 0, 235, 105, 40, 93, 48, 17, 151, 48, 93, 33, 116, 16, 155, 37, 110, 4, 203, 162, 13, 24, 134, 11, 168, 136, 23, 105, 40, 105, 40, 105, 40, 63, 76, 126, 28, 85, 55, 6, 190 }, { 37, 109, 33, 117, 63, 76, 21, 142, 12, 165, 48, 93, 16, 155, 123, 29, 93, 48, 11, 170, 48, 93, 16, 155, 55, 85, 170, 11, 136, 23, 63, 76, 146, 19, 63, 76, 27, 129, 76, 63, 27, 129, 116, 33, 76, 63, 33, 117, 63, 76, 19, 147, 217, 2, 168, 11, 142, 21, 48, 93, 120, 31, 80, 59 }, { 175, 9, 93, 49, 10, 172, 105, 40, 63, 76, 125, 28, 85, 55, 8, 179, 117, 33, 84, 55, 197, 5, 55, 84, 27, 129, 116, 33, 93, 49, 213, 2, 49, 93, 11, 170, 49, 93, 172, 10, 105, 40, 93, 49, 5, 194, 49, 93, 192, 6, 116, 33, 63, 76, 120, 31, 63, 76, 3, 206, 162, 13, 26, 131 }, { 37, 109, 18, 149, 63, 76, 0, 235, 131, 26, 187, 6, 116, 33, 84, 55, 1, 222, 140, 22, 63, 76, 33, 116, 8, 179, 84, 55, 158, 15, 55, 84, 27, 129, 84, 55, 217, 2, 55, 84, 20, 144, 10, 174, 55, 84, 149, 18, 122, 29, 93, 49, 20, 143, 49, 93, 15, 158, 116, 33, 105, 40, 80, 59 }, { 138, 22, 93, 49, 22, 138, 105, 40, 105, 40, 63, 76, 159, 14, 136, 23, 63, 75, 33, 116, 164, 13, 144, 20, 93, 49, 5, 194, 63, 75, 33, 116, 185, 7, 116, 33, 75, 63, 31, 120, 104, 40, 75, 63, 31, 120, 104, 41, 75, 63, 181, 8, 84, 55, 6, 192, 104, 41, 84, 55, 21, 142, 217, 2 }, { 84, 55, 197, 5, 55, 84, 19, 146, 13, 164, 140, 22, 104, 41, 93, 49, 18, 149, 49, 93, 28, 125, 63, 75, 125, 28, 93, 49, 21, 141, 11, 168, 63, 75, 165, 12, 24, 134, 15, 158, 209, 3, 26, 131, 15, 158, 1, 227, 144, 20, 49, 93, 16, 153, 63, 75, 23, 136, 10, 172, 63, 75, 120, 30 }, { 14, 161, 75, 63, 177, 8, 116, 33, 75, 63, 33, 116, 2, 213, 175, 9, 63, 75, 190, 6, 92, 49, 2, 213, 152, 17, 111, 36, 63, 75, 36, 112, 27, 129, 111, 36, 104, 41, 104, 41, 104, 41, 104, 41, 104, 41, 104, 41, 75, 63, 125, 28, 92, 49, 14, 161, 104, 41, 92, 49, 7, 185, 49, 92 }, { 47, 94, 144, 20, 122, 30, 92, 49, 5, 197, 49, 92, 28, 125, 92, 49, 143, 20, 49, 92, 18, 149, 75, 63, 36, 112, 11, 168, 222, 1, 49, 92, 203, 4, 55, 84, 190, 6, 162, 13, 26, 130, 190, 6, 164, 13, 26, 130, 13, 162, 206, 3, 122, 30, 84, 55, 0, 235, 122, 30, 84, 55, 16, 152 }, { 6, 192, 116, 33, 75, 63, 16, 155, 63, 74, 15, 156, 64, 74, 20, 143, 84, 55, 22, 138, 92, 49, 143, 20, 49, 92, 27, 129, 55, 84, 156, 15, 56, 84, 16, 155, 116, 33, 104, 41, 104, 41, 104, 41, 104, 41, 104, 41, 103, 41, 64, 74, 181, 8, 115, 33, 64, 74, 152, 17, 122, 30, 80, 59 }, { 103, 41, 92, 49, 213, 2, 49, 92, 28, 125, 92, 49, 6, 185, 92, 49, 3, 206, 64, 74, 7, 185, 64, 74, 190, 6, 64, 74, 31, 120, 64, 74, 33, 117, 103, 41, 64, 74, 20, 144, 8, 181, 24, 134, 15, 158, 5, 197, 141, 21, 122, 30, 56, 84, 19, 146, 13, 164, 50, 91, 203, 4, 112, 36 }, { 24, 134, 12, 167, 56, 84, 34, 115, 172, 10, 136, 23, 64, 74, 18, 149, 92, 49, 18, 149, 91, 49, 15, 156, 50, 91, 20, 144, 7, 183, 24, 134, 183, 7, 24, 134, 235, 0, 50, 91, 31, 120, 64, 74, 125, 28, 115, 34, 64, 74, 161, 14, 115, 34, 103, 41, 64, 74, 125, 28, 37, 110, 165, 12 }, { 103, 41, 64, 74, 23, 136, 185, 7, 103, 41, 91, 50, 20, 143, 50, 91, 22, 138, 56, 84, 31, 120, 64, 74, 31, 120, 103, 41, 103, 41, 64, 74, 31, 120, 103, 41, 64, 74, 125, 28, 91, 50, 217, 2, 103, 41, 91, 50, 10, 174, 50, 91, 22, 140, 200, 4, 134, 24, 7, 183, 65, 74, 28, 126 }, { 227, 1, 146, 19, 103, 41, 65, 74, 21, 142, 227, 1, 65, 74, 6, 190, 65, 74, 9, 175, 0, 235, 24, 134, 206, 3, 162, 13, 130, 26, 213, 2, 50, 91, 13, 162, 131, 26, 185, 7, 152, 17, 65, 74, 170, 11, 144, 20, 56, 84, 1, 222, 103, 41, 103, 41, 103, 41, 91, 50, 175, 9, 50, 91 }, { 49, 93, 33, 116, 6, 187, 136, 23, 50, 91, 33, 116, 18, 149, 50, 91, 19, 147, 103, 41, 103, 41, 102, 41, 102, 42, 102, 42, 102, 42, 65, 74, 21, 141, 102, 42, 102, 42, 65, 74, 125, 28, 115, 34, 102, 42, 65, 74, 31, 119, 65, 74, 167, 12, 26, 130, 12, 165, 115, 34, 84, 56, 151, 17 }, { 148, 18, 102, 42, 102, 42, 84, 56, 174, 10, 102, 42, 65, 74, 22, 140, 65, 74, 159, 14, 131, 26, 11, 168, 26, 131, 15, 158, 7, 185, 159, 14, 50, 91, 5, 197, 168, 11, 141, 21, 50, 91, 179, 8, 24, 134, 4, 203, 162, 13, 142, 21, 102, 42, 102, 42, 65, 74, 2, 217, 140, 22, 80, 59 }, { 49, 92, 9, 175, 24, 133, 3, 209, 65, 74, 19, 146, 185, 7, 90, 50, 3, 209, 102, 42, 65, 74, 31, 120, 102, 42, 65, 74, 31, 120, 65, 73, 34, 115, 27, 129, 115, 34, 56, 84, 203, 4, 111, 36, 65, 73, 125, 28, 102, 42, 65, 73, 23, 136, 192, 6, 136, 23, 102, 42, 90, 50, 6, 187 }, { 31, 119, 102, 42, 102, 42, 90, 50, 138, 22, 102, 42, 65, 73, 125, 28, 65, 73, 21, 141, 194, 5, 50, 90, 192, 6, 141, 21, 50, 90, 21, 141, 6, 187, 102, 42, 65, 73, 16, 155, 122, 30, 90, 50, 14, 161, 50, 90, 34, 115, 200, 4, 102, 42, 102, 42, 84, 56, 18, 149, 115, 34, 79, 59 }, { 209, 3, 25, 133, 6, 187, 146, 19, 65, 73, 203, 4, 134, 24, 11, 168, 111, 36, 102, 42, 65, 73, 19, 147, 102, 42, 65, 73, 1, 227, 102, 42, 65, 73, 19, 146, 217, 2, 115, 34, 56, 84, 17, 152, 73, 65, 177, 9, 151, 17, 73, 65, 165, 12, 131, 26, 175, 9, 73, 65, 9, 174, 24, 134 }, { 33, 117, 102, 42, 65, 73, 34, 115, 11, 170, 115, 34, 65, 73, 36, 111, 181, 7, 168, 11, 136, 23, 50, 90, 161, 14, 146, 19, 50, 90, 159, 14, 136, 23, 102, 42, 102, 42, 73, 65, 7, 183, 90, 50, 1, 227, 50, 90, 36, 111, 27, 129, 115, 34, 72, 65, 34, 115, 27, 127, 111, 36, 79, 59 }, { 50, 90, 164, 13, 141, 21, 102, 42, 102, 42, 90, 50, 15, 156, 50, 90, 27, 127, 115, 34, 66, 72, 2, 217, 102, 42, 66, 72, 22, 138, 102, 42, 66, 72, 167, 12, 133, 25, 12, 165, 37, 110, 28, 125, 72, 66, 143, 20, 72, 66, 179, 8, 90, 50, 235, 0, 51, 90, 203, 4, 90, 50, 7, 183 }, { 17, 152, 101, 42, 66, 72, 235, 0, 25, 133, 8, 181, 66, 72, 222, 1, 101, 43, 90, 50, 17, 152, 51, 90, 23, 136, 185, 7, 51, 90, 9, 175, 203, 4, 114, 34, 72, 66, 125, 28, 72, 66, 172, 10, 146, 19, 90, 51, 209, 3, 51, 90, 153, 16, 56, 84, 16, 155, 56, 84, 16, 155, 87, 53 }, { 84, 56, 6, 192, 151, 17, 114, 35, 72, 66, 35, 114, 27, 127, 37, 110, 17, 152, 197, 5, 84, 56, 14, 161, 101, 43, 72, 66, 18, 149, 72, 66, 125, 28, 90, 51, 190, 6, 51, 90, 3, 206, 51, 90, 35, 114, 11, 170, 66, 72, 159, 14, 66, 72, 28, 125, 66, 72, 31, 119, 66, 72, 127, 27 }, { 111, 36, 66, 72, 124, 28, 90, 51, 16, 155, 51, 90, 16, 155, 66, 72, 29, 124, 66, 72, 124, 29, 66, 72, 5, 192, 136, 23, 51, 90, 144, 19, 51, 90, 149, 18, 56, 83, 18, 149, 66, 72, 142, 20, 101, 43, 84, 56, 31, 119, 83, 56, 35, 114, 170, 10, 25, 133, 183, 7, 133, 25, 1, 222 }, { 172, 10, 141, 21, 51, 90, 170, 11, 83, 56, 4, 200, 89, 51, 11, 170, 52, 89, 21, 141, 183, 7, 114, 35, 101, 43, 66, 72, 2, 213, 66, 72, 8, 179, 66, 72, 22, 140, 52, 89, 147, 19, 52, 89, 203, 4, 133, 25, 8, 181, 25, 133, 4, 200, 101, 43, 66, 72, 114, 35, 83, 56, 36, 111 }, { 28, 126, 66, 72, 3, 206, 37, 110, 29, 124, 72, 66, 31, 119, 71, 66, 4, 203, 101, 43, 67, 71, 167, 12, 25, 133, 12, 165, 52, 89, 29, 124, 89, 52, 0, 235, 52, 89, 177, 9, 56, 83, 11, 170, 114, 35, 67, 71, 35, 114, 101, 43, 67, 71, 35, 114, 2, 213, 52, 89, 177, 9, 79, 59 }, { 51, 90, 15, 156, 122, 30, 67, 71, 8, 181, 133, 25, 185, 7, 141, 21, 52, 89, 16, 155, 114, 35, 101, 43, 101, 43, 67, 71, 36, 111, 165, 12, 136, 23, 56, 83, 31, 119, 67, 71, 35, 114, 127, 27, 89, 52, 15, 156, 52, 89, 167, 12, 133, 25, 12, 165, 83, 56, 16, 155, 89, 52, 15, 156 }, { 6, 192, 101, 43, 89, 52, 148, 18, 101, 43, 101, 43, 101, 43, 67, 71, 124, 29, 67, 71, 0, 235, 25, 133, 200, 4, 133, 25, 183, 7, 101, 43, 67, 71, 19, 146, 187, 6, 133, 25, 217, 2, 67, 71, 8, 181, 67, 71, 1, 222, 114, 35, 101, 43, 67, 71, 31, 119, 67, 71, 31, 119, 79, 59 }, { 51, 90, 23, 135, 10, 172, 67, 71, 24, 135, 222, 1, 26, 130, 15, 158, 10, 174, 114, 35, 100, 43, 67, 71, 31, 119, 67, 70, 35, 114, 21, 141, 5, 194, 114, 35, 100, 43, 100, 43, 89, 52, 16, 155, 52, 89, 27, 127, 122, 30, 56, 83, 197, 5, 132, 25, 8, 181, 25, 133, 206, 3, 137, 23 }, { 18, 149, 100, 43, 89, 52, 194, 5, 100, 43, 100, 43, 100, 43, 100, 43, 68, 70, 7, 185, 26, 131, 175, 9, 52, 88, 11, 170, 100, 43, 100, 43, 100, 43, 68, 70, 21, 141, 12, 165, 111, 36, 68, 70, 35, 113, 16, 155, 56, 83, 16, 155, 113, 35, 68, 70, 35, 113, 68, 70, 113, 35, 79, 59 }, { 52, 88, 227, 1, 135, 24, 68, 70, 167, 12, 26, 130, 13, 162, 209, 3, 135, 24, 100, 43, 100, 43, 83, 56, 18, 148, 56, 83, 1, 222, 162, 13, 132, 25, 12, 167, 52, 88, 35, 113, 7, 183, 25, 133, 4, 203, 56, 83, 175, 9, 122, 30, 88, 52, 15, 156, 52, 88, 168, 11, 52, 88, 181, 8 }, { 27, 129, 113, 35, 88, 52, 20, 143, 100, 43, 100, 43, 100, 43, 99, 43, 68, 70, 19, 146, 5, 194, 113, 35, 68, 70, 35, 113, 29, 124, 99, 44, 99, 44, 68, 70, 2, 213, 68, 70, 29, 124, 99, 44, 68, 70, 31, 119, 99, 44, 70, 68, 177, 9, 70, 68, 227, 1, 83, 56, 16, 153, 56, 83 }, { 170, 11, 70, 68, 10, 174, 68, 70, 19, 146, 197, 5, 158, 15, 130, 26, 175, 9, 113, 35, 56, 83, 21, 140, 3, 209, 152, 17, 56, 83, 21, 141, 4, 197, 122, 30, 88, 52, 16, 153, 52, 88, 165, 12, 132, 25, 183, 7, 25, 132, 213, 2, 88, 52, 143, 20, 52, 88, 119, 31, 68, 70, 32, 118 }, { 88, 52, 19, 147, 88, 52, 213, 2, 99, 44, 99, 44, 99, 44, 99, 44, 99, 44, 68, 70, 161, 14, 111, 36, 99, 44, 68, 70, 7, 183, 99, 44, 70, 68, 16, 153, 122, 30, 70, 68, 5, 197, 113, 35, 68, 70, 35, 113, 68, 70, 35, 113, 29, 124, 68, 70, 24, 135, 187, 6, 25, 132, 3, 209 }, { 31, 119, 70, 68, 124, 29, 82, 57, 21, 141, 13, 164, 132, 25, 187, 6, 25, 132, 217, 2, 122, 30, 70, 68, 18, 148, 122, 30, 37, 110, 16, 153, 122, 30, 56, 82, 10, 172, 113, 35, 99, 44, 88, 52, 0, 235, 52, 88, 14, 159, 52, 88, 17, 152, 5, 194, 99, 44, 99, 44, 99, 44, 79, 60 }, { 13, 162, 200, 4, 167, 11, 111, 36, 68, 70, 119, 31, 68, 70, 119, 31, 98, 44, 98, 45, 87, 52, 6, 190, 53, 87, 9, 177, 57, 82, 30, 122, 8, 179, 113, 35, 69, 68, 7, 185, 132, 25, 12, 164, 57, 82, 17, 152, 69, 69, 177, 9, 69, 69, 35, 113, 165, 12, 26, 130, 11, 168, 132, 25 }, { 37, 109, 69, 69, 36, 111, 17, 151, 190, 6, 53, 87, 1, 227, 53, 87, 10, 174, 130, 26, 14, 159, 69, 69, 20, 143, 69, 69, 206, 3, 98, 45, 69, 69, 1, 227, 142, 21, 98, 45, 98, 45, 69, 69, 124, 29, 37, 110, 5, 197, 87, 53, 20, 143, 53, 87, 29, 124, 98, 45, 98, 45, 79, 60 }, { 26, 130, 14, 159, 53, 87, 29, 124, 82, 57, 18, 148, 82, 57, 18, 148, 98, 45, 98, 45, 87, 53, 138, 22, 53, 87, 124, 29, 37, 110, 165, 12, 142, 21, 98, 45, 69, 69, 24, 135, 3, 209, 132, 25, 181, 8, 82, 57, 27, 127, 113, 35, 82, 57, 177, 9, 57, 82, 213, 2, 25, 132, 6, 187 }, { 37, 109, 61, 78, 8, 179, 61, 78, 20, 143, 66, 72, 22, 138, 66, 72, 24, 135, 4, 200, 175, 9, 72, 66, 1, 227, 151, 17, 72, 66, 29, 124, 68, 70, 24, 135, 181, 8, 98, 45, 98, 45, 98, 45, 68, 70, 18, 148, 70, 68, 17, 151, 222, 1, 70, 68, 18, 148, 112, 35, 98, 45, 78, 61 } }; ippsample/tools/Dependencies0000644000175000017500000000317413240604116015215 0ustar tilltillippfind.o: ippfind.c ../cups/cups-private.h ../cups/string-private.h \ ../config.h ../cups/debug-private.h ../cups/versioning.h \ ../cups/array-private.h ../cups/array.h ../cups/ipp-private.h \ ../cups/ipp.h ../cups/http.h ../cups/http-private.h ../cups/language.h \ ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ ../cups/pwg-private.h ../cups/cups.h ../cups/file.h ../cups/pwg.h \ ../cups/thread-private.h ippproxy.o: ippproxy.c ../cups/cups.h ../cups/file.h ../cups/versioning.h \ ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h \ ../cups/pwg.h ../cups/thread-private.h ../config.h ipptool.o: ipptool.c ../cups/cups-private.h ../cups/string-private.h \ ../config.h ../cups/debug-private.h ../cups/versioning.h \ ../cups/array-private.h ../cups/array.h ../cups/ipp-private.h \ ../cups/ipp.h ../cups/http.h ../cups/http-private.h ../cups/language.h \ ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ ../cups/pwg-private.h ../cups/cups.h ../cups/file.h ../cups/pwg.h \ ../cups/thread-private.h ../cups/file-private.h ipptransform.o: ipptransform.c ../cups/cups.h ../cups/file.h \ ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ ../cups/language.h ../cups/pwg.h ../cups/raster.h \ ../cups/array-private.h ../cups/string-private.h ../config.h \ ../cups/thread-private.h dither.h ipptransform3d.o: ipptransform3d.c ../config.h ../cups/cups.h \ ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h \ ../cups/array.h ../cups/language.h ../cups/pwg.h \ ../cups/array-private.h ../cups/string-private.h \ ../cups/thread-private.h ippsample/tools/ippproxy.c0000644000175000017500000007555013240604116014751 0ustar tilltill/* * IPP Proxy implementation for HP PCL and IPP Everywhere printers. * * Copyright 2016-2017 by the IEEE-ISTO Printer Working Group. * Copyright 2014-2017 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ #include #include #include #include #include #include /* * Local types... */ typedef struct proxy_info_s { const char *printer_uri, *device_uri, *device_uuid; } proxy_info_t; typedef struct proxy_job_s { ipp_jstate_t local_job_state; /* Local job-state value */ int local_job_id, /* Local job-id value */ remote_job_id, /* Remote job-id value */ remote_job_state; /* Remote job-state value */ } proxy_job_t; /* * Local globals... */ static cups_array_t *jobs; /* Local jobs */ static _cups_cond_t jobs_cond = _CUPS_COND_INITIALIZER; /* Condition for jobs array */ static _cups_mutex_t jobs_mutex = _CUPS_MUTEX_INITIALIZER; /* Mutex for jobs array */ static const char * const printer_attrs[] = { /* Printer attributes we care about */ "copies-supported", "document-format-supported", "jpeg-k-octets-supported", "media-bottom-margin-supported", "media-col-database", "media-col-default", "media-col-ready", "media-col-supported", "media-default", "media-left-margin-supported", "media-ready", "media-right-margin-supported", "media-size-supported", "media-source-supported", "media-supported", "media-top-margin-supported", "media-type-supported", "pdf-k-octets-supported", "print-color-mode-default", "print-color-mode-supported", "print-quality-default", "print-quality-supported", "printer-resolution-default", "printer-resolution-supported", "printer-state", "printer-state-message", "printer-state-reasons", "pwg-raster-document-resolution-supported", "pwg-raster-document-sheet-back", "pwg-raster-document-type-supported", "sides-default", "sides-supported", "urf-supported" }; static int stop_running = 0; static int verbosity = 0; /* * Local functions... */ static int attrs_are_equal(ipp_attribute_t *a, ipp_attribute_t *b); static int compare_jobs(proxy_job_t *a, proxy_job_t *b); static proxy_job_t *copy_job(proxy_job_t *src); static ipp_t *create_media_col(const char *media, const char *source, const char *type, int width, int length, int margins); static ipp_t *create_media_size(int width, int length); static void deregister_printer(http_t *http, const char *printer_uri, const char *resource, int subscription_id, const char *device_uuid); static int fetch_job(http_t *http, const char *printer_uri, const char *resource, int job_id, const char *device_uri, const char *device_uuid, ipp_t *device_attrs); static ipp_t *get_device_attrs(const char *device_uri); static void make_uuid(const char *device_uri, char *uuid, size_t uuidsize); static const char *password_cb(const char *prompt, http_t *http, const char *method, const char *resource, void *user_data); static void *proxy_jobs(proxy_info_t *info); static int register_printer(http_t *http, const char *printer_uri, const char *resource, const char *device_uri, const char *device_uuid); static void run_printer(http_t *http, const char *printer_uri, const char *resource, int subscription_id, const char *device_uri, const char *device_uuid); static void sighandler(int sig); static int update_device_attrs(http_t *http, const char *printer_uri, const char *resource, const char *device_uuid, ipp_t *old_attrs, ipp_t *new_attrs); static void usage(int status) __attribute__((noreturn)); /* * 'main()' - Main entry for ippproxy. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ char *opt, /* Current option */ *device_uri = NULL, /* Device URI */ *password = NULL, /* Password, if any */ *printer_uri = NULL; /* Infrastructure printer URI */ cups_dest_t *dest; /* Destination for printer URI */ http_t *http; /* Connection to printer */ char resource[1024]; /* Resource path */ int subscription_id; /* Event subscription ID */ char device_uuid[45]; /* Device UUID URN */ /* * Parse command-line... */ for (i = 1; i < argc; i ++) { if (argv[i][0] == '-' && argv[i][1] != '-') { for (opt = argv[i] + 1; *opt; opt ++) { switch (*opt) { case 'd' : /* -d device-uri */ i ++; if (i >= argc) { fputs("ippproxy: Missing device URI after '-d' option.\n", stderr); usage(1); } device_uri = argv[i]; break; case 'p' : /* -p password */ i ++; if (i >= argc) { fputs("ippproxy: Missing password after '-p' option.\n", stderr); usage(1); } password = argv[i]; break; case 'u' : /* -u user */ i ++; if (i >= argc) { fputs("ippproxy: Missing username after '-u' option.\n", stderr); usage(1); } cupsSetUser(argv[i]); break; case 'v' : /* Be verbose */ verbosity ++; break; default : fprintf(stderr, "ippproxy: Unknown option '-%c'.\n", *opt); usage(1); break; } } } else if (!strcmp(argv[i], "--help")) usage(0); else if (printer_uri) { fprintf(stderr, "ippproxy: Unexpected option '%s'.\n", argv[i]); usage(1); } else printer_uri = argv[i]; } if (!printer_uri) usage(1); if (!device_uri) { fputs("ippproxy: Must specify '-d device-uri'.\n", stderr); usage(1); } if (!password) password = getenv("IPPPROXY_PASSWORD"); if (password) cupsSetPasswordCB2(password_cb, password); make_uuid(device_uri, device_uuid, sizeof(device_uuid)); /* * Connect to the infrastructure printer... */ dest = cupsGetDestWithURI("infra", printer_uri); while ((http = cupsConnectDest(dest, CUPS_DEST_FLAGS_NONE, 30000, NULL, resource, sizeof(resource), NULL, NULL)) == NULL) { fprintf(stderr, "ippproxy: Infrastructure printer at '%s' is not responding, retrying in 30 seconds...\n", printer_uri); sleep(30); } cupsFreeDests(1, dest); /* * Register the printer and wait for jobs to process... */ signal(SIGHUP, sighandler); signal(SIGINT, sighandler); signal(SIGTERM, sighandler); if ((subscription_id = register_printer(http, printer_uri, resource, device_uri, device_uuid)) == 0) { httpClose(http); return (1); } run_printer(http, printer_uri, resource, subscription_id, device_uri, device_uuid); deregister_printer(http, printer_uri, resource, subscription_id, device_uuid); httpClose(http); return (0); } /* * 'attrs_are_equal()' - Compare two attributes for equality. */ static int /* O - 1 if equal, 0 otherwise */ attrs_are_equal(ipp_attribute_t *a, /* I - First attribute */ ipp_attribute_t *b) /* I - Second attribute */ { int i, /* Looping var */ count; /* Number of values */ ipp_tag_t tag; /* Type of value */ /* * Check that both 'a' and 'b' point to something first... */ if ((a != NULL) != (b != NULL)) return (0); if (a == NULL && b == NULL) return (1); /* * Check that 'a' and 'b' are of the same type with the same number * of values... */ if ((tag = ippGetValueTag(a)) != ippGetValueTag(b)) return (0); if ((count = ippGetCount(a)) != ippGetCount(b)) return (0); /* * Compare values... */ switch (tag) { case IPP_TAG_INTEGER : case IPP_TAG_ENUM : for (i = 0; i < count; i ++) if (ippGetInteger(a, i) != ippGetInteger(b, i)) return (0); break; case IPP_TAG_BOOLEAN : for (i = 0; i < count; i ++) if (ippGetBoolean(a, i) != ippGetBoolean(b, i)) return (0); break; case IPP_TAG_KEYWORD : for (i = 0; i < count; i ++) if (strcmp(ippGetString(a, i, NULL), ippGetString(b, i, NULL))) return (0); break; default : return (0); } /* * If we get this far we must be the same... */ return (1); } /* * 'compare_jobs()' - Compare two jobs. */ static int compare_jobs(proxy_job_t *a, /* I - First job */ proxy_job_t *b) /* I - Second job */ { return (a->remote_job_id - b->remote_job_id); } /* * 'copy_job()' - Create a job of a job. */ static proxy_job_t * /* O - New job */ copy_job(proxy_job_t *src) /* I - Original job */ { proxy_job_t *dst; /* New job */ if ((dst = malloc(sizeof(proxy_job_t))) != NULL) memcpy(dst, src, sizeof(proxy_job_t)); return (dst); } /* * 'create_media_col()' - Create a media-col value. */ static ipp_t * /* O - media-col collection */ create_media_col(const char *media, /* I - Media name */ const char *source, /* I - Media source */ const char *type, /* I - Media type */ int width, /* I - x-dimension in 2540ths */ int length, /* I - y-dimension in 2540ths */ int margins) /* I - Value for margins */ { ipp_t *media_col = ippNew(), /* media-col value */ *media_size = create_media_size(width, length); /* media-size value */ char media_key[256]; /* media-key value */ if (type && source) snprintf(media_key, sizeof(media_key), "%s_%s_%s%s", media, source, type, margins == 0 ? "_borderless" : ""); else if (type) snprintf(media_key, sizeof(media_key), "%s__%s%s", media, type, margins == 0 ? "_borderless" : ""); else if (source) snprintf(media_key, sizeof(media_key), "%s_%s%s", media, source, margins == 0 ? "_borderless" : ""); else snprintf(media_key, sizeof(media_key), "%s%s", media, margins == 0 ? "_borderless" : ""); ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-key", NULL, media_key); ippAddCollection(media_col, IPP_TAG_PRINTER, "media-size", media_size); ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-size-name", NULL, media); ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin", margins); ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-left-margin", margins); ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-right-margin", margins); ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-top-margin", margins); if (source) ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-source", NULL, source); if (type) ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-type", NULL, type); ippDelete(media_size); return (media_col); } /* * 'create_media_size()' - Create a media-size value. */ static ipp_t * /* O - media-col collection */ create_media_size(int width, /* I - x-dimension in 2540ths */ int length) /* I - y-dimension in 2540ths */ { ipp_t *media_size = ippNew(); /* media-size value */ ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "x-dimension", width); ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "y-dimension", length); return (media_size); } /* * 'deregister_printer()' - Unregister the output device and cancel the printer subscription. */ static void deregister_printer( http_t *http, /* I - Connection to printer */ const char *printer_uri, /* I - Printer URI */ const char *resource, /* I - Resource path */ int subscription_id, /* I - Subscription ID */ const char *device_uuid) /* I - Device UUID */ { ipp_t *request; /* IPP request */ /* * Deregister the output device... */ request = ippNewRequest(IPP_OP_DEREGISTER_OUTPUT_DEVICE); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer_uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "output-device-uuid", NULL, device_uuid); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippDelete(cupsDoRequest(http, request, resource)); /* * Then cancel the subscription we are using... */ request = ippNewRequest(IPP_OP_CANCEL_SUBSCRIPTION); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer_uri); ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "notify-subscription-id", subscription_id); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippDelete(cupsDoRequest(http, request, resource)); } /* * 'fetch_job()' - Fetch and print a job. */ static int /* O - 1 on success, 0 on failure */ fetch_job(http_t *http, /* I - Connection to printer */ const char *printer_uri, /* I - Printer URI */ const char *resource, /* I - Resource path */ int job_id, /* I - Job ID */ const char *device_uri, /* I - Device URI */ const char *device_uuid, /* I - Device UUID */ ipp_t *device_attrs) /* I - Device attributes */ { (void)http; (void)printer_uri; (void)resource; (void)job_id; (void)device_uri; (void)device_uuid; (void)device_attrs; return (0); } /* * 'get_device_attrs()' - Get current attributes for a device. */ static ipp_t * /* O - IPP attributes */ get_device_attrs(const char *device_uri)/* I - Device URI */ { ipp_t *response = NULL; /* IPP attributes */ if (!strncmp(device_uri, "ipp://", 6) || !strncmp(device_uri, "ipps://", 7)) { /* * Query the IPP printer... */ cups_dest_t *dest; /* Destination for printer URI */ http_t *http; /* Connection to printer */ char resource[1024]; /* Resource path */ ipp_t *request; /* Get-Printer-Attributes request */ /* * Connect to the printer... */ dest = cupsGetDestWithURI("device", device_uri); while ((http = cupsConnectDest(dest, CUPS_DEST_FLAGS_NONE, 30000, NULL, resource, sizeof(resource), NULL, NULL)) == NULL) { fprintf(stderr, "ippproxy: Device at '%s' is not responding, retrying in 30 seconds...\n", device_uri); sleep(30); } cupsFreeDests(1, dest); /* * Get the attributes... */ request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, device_uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(printer_attrs) / sizeof(printer_attrs[0])), NULL, printer_attrs); response = cupsDoRequest(http, request, resource); if (cupsLastError() >= IPP_STATUS_ERROR_BAD_REQUEST) { fprintf(stderr, "ippproxy: Device at '%s' returned error: %s\n", device_uri, cupsLastErrorString()); ippDelete(response); response = NULL; } httpClose(http); } else { /* * Must be a socket-based HP PCL laser printer, report just * standard size information... */ int i; /* Looping var */ ipp_attribute_t *media_col_database, /* media-col-database value */ *media_size_supported; /* media-size-supported value */ ipp_t *media_col; /* media-col-default value */ static const int media_col_sizes[][2] = { /* Default media-col sizes */ { 21590, 27940 }, /* Letter */ { 21590, 35560 }, /* Legal */ { 21000, 29700 } /* A4 */ }; static const char * const media_col_supported[] = { /* media-col-supported values */ "media-bottom-margin", "media-left-margin", "media-right-margin", "media-size", "media-size-name", "media-top-margin" }; static const char * const media_supported[] = { /* Default media sizes */ "na_letter_8.5x11in", /* Letter */ "na_legal_8.5x14in", /* Legal */ "iso_a4_210x297mm" /* A4 */ }; static const int quality_supported[] = { /* print-quality-supported values */ IPP_QUALITY_DRAFT, IPP_QUALITY_NORMAL, IPP_QUALITY_HIGH }; static const int resolution_supported[] = { /* printer-resolution-supported values */ 300, 600 }; static const char * const sides_supported[] = { /* sides-supported values */ "one-sided", "two-sided-long-edge", "two-sided-short-edge" }; response = ippNew(); ippAddRange(response, IPP_TAG_PRINTER, "copies-supported", 1, 1); ippAddString(response, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, "document-format-supported", NULL, "application/vnd.hp-pcl"); ippAddInteger(response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin-supported", 635); media_col_database = ippAddCollections(response, IPP_TAG_PRINTER, "media-col-database", (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])), NULL); for (i = 0; i < (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])); i ++) { media_col = create_media_col(media_supported[i], NULL, NULL, media_col_sizes[i][0], media_col_sizes[i][1], 635); ippSetCollection(response, &media_col_database, i, media_col); ippDelete(media_col); } media_col = create_media_col(media_supported[0], NULL, NULL, media_col_sizes[0][0], media_col_sizes[0][1], 635); ippAddCollection(response, IPP_TAG_PRINTER, "media-col-default", media_col); ippDelete(media_col); media_col = create_media_col(media_supported[0], NULL, NULL, media_col_sizes[0][0], media_col_sizes[0][1], 635); ippAddCollection(response, IPP_TAG_PRINTER, "media-col-ready", media_col); ippDelete(media_col); ippAddStrings(response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-col-supported", (int)(sizeof(media_col_supported) / sizeof(media_col_supported[0])), NULL, media_col_supported); ippAddString(response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default", NULL, media_supported[0]); ippAddInteger(response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-left-margin-supported", 635); ippAddString(response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-ready", NULL, media_supported[0]); ippAddInteger(response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-right-margin-supported", 635); media_size_supported = ippAddCollections(response, IPP_TAG_PRINTER, "media-size-supported", (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])), NULL); for (i = 0; i < (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])); i ++) { ipp_t *size = create_media_size(media_col_sizes[i][0], media_col_sizes[i][1]); ippSetCollection(response, &media_size_supported, i, size); ippDelete(size); } ippAddStrings(response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-supported", (int)(sizeof(media_supported) / sizeof(media_supported[0])), NULL, media_supported); ippAddInteger(response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-top-margin-supported", 635); ippAddString(response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "print-color-mode-default", NULL, "monochrome"); ippAddString(response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "print-color-mode-supported", NULL, "monochrome"); ippAddInteger(response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "print-quality-default", IPP_QUALITY_NORMAL); ippAddIntegers(response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "print-quality-supported", (int)(sizeof(quality_supported) / sizeof(quality_supported[0])), quality_supported); ippAddResolution(response, IPP_TAG_PRINTER, "printer-resolution-default", IPP_RES_PER_INCH, 300, 300); ippAddResolutions(response, IPP_TAG_PRINTER, "printer-resolution-supported", (int)(sizeof(resolution_supported) / sizeof(resolution_supported[0])), IPP_RES_PER_INCH, resolution_supported, resolution_supported); ippAddInteger(response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", IPP_PSTATE_IDLE); ippAddString(response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "printer-state-reasons", NULL, "none"); ippAddString(response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-default", NULL, "two-sided-long-edge"); ippAddStrings(response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-supported", (int)(sizeof(sides_supported) / sizeof(sides_supported[0])), NULL, sides_supported); } return (response); } /* * 'make_uuid()' - Make a RFC 4122 URN UUID from the device URI. * * NULL device URIs are (appropriately) mapped to "file://hostname/dev/null". */ static void make_uuid(const char *device_uri, /* I - Device URI or NULL */ char *uuid, /* I - UUID string buffer */ size_t uuidsize) /* I - Size of UUID buffer */ { char nulluri[1024]; /* NULL URI buffer */ unsigned char sha256[32]; /* SHA-256 hash */ /* * Use "file://hostname/dev/null" if the device URI is NULL... */ if (!device_uri) { char host[1024]; /* Hostname */ httpGetHostname(NULL, host, sizeof(host)); httpAssembleURI(HTTP_URI_CODING_ALL, nulluri, sizeof(nulluri), "file", NULL, host, 0, "/dev/null"); device_uri = nulluri; } /* * Build a version 3 UUID conforming to RFC 4122 based on the * SHA-256 hash of the device URI */ cupsHashData("sha-256", device_uri, strlen(device_uri), sha256, sizeof(sha256)); snprintf(uuid, uuidsize, "urn:uuid:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", sha256[0], sha256[1], sha256[2], sha256[3], sha256[4], sha256[5], (sha256[6] & 15) | 0x30, sha256[7], (sha256[8] & 0x3f) | 0x40, sha256[9], sha256[10], sha256[11], sha256[12], sha256[13], sha256[14], sha256[15]); fprintf(stderr, "ippproxy: UUID for '%s' is '%s'.\n", device_uri, uuid); } /* * 'password_cb()' - Password callback. */ static const char * /* O - Password string */ password_cb(const char *prompt, /* I - Prompt (unused) */ http_t *http, /* I - Connection (unused) */ const char *method, /* I - Method (unused) */ const char *resource, /* I - Resource path (unused) */ void *user_data) /* I - Password string */ { (void)prompt; (void)http; (void)method; (void)resource; return ((char *)user_data); } /* * 'proxy_jobs()' - Relay jobs to the local printer. */ static void * /* O - Thread exit status */ proxy_jobs(proxy_info_t *info) /* I - Printer and device info */ { (void)info; for (;;) { _cupsMutexLock(&jobs_mutex); _cupsCondWait(&jobs_cond, &jobs_mutex, 0.0); _cupsMutexUnlock(&jobs_mutex); } return (NULL); } /* * 'register_printer()' - Register the printer (output device) with the Infrastructure Printer. */ static int /* O - Subscription ID */ register_printer( http_t *http, /* I - Connection to printer */ const char *printer_uri, /* I - Printer URI */ const char *resource, /* I - Resource path */ const char *device_uri, /* I - Device URI, if any */ const char *device_uuid) /* I - Device UUID */ { ipp_t *request, /* IPP request */ *response; /* IPP response */ ipp_attribute_t *attr; /* Attribute in response */ int subscription_id = 0; /* Subscription ID */ static const char * const events[] = /* Events to monitor */ { "document-config-change", "document-state-change", "job-config-change", "job-state-change", "printer-config-change", "printer-state-change" }; (void)device_uri; (void)device_uuid; /* * Create a printer subscription to monitor for events... */ request = ippNewRequest(IPP_OP_CREATE_PRINTER_SUBSCRIPTION); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer_uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddString(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-pull-method", NULL, "ippget"); ippAddStrings(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-events", (int)(sizeof(events) / sizeof(events[0])), NULL, events); ippAddInteger(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-lease-duration", 0); response = cupsDoRequest(http, request, resource); if (cupsLastError() != IPP_STATUS_OK) { fprintf(stderr, "ippproxy: Unable to monitor events on '%s': %s\n", printer_uri, cupsLastErrorString()); return (0); } if ((attr = ippFindAttribute(response, "notify-subscription-id", IPP_TAG_INTEGER)) != NULL) { subscription_id = ippGetInteger(attr, 0); } else { fprintf(stderr, "ippproxy: Unable to monitor events on '%s': No notify-subscription-id returned.\n", printer_uri); } ippDelete(response); return (subscription_id); } /* * 'run_printer()' - Run the printer until no work remains. */ static void run_printer( http_t *http, /* I - Connection to printer */ const char *printer_uri, /* I - Printer URI */ const char *resource, /* I - Resource path */ int subscription_id, /* I - Subscription ID */ const char *device_uri, /* I - Device URI, if any */ const char *device_uuid) /* I - Device UUID */ { ipp_t *device_attrs, /* Device attributes */ *request, /* IPP request */ *response; /* IPP response */ ipp_attribute_t *attr; /* IPP attribute */ const char *name, /* Attribute name */ *event; /* Current event */ int job_id; /* Job ID, if any */ ipp_jstate_t job_state; /* Job state, if any */ int seq_number = 1; /* Current event sequence number */ int get_interval; /* How long to sleep */ proxy_info_t info; /* Information for proxy thread */ _cups_thread_t jobs_thread; /* Job proxy processing thread */ /* * Initialize the local jobs array... */ jobs = cupsArrayNew3((cups_array_func_t)compare_jobs, NULL, NULL, 0, (cups_acopy_func_t)copy_job, (cups_afree_func_t)free); info.printer_uri = printer_uri; info.device_uri = device_uri; info.device_uuid = device_uuid; jobs_thread = _cupsThreadCreate((_cups_thread_func_t)proxy_jobs, &info); /* * Query the printer... */ device_attrs = get_device_attrs(device_uri); /* * Register the output device... */ if (!update_device_attrs(http, printer_uri, resource, device_uuid, NULL, device_attrs)) return; while (!stop_running) { /* * See if we have any work to do... */ request = ippNewRequest(IPP_OP_GET_NOTIFICATIONS); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer_uri); ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "notify-subscription-ids", subscription_id); ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "notify-sequence-numbers", seq_number); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddBoolean(request, IPP_TAG_OPERATION, "notify-wait", 1); response = cupsDoRequest(http, request, resource); if ((attr = ippFindAttribute(response, "notify-get-interval", IPP_TAG_INTEGER)) != NULL) get_interval = ippGetInteger(attr, 0); else get_interval = 30; for (attr = ippFirstAttribute(response); attr; attr = ippNextAttribute(response)) { if (ippGetGroupTag(attr) != IPP_TAG_EVENT_NOTIFICATION || !ippGetName(attr)) continue; event = NULL; job_id = 0; job_state = IPP_JSTATE_PENDING; while (ippGetGroupTag(attr) == IPP_TAG_EVENT_NOTIFICATION && (name = ippGetName(attr)) != NULL) { if (!strcmp(name, "notify-subscribed-event") && ippGetValueTag(attr) == IPP_TAG_KEYWORD) event = ippGetString(attr, 0, NULL); else if (!strcmp(name, "notify-job-id") && ippGetValueTag(attr) == IPP_TAG_INTEGER) job_id = ippGetInteger(attr, 0); else if (!strcmp(name, "job-state") && ippGetValueTag(attr) == IPP_TAG_ENUM) job_state = (ipp_jstate_t)ippGetInteger(attr, 0); else if (!strcmp(name, "notify-sequence-number") && ippGetValueTag(attr) == IPP_TAG_INTEGER) { int new_seq = ippGetInteger(attr, 0); if (new_seq > seq_number) seq_number = new_seq; } attr = ippNextAttribute(response); } if (event) { if (!strcmp(event, "job-fetchable") && job_id) { /* TODO: queue up fetches */ fetch_job(http, printer_uri, resource, job_id, device_uri, device_uuid, device_attrs); } else if (!strcmp(event, "job-state-changed") && job_id) { /* TODO: Support cancellation */ if (job_state == IPP_JSTATE_CANCELED || job_state == IPP_JSTATE_ABORTED) { /* Cancel job locally if it is printing... */ } } } } /* * Pause before our next poll of the Infrastructure Printer... */ if (get_interval > 0 && get_interval < 3600) sleep((unsigned)get_interval); else sleep(30); } /* * Stop the job proxy thread... */ _cupsThreadCancel(jobs_thread); _cupsThreadWait(jobs_thread); } /* * 'sighandler()' - Handle termination signals so we can clean up... */ static void sighandler(int sig) /* I - Signal */ { (void)sig; stop_running = 1; } /* * 'update_device_attrs()' - Update device attributes on the server. */ static int /* O - 1 on success, 0 on failure */ update_device_attrs( http_t *http, /* I - Connection to server */ const char *printer_uri, /* I - Printer URI */ const char *resource, /* I - Resource path */ const char *device_uuid, /* I - Device UUID */ ipp_t *old_attrs, /* I - Old attributes */ ipp_t *new_attrs) /* I - New attributes */ { int i, /* Looping var */ result; /* Result of comparison */ ipp_t *request; /* IPP request */ ipp_attribute_t *attr; /* New attribute */ const char *name; /* New attribute name */ /* * Update the configuration of the output device... */ request = ippNewRequest(IPP_OP_UPDATE_OUTPUT_DEVICE_ATTRIBUTES); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer_uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "output-device-uuid", NULL, device_uuid); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); for (attr = ippFirstAttribute(new_attrs); attr; attr = ippNextAttribute(new_attrs)) { /* * Add any attributes that have changed... */ if (ippGetGroupTag(attr) != IPP_TAG_PRINTER || (name = ippGetName(attr)) == NULL) continue; for (i = 0, result = 1; i < (int)(sizeof(printer_attrs) / sizeof(printer_attrs[0])) && result > 0; i ++) { if ((result = strcmp(name, printer_attrs[i])) == 0) { /* * This is an attribute we care about... */ if (!attrs_are_equal(ippFindAttribute(old_attrs, name, ippGetValueTag(attr)), attr)) ippCopyAttribute(request, attr, 1); } } } ippDelete(cupsDoRequest(http, request, resource)); if (cupsLastError() != IPP_STATUS_OK) { fprintf(stderr, "ippproxy: Unable to update the output device with '%s': %s\n", printer_uri, cupsLastErrorString()); return (0); } return (1); } /* * 'usage()' - Show program usage and exit. */ static void usage(int status) /* O - Exit status */ { puts("Usage: ippproxy [options] printer-uri"); puts("Options:"); puts(" -d device-uri Specify local printer device URI."); puts(" -p password Password for authentication."); puts(" (Also IPPPROXY_PASSWORD environment variable)"); puts(" -u username Username for authentication."); puts(" -v Be verbose."); puts(" --help Show this help."); exit(status); } ippsample/tools/ipptool.c0000644000175000017500000041231113240604116014533 0ustar tilltill/* * ipptool command for CUPS. * * Copyright © 2007-2018 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ /* * Include necessary headers... */ #define _IPP_PRIVATE_STRUCTURES 0 /* Disable private IPP stuff */ #include #include #include #include #ifdef WIN32 # include # ifndef R_OK # define R_OK 0 # endif /* !R_OK */ #else # include # include #endif /* WIN32 */ #ifndef O_BINARY # define O_BINARY 0 #endif /* !O_BINARY */ /* * Types... */ typedef enum _cups_transfer_e /**** How to send request data ****/ { _CUPS_TRANSFER_AUTO, /* Chunk for files, length for static */ _CUPS_TRANSFER_CHUNKED, /* Chunk always */ _CUPS_TRANSFER_LENGTH /* Length always */ } _cups_transfer_t; typedef enum _cups_output_e /**** Output mode ****/ { _CUPS_OUTPUT_QUIET, /* No output */ _CUPS_OUTPUT_TEST, /* Traditional CUPS test output */ _CUPS_OUTPUT_PLIST, /* XML plist test output */ _CUPS_OUTPUT_IPPSERVER, /* ippserver attribute file output */ _CUPS_OUTPUT_LIST, /* Tabular list output */ _CUPS_OUTPUT_CSV /* Comma-separated values output */ } _cups_output_t; typedef enum _cups_with_e /**** WITH flags ****/ { _CUPS_WITH_LITERAL = 0, /* Match string is a literal value */ _CUPS_WITH_ALL = 1, /* Must match all values */ _CUPS_WITH_REGEX = 2, /* Match string is a regular expression */ _CUPS_WITH_HOSTNAME = 4, /* Match string is a URI hostname */ _CUPS_WITH_RESOURCE = 8, /* Match string is a URI resource */ _CUPS_WITH_SCHEME = 16 /* Match string is a URI scheme */ } _cups_with_t; typedef struct _cups_expect_s /**** Expected attribute info ****/ { int optional, /* Optional attribute? */ not_expect, /* Don't expect attribute? */ expect_all; /* Expect all attributes to match/not match */ char *name, /* Attribute name */ *of_type, /* Type name */ *same_count_as, /* Parallel attribute name */ *if_defined, /* Only required if variable defined */ *if_not_defined, /* Only required if variable is not defined */ *with_value, /* Attribute must include this value */ *with_value_from, /* Attribute must have one of the values in this attribute */ *define_match, /* Variable to define on match */ *define_no_match, /* Variable to define on no-match */ *define_value; /* Variable to define with value */ int repeat_limit, /* Maximum number of times to repeat */ repeat_match, /* Repeat test on match */ repeat_no_match, /* Repeat test on no match */ with_flags, /* WITH flags */ count; /* Expected count if > 0 */ ipp_tag_t in_group; /* IN-GROUP value */ } _cups_expect_t; typedef struct _cups_status_s /**** Status info ****/ { ipp_status_t status; /* Expected status code */ char *if_defined, /* Only if variable is defined */ *if_not_defined, /* Only if variable is not defined */ *define_match, /* Variable to define on match */ *define_no_match, /* Variable to define on no-match */ *define_value; /* Variable to define with value */ int repeat_limit, /* Maximum number of times to repeat */ repeat_match, /* Repeat the test when it does not match */ repeat_no_match; /* Repeat the test when it matches */ } _cups_status_t; typedef struct _cups_testdata_s /**** Test Data ****/ { /* Global Options */ http_encryption_t encryption; /* Encryption for connection */ int family; /* Address family */ _cups_output_t output; /* Output mode */ int stop_after_include_error; /* Stop after include errors? */ double timeout; /* Timeout for connection */ int validate_headers, /* Validate HTTP headers in response? */ verbosity; /* Show all attributes? */ /* Test Defaults */ int def_ignore_errors; /* Default IGNORE-ERRORS value */ _cups_transfer_t def_transfer; /* Default TRANSFER value */ int def_version; /* Default IPP version */ /* Global State */ http_t *http; /* HTTP connection to printer/server */ cups_file_t *outfile; /* Output file */ int show_header, /* Show the test header? */ xml_header; /* 1 if XML plist header was written */ int pass, /* Have we passed all tests? */ test_count, /* Number of tests (total) */ pass_count, /* Number of tests that passed */ fail_count, /* Number of tests that failed */ skip_count; /* Number of tests that were skipped */ /* Per-Test State */ cups_array_t *errors; /* Errors array */ int prev_pass, /* Result of previous test */ skip_previous; /* Skip on previous test failure? */ char compression[16]; /* COMPRESSION value */ useconds_t delay; /* Initial delay */ int num_displayed; /* Number of displayed attributes */ char *displayed[200]; /* Displayed attributes */ int num_expects; /* Number of expected attributes */ _cups_expect_t expects[200], /* Expected attributes */ *expect, /* Current expected attribute */ *last_expect; /* Last EXPECT (for predicates) */ char file[1024], /* Data filename */ file_id[1024]; /* File identifier */ int ignore_errors; /* Ignore test failures? */ char name[1024]; /* Test name */ useconds_t repeat_interval; /* Repeat interval (delay) */ int request_id; /* Current request ID */ char resource[512]; /* Resource for request */ int skip_test, /* Skip this test? */ num_statuses; /* Number of valid status codes */ _cups_status_t statuses[100], /* Valid status codes */ *last_status; /* Last STATUS (for predicates) */ char test_id[1024]; /* Test identifier */ _cups_transfer_t transfer; /* To chunk or not to chunk */ int version; /* IPP version number to use */ } _cups_testdata_t; /* * Globals... */ static int Cancel = 0; /* Cancel test? */ /* * Local functions... */ static void add_stringf(cups_array_t *a, const char *s, ...) __attribute__ ((__format__ (__printf__, 2, 3))); static int compare_uris(const char *a, const char *b); static int do_test(_ipp_file_t *f, _ipp_vars_t *vars, _cups_testdata_t *data); static int do_tests(const char *testfile, _ipp_vars_t *vars, _cups_testdata_t *data); static int error_cb(_ipp_file_t *f, _cups_testdata_t *data, const char *error); static int expect_matches(_cups_expect_t *expect, ipp_tag_t value_tag); static char *get_filename(const char *testfile, char *dst, const char *src, size_t dstsize); static const char *get_string(ipp_attribute_t *attr, int element, int flags, char *buffer, size_t bufsize); static void init_data(_cups_testdata_t *data); static char *iso_date(const ipp_uchar_t *date); static void pause_message(const char *message); static void print_attr(cups_file_t *outfile, int output, ipp_attribute_t *attr, ipp_tag_t *group); static void print_csv(_cups_testdata_t *data, ipp_t *ipp, ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths); static void print_fatal_error(_cups_testdata_t *data, const char *s, ...) __attribute__ ((__format__ (__printf__, 2, 3))); static void print_ippserver_attr(_cups_testdata_t *data, ipp_attribute_t *attr, int indent); static void print_ippserver_string(_cups_testdata_t *data, const char *s, size_t len); static void print_line(_cups_testdata_t *data, ipp_t *ipp, ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths); static void print_xml_header(_cups_testdata_t *data); static void print_xml_string(cups_file_t *outfile, const char *element, const char *s); static void print_xml_trailer(_cups_testdata_t *data, int success, const char *message); #ifndef WIN32 static void sigterm_handler(int sig); #endif /* WIN32 */ static int timeout_cb(http_t *http, void *user_data); static int token_cb(_ipp_file_t *f, _ipp_vars_t *vars, _cups_testdata_t *data, const char *token); static void usage(void) __attribute__((noreturn)); static const char *with_flags_string(int flags); static int with_value(_cups_testdata_t *data, cups_array_t *errors, char *value, int flags, ipp_attribute_t *attr, char *matchbuf, size_t matchlen); static int with_value_from(cups_array_t *errors, ipp_attribute_t *fromattr, ipp_attribute_t *attr, char *matchbuf, size_t matchlen); /* * 'main()' - Parse options and do tests. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ int status; /* Status of tests... */ char *opt, /* Current option */ name[1024], /* Name/value buffer */ *value, /* Pointer to value */ filename[1024], /* Real filename */ testname[1024]; /* Real test filename */ const char *ext, /* Extension on filename */ *testfile; /* Test file to use */ int interval, /* Test interval in microseconds */ repeat; /* Repeat count */ _cups_testdata_t data; /* Test data */ _ipp_vars_t vars; /* Variables */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ #ifndef WIN32 /* * Catch SIGINT and SIGTERM... */ signal(SIGINT, sigterm_handler); signal(SIGTERM, sigterm_handler); #endif /* !WIN32 */ /* * Initialize the locale and variables... */ _cupsSetLocale(argv); init_data(&data); _ippVarsInit(&vars, NULL, (_ipp_ferror_cb_t)error_cb, (_ipp_ftoken_cb_t)token_cb); /* * We need at least: * * ipptool URI testfile */ interval = 0; repeat = 0; status = 0; testfile = NULL; for (i = 1; i < argc; i ++) { if (!strcmp(argv[i], "--help")) { usage(); } else if (!strcmp(argv[i], "--ippserver")) { i ++; if (i >= argc) { _cupsLangPuts(stderr, _("ipptool: Missing filename for \"--ippserver\".")); usage(); } if (data.outfile != cupsFileStdout()) usage(); if ((data.outfile = cupsFileOpen(argv[i], "w")) == NULL) { _cupsLangPrintf(stderr, _("%s: Unable to open \"%s\": %s"), "ipptool", argv[i], strerror(errno)); exit(1); } data.output = _CUPS_OUTPUT_IPPSERVER; } else if (!strcmp(argv[i], "--stop-after-include-error")) { data.stop_after_include_error = 1; } else if (!strcmp(argv[i], "--version")) { puts(CUPS_SVERSION); return (0); } else if (argv[i][0] == '-') { for (opt = argv[i] + 1; *opt; opt ++) { switch (*opt) { case '4' : /* Connect using IPv4 only */ data.family = AF_INET; break; #ifdef AF_INET6 case '6' : /* Connect using IPv6 only */ data.family = AF_INET6; break; #endif /* AF_INET6 */ case 'C' : /* Enable HTTP chunking */ data.def_transfer = _CUPS_TRANSFER_CHUNKED; break; case 'E' : /* Encrypt with TLS */ #ifdef HAVE_SSL data.encryption = HTTP_ENCRYPT_REQUIRED; #else _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]); #endif /* HAVE_SSL */ break; case 'I' : /* Ignore errors */ data.def_ignore_errors = 1; break; case 'L' : /* Disable HTTP chunking */ data.def_transfer = _CUPS_TRANSFER_LENGTH; break; case 'P' : /* Output to plist file */ i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("%s: Missing filename for \"-P\"."), "ipptool"); usage(); } if (data.outfile != cupsFileStdout()) usage(); if ((data.outfile = cupsFileOpen(argv[i], "w")) == NULL) { _cupsLangPrintf(stderr, _("%s: Unable to open \"%s\": %s"), "ipptool", argv[i], strerror(errno)); exit(1); } data.output = _CUPS_OUTPUT_PLIST; if (interval || repeat) { _cupsLangPuts(stderr, _("ipptool: \"-i\" and \"-n\" are incompatible with \"-P\" and \"-X\".")); usage(); } break; case 'S' : /* Encrypt with SSL */ #ifdef HAVE_SSL data.encryption = HTTP_ENCRYPT_ALWAYS; #else _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]); #endif /* HAVE_SSL */ break; case 'T' : /* Set timeout */ i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("%s: Missing timeout for \"-T\"."), "ipptool"); usage(); } data.timeout = _cupsStrScand(argv[i], NULL, localeconv()); break; case 'V' : /* Set IPP version */ i ++; if (i >= argc) { _cupsLangPrintf(stderr, _("%s: Missing version for \"-V\"."), "ipptool"); usage(); } if (!strcmp(argv[i], "1.0")) { data.def_version = 10; } else if (!strcmp(argv[i], "1.1")) { data.def_version = 11; } else if (!strcmp(argv[i], "2.0")) { data.def_version = 20; } else if (!strcmp(argv[i], "2.1")) { data.def_version = 21; } else if (!strcmp(argv[i], "2.2")) { data.def_version = 22; } else { _cupsLangPrintf(stderr, _("%s: Bad version %s for \"-V\"."), "ipptool", argv[i]); usage(); } break; case 'X' : /* Produce XML output */ data.output = _CUPS_OUTPUT_PLIST; if (interval || repeat) { _cupsLangPuts(stderr, _("ipptool: \"-i\" and \"-n\" are incompatible with \"-P\" and \"-X\".")); usage(); } break; case 'c' : /* CSV output */ data.output = _CUPS_OUTPUT_CSV; break; case 'd' : /* Define a variable */ i ++; if (i >= argc) { _cupsLangPuts(stderr, _("ipptool: Missing name=value for \"-d\".")); usage(); } strlcpy(name, argv[i], sizeof(name)); if ((value = strchr(name, '=')) != NULL) *value++ = '\0'; else value = name + strlen(name); _ippVarsSet(&vars, name, value); break; case 'f' : /* Set the default test filename */ i ++; if (i >= argc) { _cupsLangPuts(stderr, _("ipptool: Missing filename for \"-f\".")); usage(); } if (access(argv[i], 0)) { /* * Try filename.gz... */ snprintf(filename, sizeof(filename), "%s.gz", argv[i]); if (access(filename, 0) && filename[0] != '/' #ifdef WIN32 && (!isalpha(filename[0] & 255) || filename[1] != ':') #endif /* WIN32 */ ) { snprintf(filename, sizeof(filename), "%s/ipptool/%s", cg->cups_datadir, argv[i]); if (access(filename, 0)) { snprintf(filename, sizeof(filename), "%s/ipptool/%s.gz", cg->cups_datadir, argv[i]); if (access(filename, 0)) strlcpy(filename, argv[i], sizeof(filename)); } } } else strlcpy(filename, argv[i], sizeof(filename)); _ippVarsSet(&vars, "filename", filename); if ((ext = strrchr(filename, '.')) != NULL) { /* * Guess the MIME media type based on the extension... */ if (!_cups_strcasecmp(ext, ".gif")) _ippVarsSet(&vars, "filetype", "image/gif"); else if (!_cups_strcasecmp(ext, ".htm") || !_cups_strcasecmp(ext, ".htm.gz") || !_cups_strcasecmp(ext, ".html") || !_cups_strcasecmp(ext, ".html.gz")) _ippVarsSet(&vars, "filetype", "text/html"); else if (!_cups_strcasecmp(ext, ".jpg") || !_cups_strcasecmp(ext, ".jpeg")) _ippVarsSet(&vars, "filetype", "image/jpeg"); else if (!_cups_strcasecmp(ext, ".pcl") || !_cups_strcasecmp(ext, ".pcl.gz")) _ippVarsSet(&vars, "filetype", "application/vnd.hp-PCL"); else if (!_cups_strcasecmp(ext, ".pdf")) _ippVarsSet(&vars, "filetype", "application/pdf"); else if (!_cups_strcasecmp(ext, ".png")) _ippVarsSet(&vars, "filetype", "image/png"); else if (!_cups_strcasecmp(ext, ".ps") || !_cups_strcasecmp(ext, ".ps.gz")) _ippVarsSet(&vars, "filetype", "application/postscript"); else if (!_cups_strcasecmp(ext, ".pwg") || !_cups_strcasecmp(ext, ".pwg.gz") || !_cups_strcasecmp(ext, ".ras") || !_cups_strcasecmp(ext, ".ras.gz")) _ippVarsSet(&vars, "filetype", "image/pwg-raster"); else if (!_cups_strcasecmp(ext, ".tif") || !_cups_strcasecmp(ext, ".tiff")) _ippVarsSet(&vars, "filetype", "image/tiff"); else if (!_cups_strcasecmp(ext, ".txt") || !_cups_strcasecmp(ext, ".txt.gz")) _ippVarsSet(&vars, "filetype", "text/plain"); else if (!_cups_strcasecmp(ext, ".urf") || !_cups_strcasecmp(ext, ".urf.gz")) _ippVarsSet(&vars, "filetype", "image/urf"); else if (!_cups_strcasecmp(ext, ".xps")) _ippVarsSet(&vars, "filetype", "application/openxps"); else _ippVarsSet(&vars, "filetype", "application/octet-stream"); } else { /* * Use the "auto-type" MIME media type... */ _ippVarsSet(&vars, "filetype", "application/octet-stream"); } break; case 'h' : /* Validate response headers */ data.validate_headers = 1; break; case 'i' : /* Test every N seconds */ i ++; if (i >= argc) { _cupsLangPuts(stderr, _("ipptool: Missing seconds for \"-i\".")); usage(); } else { interval = (int)(_cupsStrScand(argv[i], NULL, localeconv()) * 1000000.0); if (interval <= 0) { _cupsLangPuts(stderr, _("ipptool: Invalid seconds for \"-i\".")); usage(); } } if ((data.output == _CUPS_OUTPUT_PLIST || data.output == _CUPS_OUTPUT_IPPSERVER) && interval) { _cupsLangPuts(stderr, _("ipptool: \"-i\" and \"-n\" are incompatible with \"--ippserver\", \"-P\", and \"-X\".")); usage(); } break; case 'l' : /* List as a table */ data.output = _CUPS_OUTPUT_LIST; break; case 'n' : /* Repeat count */ i ++; if (i >= argc) { _cupsLangPuts(stderr, _("ipptool: Missing count for \"-n\".")); usage(); } else repeat = atoi(argv[i]); if ((data.output == _CUPS_OUTPUT_PLIST || data.output == _CUPS_OUTPUT_IPPSERVER) && repeat) { _cupsLangPuts(stderr, _("ipptool: \"-i\" and \"-n\" are incompatible with \"--ippserver\", \"-P\", and \"-X\".")); usage(); } break; case 'q' : /* Be quiet */ data.output = _CUPS_OUTPUT_QUIET; break; case 't' : /* CUPS test output */ data.output = _CUPS_OUTPUT_TEST; break; case 'v' : /* Be verbose */ data.verbosity ++; break; default : _cupsLangPrintf(stderr, _("%s: Unknown option \"-%c\"."), "ipptool", *opt); usage(); } } } else if (!strncmp(argv[i], "ipp://", 6) || !strncmp(argv[i], "http://", 7) #ifdef HAVE_SSL || !strncmp(argv[i], "ipps://", 7) || !strncmp(argv[i], "https://", 8) #endif /* HAVE_SSL */ ) { /* * Set URI... */ if (vars.uri) { _cupsLangPuts(stderr, _("ipptool: May only specify a single URI.")); usage(); } #ifdef HAVE_SSL if (!strncmp(argv[i], "ipps://", 7) || !strncmp(argv[i], "https://", 8)) data.encryption = HTTP_ENCRYPT_ALWAYS; #endif /* HAVE_SSL */ if (!_ippVarsSet(&vars, "uri", argv[i])) { _cupsLangPrintf(stderr, _("ipptool: Bad URI \"%s\"."), argv[i]); return (1); } if (vars.username[0] && vars.password) cupsSetPasswordCB2(_ippVarsPasswordCB, &vars); } else { /* * Run test... */ if (!vars.uri) { _cupsLangPuts(stderr, _("ipptool: URI required before test file.")); _cupsLangPuts(stderr, argv[i]); usage(); } if (access(argv[i], 0) && argv[i][0] != '/' #ifdef WIN32 && (!isalpha(argv[i][0] & 255) || argv[i][1] != ':') #endif /* WIN32 */ ) { snprintf(testname, sizeof(testname), "%s/ipptool/%s", cg->cups_datadir, argv[i]); if (access(testname, 0)) testfile = argv[i]; else testfile = testname; } else testfile = argv[i]; if (!do_tests(testfile, &vars, &data)) status = 1; } } if (!vars.uri || !testfile) usage(); /* * Loop if the interval is set... */ if (data.output == _CUPS_OUTPUT_PLIST) print_xml_trailer(&data, !status, NULL); else if (interval > 0 && repeat > 0) { while (repeat > 1) { usleep((useconds_t)interval); do_tests(testfile, &vars, &data); repeat --; } } else if (interval > 0) { for (;;) { usleep((useconds_t)interval); do_tests(testfile, &vars, &data); } } if ((data.output == _CUPS_OUTPUT_TEST || (data.output == _CUPS_OUTPUT_PLIST && data.outfile)) && data.test_count > 1) { /* * Show a summary report if there were multiple tests... */ cupsFilePrintf(cupsFileStdout(), "\nSummary: %d tests, %d passed, %d failed, %d skipped\nScore: %d%%\n", data.test_count, data.pass_count, data.fail_count, data.skip_count, 100 * (data.pass_count + data.skip_count) / data.test_count); } cupsFileClose(data.outfile); /* * Exit... */ return (status); } /* * 'add_stringf()' - Add a formatted string to an array. */ static void add_stringf(cups_array_t *a, /* I - Array */ const char *s, /* I - Printf-style format string */ ...) /* I - Additional args as needed */ { char buffer[10240]; /* Format buffer */ va_list ap; /* Argument pointer */ /* * Don't bother is the array is NULL... */ if (!a) return; /* * Format the message... */ va_start(ap, s); vsnprintf(buffer, sizeof(buffer), s, ap); va_end(ap); /* * Add it to the array... */ cupsArrayAdd(a, buffer); } /* * 'compare_uris()' - Compare two URIs... */ static int /* O - Result of comparison */ compare_uris(const char *a, /* I - First URI */ const char *b) /* I - Second URI */ { char ascheme[32], /* Components of first URI */ auserpass[256], ahost[256], aresource[256]; int aport; char bscheme[32], /* Components of second URI */ buserpass[256], bhost[256], bresource[256]; int bport; char *ptr; /* Pointer into string */ int result; /* Result of comparison */ /* * Separate the URIs into their components... */ if (httpSeparateURI(HTTP_URI_CODING_ALL, a, ascheme, sizeof(ascheme), auserpass, sizeof(auserpass), ahost, sizeof(ahost), &aport, aresource, sizeof(aresource)) < HTTP_URI_STATUS_OK) return (-1); if (httpSeparateURI(HTTP_URI_CODING_ALL, b, bscheme, sizeof(bscheme), buserpass, sizeof(buserpass), bhost, sizeof(bhost), &bport, bresource, sizeof(bresource)) < HTTP_URI_STATUS_OK) return (-1); /* * Strip trailing dots from the host components, if present... */ if ((ptr = ahost + strlen(ahost) - 1) > ahost && *ptr == '.') *ptr = '\0'; if ((ptr = bhost + strlen(bhost) - 1) > bhost && *ptr == '.') *ptr = '\0'; /* * Compare each component... */ if ((result = _cups_strcasecmp(ascheme, bscheme)) != 0) return (result); if ((result = strcmp(auserpass, buserpass)) != 0) return (result); if ((result = _cups_strcasecmp(ahost, bhost)) != 0) return (result); if (aport != bport) return (aport - bport); if (!_cups_strcasecmp(ascheme, "mailto") || !_cups_strcasecmp(ascheme, "urn")) return (_cups_strcasecmp(aresource, bresource)); else return (strcmp(aresource, bresource)); } /* * 'do_test()' - Do a single test from the test file. */ static int /* O - 1 on success, 0 on failure */ do_test(_ipp_file_t *f, /* I - IPP data file */ _ipp_vars_t *vars, /* I - IPP variables */ _cups_testdata_t *data) /* I - Test data */ { int i, /* Looping var */ status_ok, /* Did we get a matching status? */ repeat_count = 0, /* Repeat count */ repeat_test; /* Repeat the test? */ _cups_expect_t *expect; /* Current expected attribute */ ipp_t *request, /* IPP request */ *response; /* IPP response */ size_t length; /* Length of IPP request */ http_status_t status; /* HTTP status */ cups_array_t *a; /* Duplicate attribute array */ ipp_tag_t group; /* Current group */ ipp_attribute_t *attrptr, /* Attribute pointer */ *found; /* Found attribute */ char temp[1024]; /* Temporary string */ cups_file_t *reqfile; /* File to send */ ssize_t bytes; /* Bytes read/written */ char buffer[131072]; /* Copy buffer */ size_t widths[200]; /* Width of columns */ const char *error; /* Current error */ if (Cancel) return (0); /* * Take over control of the attributes in the request... */ request = f->attrs; f->attrs = NULL; /* * Submit the IPP request... */ data->test_count ++; ippSetVersion(request, data->version / 10, data->version % 10); ippSetRequestId(request, data->request_id); if (data->output == _CUPS_OUTPUT_PLIST) { cupsFilePuts(data->outfile, "\n"); cupsFilePuts(data->outfile, "Name\n"); print_xml_string(data->outfile, "string", data->name); if (data->file_id[0]) { cupsFilePuts(data->outfile, "FileId\n"); print_xml_string(data->outfile, "string", data->file_id); } if (data->test_id[0]) { cupsFilePuts(data->outfile, "TestId\n"); print_xml_string(data->outfile, "string", data->test_id); } cupsFilePuts(data->outfile, "Version\n"); cupsFilePrintf(data->outfile, "%d.%d\n", data->version / 10, data->version % 10); cupsFilePuts(data->outfile, "Operation\n"); print_xml_string(data->outfile, "string", ippOpString(ippGetOperation(request))); cupsFilePuts(data->outfile, "RequestId\n"); cupsFilePrintf(data->outfile, "%d\n", data->request_id); cupsFilePuts(data->outfile, "RequestAttributes\n"); cupsFilePuts(data->outfile, "\n"); if (ippFirstAttribute(request)) { cupsFilePuts(data->outfile, "\n"); for (attrptr = ippFirstAttribute(request), group = ippGetGroupTag(attrptr); attrptr; attrptr = ippNextAttribute(request)) print_attr(data->outfile, data->output, attrptr, &group); cupsFilePuts(data->outfile, "\n"); } cupsFilePuts(data->outfile, "\n"); } if (data->output == _CUPS_OUTPUT_TEST || (data->output == _CUPS_OUTPUT_PLIST && data->outfile != cupsFileStdout())) { if (data->verbosity) { cupsFilePrintf(cupsFileStdout(), " %s:\n", ippOpString(ippGetOperation(request))); for (attrptr = ippFirstAttribute(request); attrptr; attrptr = ippNextAttribute(request)) print_attr(cupsFileStdout(), _CUPS_OUTPUT_TEST, attrptr, NULL); } cupsFilePrintf(cupsFileStdout(), " %-68.68s [", data->name); } if ((data->skip_previous && !data->prev_pass) || data->skip_test) { data->skip_count ++; ippDelete(request); request = NULL; response = NULL; if (data->output == _CUPS_OUTPUT_PLIST) { cupsFilePuts(data->outfile, "Successful\n"); cupsFilePuts(data->outfile, "\n"); cupsFilePuts(data->outfile, "Skipped\n"); cupsFilePuts(data->outfile, "\n"); cupsFilePuts(data->outfile, "StatusCode\n"); print_xml_string(data->outfile, "string", "skip"); cupsFilePuts(data->outfile, "ResponseAttributes\n"); cupsFilePuts(data->outfile, "\n"); } if (data->output == _CUPS_OUTPUT_TEST || (data->output == _CUPS_OUTPUT_PLIST && data->outfile != cupsFileStdout())) cupsFilePuts(cupsFileStdout(), "SKIP]\n"); goto skip_error; } vars->password_tries = 0; do { if (data->delay > 0) usleep(data->delay); data->delay = data->repeat_interval; repeat_count ++; status = HTTP_STATUS_OK; if (data->transfer == _CUPS_TRANSFER_CHUNKED || (data->transfer == _CUPS_TRANSFER_AUTO && data->file[0])) { /* * Send request using chunking - a 0 length means "chunk". */ length = 0; } else { /* * Send request using content length... */ length = ippLength(request); if (data->file[0] && (reqfile = cupsFileOpen(data->file, "r")) != NULL) { /* * Read the file to get the uncompressed file size... */ while ((bytes = cupsFileRead(reqfile, buffer, sizeof(buffer))) > 0) length += (size_t)bytes; cupsFileClose(reqfile); } } /* * Send the request... */ data->prev_pass = 1; repeat_test = 0; response = NULL; if (status != HTTP_STATUS_ERROR) { while (!response && !Cancel && data->prev_pass) { status = cupsSendRequest(data->http, request, data->resource, length); #ifdef HAVE_LIBZ if (data->compression[0]) httpSetField(data->http, HTTP_FIELD_CONTENT_ENCODING, data->compression); #endif /* HAVE_LIBZ */ if (!Cancel && status == HTTP_STATUS_CONTINUE && ippGetState(request) == IPP_DATA && data->file[0]) { if ((reqfile = cupsFileOpen(data->file, "r")) != NULL) { while (!Cancel && (bytes = cupsFileRead(reqfile, buffer, sizeof(buffer))) > 0) { if ((status = cupsWriteRequestData(data->http, buffer, (size_t)bytes)) != HTTP_STATUS_CONTINUE) break; } cupsFileClose(reqfile); } else { snprintf(buffer, sizeof(buffer), "%s: %s", data->file, strerror(errno)); _cupsSetError(IPP_INTERNAL_ERROR, buffer, 0); status = HTTP_STATUS_ERROR; } } /* * Get the server's response... */ if (!Cancel && status != HTTP_STATUS_ERROR) { response = cupsGetResponse(data->http, data->resource); status = httpGetStatus(data->http); } if (!Cancel && status == HTTP_STATUS_ERROR && httpError(data->http) != EINVAL && #ifdef WIN32 httpError(data->http) != WSAETIMEDOUT) #else httpError(data->http) != ETIMEDOUT) #endif /* WIN32 */ { if (httpReconnect2(data->http, 30000, NULL)) data->prev_pass = 0; } else if (status == HTTP_STATUS_ERROR || status == HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED) { data->prev_pass = 0; break; } else if (status != HTTP_STATUS_OK) { httpFlush(data->http); if (status == HTTP_STATUS_UNAUTHORIZED) continue; break; } } } if (!Cancel && status == HTTP_STATUS_ERROR && httpError(data->http) != EINVAL && #ifdef WIN32 httpError(data->http) != WSAETIMEDOUT) #else httpError(data->http) != ETIMEDOUT) #endif /* WIN32 */ { if (httpReconnect2(data->http, 30000, NULL)) data->prev_pass = 0; } else if (status == HTTP_STATUS_ERROR) { if (!Cancel) httpReconnect2(data->http, 30000, NULL); data->prev_pass = 0; } else if (status != HTTP_STATUS_OK) { httpFlush(data->http); data->prev_pass = 0; } /* * Check results of request... */ cupsArrayClear(data->errors); if (httpGetVersion(data->http) != HTTP_1_1) { int version = httpGetVersion(data->http); add_stringf(data->errors, "Bad HTTP version (%d.%d)", version / 100, version % 100); } if (data->validate_headers) { const char *header; /* HTTP header value */ if ((header = httpGetField(data->http, HTTP_FIELD_CONTENT_TYPE)) == NULL || _cups_strcasecmp(header, "application/ipp")) add_stringf(data->errors, "Bad HTTP Content-Type in response (%s)", header && *header ? header : ""); if ((header = httpGetField(data->http, HTTP_FIELD_DATE)) != NULL && *header && httpGetDateTime(header) == 0) add_stringf(data->errors, "Bad HTTP Date in response (%s)", header); } if (!response) { /* * No response, log error... */ add_stringf(data->errors, "IPP request failed with status %s (%s)", ippErrorString(cupsLastError()), cupsLastErrorString()); } else { /* * Collect common attribute values... */ if ((attrptr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL) { snprintf(temp, sizeof(temp), "%d", ippGetInteger(attrptr, 0)); _ippVarsSet(vars, "job-id", temp); } if ((attrptr = ippFindAttribute(response, "job-uri", IPP_TAG_URI)) != NULL) _ippVarsSet(vars, "job-uri", ippGetString(attrptr, 0, NULL)); if ((attrptr = ippFindAttribute(response, "notify-subscription-id", IPP_TAG_INTEGER)) != NULL) { snprintf(temp, sizeof(temp), "%d", ippGetInteger(attrptr, 0)); _ippVarsSet(vars, "notify-subscription-id", temp); } /* * Check response, validating groups and attributes and logging errors * as needed... */ if (ippGetState(response) != IPP_DATA) add_stringf(data->errors, "Missing end-of-attributes-tag in response (RFC 2910 section 3.5.1)"); if (data->version) { int major, minor; /* IPP version */ major = ippGetVersion(response, &minor); if (major != (data->version / 10) || minor != (data->version % 10)) add_stringf(data->errors, "Bad version %d.%d in response - expected %d.%d (RFC 2911 section 3.1.8).", major, minor, data->version / 10, data->version % 10); } if (ippGetRequestId(response) != data->request_id) add_stringf(data->errors, "Bad request ID %d in response - expected %d (RFC 2911 section 3.1.1)", ippGetRequestId(response), data->request_id); attrptr = ippFirstAttribute(response); if (!attrptr) { add_stringf(data->errors, "Missing first attribute \"attributes-charset (charset)\" in group operation-attributes-tag (RFC 2911 section 3.1.4)."); } else { if (!ippGetName(attrptr) || ippGetValueTag(attrptr) != IPP_TAG_CHARSET || ippGetGroupTag(attrptr) != IPP_TAG_OPERATION || ippGetCount(attrptr) != 1 ||strcmp(ippGetName(attrptr), "attributes-charset")) add_stringf(data->errors, "Bad first attribute \"%s (%s%s)\" in group %s, expected \"attributes-charset (charset)\" in group operation-attributes-tag (RFC 2911 section 3.1.4).", ippGetName(attrptr) ? ippGetName(attrptr) : "(null)", ippGetCount(attrptr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attrptr)), ippTagString(ippGetGroupTag(attrptr))); attrptr = ippNextAttribute(response); if (!attrptr) add_stringf(data->errors, "Missing second attribute \"attributes-natural-language (naturalLanguage)\" in group operation-attributes-tag (RFC 2911 section 3.1.4)."); else if (!ippGetName(attrptr) || ippGetValueTag(attrptr) != IPP_TAG_LANGUAGE || ippGetGroupTag(attrptr) != IPP_TAG_OPERATION || ippGetCount(attrptr) != 1 || strcmp(ippGetName(attrptr), "attributes-natural-language")) add_stringf(data->errors, "Bad first attribute \"%s (%s%s)\" in group %s, expected \"attributes-natural-language (naturalLanguage)\" in group operation-attributes-tag (RFC 2911 section 3.1.4).", ippGetName(attrptr) ? ippGetName(attrptr) : "(null)", ippGetCount(attrptr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attrptr)), ippTagString(ippGetGroupTag(attrptr))); } if ((attrptr = ippFindAttribute(response, "status-message", IPP_TAG_ZERO)) != NULL) { const char *status_message = ippGetString(attrptr, 0, NULL); /* String value */ if (ippGetValueTag(attrptr) != IPP_TAG_TEXT) add_stringf(data->errors, "status-message (text(255)) has wrong value tag %s (RFC 2911 section 3.1.6.2).", ippTagString(ippGetValueTag(attrptr))); if (ippGetGroupTag(attrptr) != IPP_TAG_OPERATION) add_stringf(data->errors, "status-message (text(255)) has wrong group tag %s (RFC 2911 section 3.1.6.2).", ippTagString(ippGetGroupTag(attrptr))); if (ippGetCount(attrptr) != 1) add_stringf(data->errors, "status-message (text(255)) has %d values (RFC 2911 section 3.1.6.2).", ippGetCount(attrptr)); if (status_message && strlen(status_message) > 255) add_stringf(data->errors, "status-message (text(255)) has bad length %d (RFC 2911 section 3.1.6.2).", (int)strlen(status_message)); } if ((attrptr = ippFindAttribute(response, "detailed-status-message", IPP_TAG_ZERO)) != NULL) { const char *detailed_status_message = ippGetString(attrptr, 0, NULL); /* String value */ if (ippGetValueTag(attrptr) != IPP_TAG_TEXT) add_stringf(data->errors, "detailed-status-message (text(MAX)) has wrong " "value tag %s (RFC 2911 section 3.1.6.3).", ippTagString(ippGetValueTag(attrptr))); if (ippGetGroupTag(attrptr) != IPP_TAG_OPERATION) add_stringf(data->errors, "detailed-status-message (text(MAX)) has wrong " "group tag %s (RFC 2911 section 3.1.6.3).", ippTagString(ippGetGroupTag(attrptr))); if (ippGetCount(attrptr) != 1) add_stringf(data->errors, "detailed-status-message (text(MAX)) has %d values" " (RFC 2911 section 3.1.6.3).", ippGetCount(attrptr)); if (detailed_status_message && strlen(detailed_status_message) > 1023) add_stringf(data->errors, "detailed-status-message (text(MAX)) has bad " "length %d (RFC 2911 section 3.1.6.3).", (int)strlen(detailed_status_message)); } a = cupsArrayNew((cups_array_func_t)strcmp, NULL); for (attrptr = ippFirstAttribute(response), group = ippGetGroupTag(attrptr); attrptr; attrptr = ippNextAttribute(response)) { if (ippGetGroupTag(attrptr) != group) { int out_of_order = 0; /* Are attribute groups out-of-order? */ cupsArrayClear(a); switch (ippGetGroupTag(attrptr)) { case IPP_TAG_ZERO : break; case IPP_TAG_OPERATION : out_of_order = 1; break; case IPP_TAG_UNSUPPORTED_GROUP : if (group != IPP_TAG_OPERATION) out_of_order = 1; break; case IPP_TAG_JOB : case IPP_TAG_PRINTER : if (group != IPP_TAG_OPERATION && group != IPP_TAG_UNSUPPORTED_GROUP) out_of_order = 1; break; case IPP_TAG_SUBSCRIPTION : if (group > ippGetGroupTag(attrptr) && group != IPP_TAG_DOCUMENT) out_of_order = 1; break; default : if (group > ippGetGroupTag(attrptr)) out_of_order = 1; break; } if (out_of_order) add_stringf(data->errors, "Attribute groups out of order (%s < %s)", ippTagString(ippGetGroupTag(attrptr)), ippTagString(group)); if (ippGetGroupTag(attrptr) != IPP_TAG_ZERO) group = ippGetGroupTag(attrptr); } if (!ippValidateAttribute(attrptr)) cupsArrayAdd(data->errors, (void *)cupsLastErrorString()); if (ippGetName(attrptr)) { if (cupsArrayFind(a, (void *)ippGetName(attrptr))) add_stringf(data->errors, "Duplicate \"%s\" attribute in %s group", ippGetName(attrptr), ippTagString(group)); cupsArrayAdd(a, (void *)ippGetName(attrptr)); } } cupsArrayDelete(a); /* * Now check the test-defined expected status-code and attribute * values... */ for (i = 0, status_ok = 0; i < data->num_statuses; i ++) { if (data->statuses[i].if_defined && !_ippVarsGet(vars, data->statuses[i].if_defined)) continue; if (data->statuses[i].if_not_defined && _ippVarsGet(vars, data->statuses[i].if_not_defined)) continue; if (ippGetStatusCode(response) == data->statuses[i].status) { status_ok = 1; if (data->statuses[i].repeat_match && repeat_count < data->statuses[i].repeat_limit) repeat_test = 1; if (data->statuses[i].define_match) _ippVarsSet(vars, data->statuses[i].define_match, "1"); } else { if (data->statuses[i].repeat_no_match && repeat_count < data->statuses[i].repeat_limit) repeat_test = 1; if (data->statuses[i].define_no_match) { _ippVarsSet(vars, data->statuses[i].define_no_match, "1"); status_ok = 1; } } } if (!status_ok && data->num_statuses > 0) { for (i = 0; i < data->num_statuses; i ++) { if (data->statuses[i].if_defined && !_ippVarsGet(vars, data->statuses[i].if_defined)) continue; if (data->statuses[i].if_not_defined && _ippVarsGet(vars, data->statuses[i].if_not_defined)) continue; if (!data->statuses[i].repeat_match || repeat_count >= data->statuses[i].repeat_limit) add_stringf(data->errors, "EXPECTED: STATUS %s (got %s)", ippErrorString(data->statuses[i].status), ippErrorString(cupsLastError())); } if ((attrptr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT)) != NULL) add_stringf(data->errors, "status-message=\"%s\"", ippGetString(attrptr, 0, NULL)); } for (i = data->num_expects, expect = data->expects; i > 0; i --, expect ++) { if (expect->if_defined && !_ippVarsGet(vars, expect->if_defined)) continue; if (expect->if_not_defined && _ippVarsGet(vars, expect->if_not_defined)) continue; found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO); do { if ((found && expect->not_expect) || (!found && !(expect->not_expect || expect->optional)) || (found && !expect_matches(expect, ippGetValueTag(found))) || (found && expect->in_group && ippGetGroupTag(found) != expect->in_group)) { if (expect->define_no_match) _ippVarsSet(vars, expect->define_no_match, "1"); else if (!expect->define_match && !expect->define_value) { if (found && expect->not_expect) add_stringf(data->errors, "NOT EXPECTED: %s", expect->name); else if (!found && !(expect->not_expect || expect->optional)) add_stringf(data->errors, "EXPECTED: %s", expect->name); else if (found) { if (!expect_matches(expect, ippGetValueTag(found))) add_stringf(data->errors, "EXPECTED: %s OF-TYPE %s (got %s)", expect->name, expect->of_type, ippTagString(ippGetValueTag(found))); if (expect->in_group && ippGetGroupTag(found) != expect->in_group) add_stringf(data->errors, "EXPECTED: %s IN-GROUP %s (got %s).", expect->name, ippTagString(expect->in_group), ippTagString(ippGetGroupTag(found))); } } if (expect->repeat_no_match && repeat_count < expect->repeat_limit) repeat_test = 1; break; } if (found) ippAttributeString(found, buffer, sizeof(buffer)); if (found && expect->with_value_from && !with_value_from(NULL, ippFindAttribute(response, expect->with_value_from, IPP_TAG_ZERO), found, buffer, sizeof(buffer))) { if (expect->define_no_match) _ippVarsSet(vars, expect->define_no_match, "1"); else if (!expect->define_match && !expect->define_value && ((!expect->repeat_match && !expect->repeat_no_match) || repeat_count >= expect->repeat_limit)) { add_stringf(data->errors, "EXPECTED: %s WITH-VALUES-FROM %s", expect->name, expect->with_value_from); with_value_from(data->errors, ippFindAttribute(response, expect->with_value_from, IPP_TAG_ZERO), found, buffer, sizeof(buffer)); } if (expect->repeat_no_match && repeat_count < expect->repeat_limit) repeat_test = 1; break; } else if (found && !with_value(data, NULL, expect->with_value, expect->with_flags, found, buffer, sizeof(buffer))) { if (expect->define_no_match) _ippVarsSet(vars, expect->define_no_match, "1"); else if (!expect->define_match && !expect->define_value && !expect->repeat_match && (!expect->repeat_no_match || repeat_count >= expect->repeat_limit)) { if (expect->with_flags & _CUPS_WITH_REGEX) add_stringf(data->errors, "EXPECTED: %s %s /%s/", expect->name, with_flags_string(expect->with_flags), expect->with_value); else add_stringf(data->errors, "EXPECTED: %s %s \"%s\"", expect->name, with_flags_string(expect->with_flags), expect->with_value); with_value(data, data->errors, expect->with_value, expect->with_flags, found, buffer, sizeof(buffer)); } if (expect->repeat_no_match && repeat_count < expect->repeat_limit) repeat_test = 1; break; } if (found && expect->count > 0 && ippGetCount(found) != expect->count) { if (expect->define_no_match) _ippVarsSet(vars, expect->define_no_match, "1"); else if (!expect->define_match && !expect->define_value) { add_stringf(data->errors, "EXPECTED: %s COUNT %d (got %d)", expect->name, expect->count, ippGetCount(found)); } if (expect->repeat_no_match && repeat_count < expect->repeat_limit) repeat_test = 1; break; } if (found && expect->same_count_as) { attrptr = ippFindAttribute(response, expect->same_count_as, IPP_TAG_ZERO); if (!attrptr || ippGetCount(attrptr) != ippGetCount(found)) { if (expect->define_no_match) _ippVarsSet(vars, expect->define_no_match, "1"); else if (!expect->define_match && !expect->define_value) { if (!attrptr) add_stringf(data->errors, "EXPECTED: %s (%d values) SAME-COUNT-AS %s " "(not returned)", expect->name, ippGetCount(found), expect->same_count_as); else if (ippGetCount(attrptr) != ippGetCount(found)) add_stringf(data->errors, "EXPECTED: %s (%d values) SAME-COUNT-AS %s " "(%d values)", expect->name, ippGetCount(found), expect->same_count_as, ippGetCount(attrptr)); } if (expect->repeat_no_match && repeat_count < expect->repeat_limit) repeat_test = 1; break; } } if (found && expect->define_match) _ippVarsSet(vars, expect->define_match, "1"); if (found && expect->define_value) { if (!expect->with_value) { int last = ippGetCount(found) - 1; /* Last element in attribute */ switch (ippGetValueTag(found)) { case IPP_TAG_ENUM : case IPP_TAG_INTEGER : snprintf(buffer, sizeof(buffer), "%d", ippGetInteger(found, last)); break; case IPP_TAG_BOOLEAN : if (ippGetBoolean(found, last)) strlcpy(buffer, "true", sizeof(buffer)); else strlcpy(buffer, "false", sizeof(buffer)); break; case IPP_TAG_RESOLUTION : { int xres, /* Horizontal resolution */ yres; /* Vertical resolution */ ipp_res_t units; /* Resolution units */ xres = ippGetResolution(found, last, &yres, &units); if (xres == yres) snprintf(buffer, sizeof(buffer), "%d%s", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); else snprintf(buffer, sizeof(buffer), "%dx%d%s", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); } break; case IPP_TAG_CHARSET : case IPP_TAG_KEYWORD : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : case IPP_TAG_NAME : case IPP_TAG_NAMELANG : case IPP_TAG_TEXT : case IPP_TAG_TEXTLANG : case IPP_TAG_URI : case IPP_TAG_URISCHEME : strlcpy(buffer, ippGetString(found, last, NULL), sizeof(buffer)); break; default : ippAttributeString(found, buffer, sizeof(buffer)); break; } } _ippVarsSet(vars, expect->define_value, buffer); } if (found && expect->repeat_match && repeat_count < expect->repeat_limit) repeat_test = 1; } while (expect->expect_all && (found = ippFindNextAttribute(response, expect->name, IPP_TAG_ZERO)) != NULL); } } /* * If we are going to repeat this test, display intermediate results... */ if (repeat_test) { if (data->output == _CUPS_OUTPUT_TEST || (data->output == _CUPS_OUTPUT_PLIST && data->outfile != cupsFileStdout())) { cupsFilePrintf(cupsFileStdout(), "%04d]\n", repeat_count); \ if (data->num_displayed > 0) { for (attrptr = ippFirstAttribute(response); attrptr; attrptr = ippNextAttribute(response)) { const char *attrname = ippGetName(attrptr); if (attrname) { for (i = 0; i < data->num_displayed; i ++) { if (!strcmp(data->displayed[i], attrname)) { print_attr(cupsFileStdout(), _CUPS_OUTPUT_TEST, attrptr, NULL); break; } } } } } } if (data->output == _CUPS_OUTPUT_TEST || (data->output == _CUPS_OUTPUT_PLIST && data->outfile != cupsFileStdout())) { cupsFilePrintf(cupsFileStdout(), " %-68.68s [", data->name); } ippDelete(response); response = NULL; } } while (repeat_test); ippDelete(request); request = NULL; if (cupsArrayCount(data->errors) > 0) data->prev_pass = data->pass = 0; if (data->prev_pass) data->pass_count ++; else data->fail_count ++; if (data->output == _CUPS_OUTPUT_PLIST) { cupsFilePuts(data->outfile, "Successful\n"); cupsFilePuts(data->outfile, data->prev_pass ? "\n" : "\n"); cupsFilePuts(data->outfile, "StatusCode\n"); print_xml_string(data->outfile, "string", ippErrorString(cupsLastError())); cupsFilePuts(data->outfile, "ResponseAttributes\n"); cupsFilePuts(data->outfile, "\n"); cupsFilePuts(data->outfile, "\n"); for (attrptr = ippFirstAttribute(response), group = ippGetGroupTag(attrptr); attrptr; attrptr = ippNextAttribute(response)) print_attr(data->outfile, data->output, attrptr, &group); cupsFilePuts(data->outfile, "\n"); cupsFilePuts(data->outfile, "\n"); } else if (data->output == _CUPS_OUTPUT_IPPSERVER && response) { for (attrptr = ippFirstAttribute(response); attrptr; attrptr = ippNextAttribute(response)) { if (!ippGetName(attrptr) || ippGetGroupTag(attrptr) != IPP_TAG_PRINTER) continue; print_ippserver_attr(data, attrptr, 0); } } if (data->output == _CUPS_OUTPUT_TEST || (data->output == _CUPS_OUTPUT_PLIST && data->outfile != cupsFileStdout())) { cupsFilePuts(cupsFileStdout(), data->prev_pass ? "PASS]\n" : "FAIL]\n"); if (!data->prev_pass || (data->verbosity && response)) { cupsFilePrintf(cupsFileStdout(), " RECEIVED: %lu bytes in response\n", (unsigned long)ippLength(response)); cupsFilePrintf(cupsFileStdout(), " status-code = %s (%s)\n", ippErrorString(cupsLastError()), cupsLastErrorString()); if (data->verbosity && response) { for (attrptr = ippFirstAttribute(response); attrptr; attrptr = ippNextAttribute(response)) print_attr(cupsFileStdout(), _CUPS_OUTPUT_TEST, attrptr, NULL); } } } else if (!data->prev_pass && data->output != _CUPS_OUTPUT_QUIET) fprintf(stderr, "%s\n", cupsLastErrorString()); if (data->prev_pass && data->output >= _CUPS_OUTPUT_LIST && !data->verbosity && data->num_displayed > 0) { size_t width; /* Length of value */ for (i = 0; i < data->num_displayed; i ++) { widths[i] = strlen(data->displayed[i]); for (attrptr = ippFindAttribute(response, data->displayed[i], IPP_TAG_ZERO); attrptr; attrptr = ippFindNextAttribute(response, data->displayed[i], IPP_TAG_ZERO)) { width = ippAttributeString(attrptr, NULL, 0); if (width > widths[i]) widths[i] = width; } } if (data->output == _CUPS_OUTPUT_CSV) print_csv(data, NULL, NULL, data->num_displayed, data->displayed, widths); else print_line(data, NULL, NULL, data->num_displayed, data->displayed, widths); attrptr = ippFirstAttribute(response); while (attrptr) { while (attrptr && ippGetGroupTag(attrptr) <= IPP_TAG_OPERATION) attrptr = ippNextAttribute(response); if (attrptr) { if (data->output == _CUPS_OUTPUT_CSV) print_csv(data, response, attrptr, data->num_displayed, data->displayed, widths); else print_line(data, response, attrptr, data->num_displayed, data->displayed, widths); while (attrptr && ippGetGroupTag(attrptr) > IPP_TAG_OPERATION) attrptr = ippNextAttribute(response); } } } else if (!data->prev_pass) { if (data->output == _CUPS_OUTPUT_PLIST) { cupsFilePuts(data->outfile, "Errors\n"); cupsFilePuts(data->outfile, "\n"); for (error = (char *)cupsArrayFirst(data->errors); error; error = (char *)cupsArrayNext(data->errors)) print_xml_string(data->outfile, "string", error); cupsFilePuts(data->outfile, "\n"); } if (data->output == _CUPS_OUTPUT_TEST || (data->output == _CUPS_OUTPUT_PLIST && data->outfile != cupsFileStdout())) { for (error = (char *)cupsArrayFirst(data->errors); error; error = (char *)cupsArrayNext(data->errors)) cupsFilePrintf(cupsFileStdout(), " %s\n", error); } } if (data->num_displayed > 0 && !data->verbosity && response && (data->output == _CUPS_OUTPUT_TEST || (data->output == _CUPS_OUTPUT_PLIST && data->outfile != cupsFileStdout()))) { for (attrptr = ippFirstAttribute(response); attrptr; attrptr = ippNextAttribute(response)) { if (ippGetName(attrptr)) { for (i = 0; i < data->num_displayed; i ++) { if (!strcmp(data->displayed[i], ippGetName(attrptr))) { print_attr(data->outfile, data->output, attrptr, NULL); break; } } } } } skip_error: if (data->output == _CUPS_OUTPUT_PLIST) cupsFilePuts(data->outfile, "\n"); ippDelete(response); response = NULL; for (i = 0; i < data->num_statuses; i ++) { if (data->statuses[i].if_defined) free(data->statuses[i].if_defined); if (data->statuses[i].if_not_defined) free(data->statuses[i].if_not_defined); if (data->statuses[i].define_match) free(data->statuses[i].define_match); if (data->statuses[i].define_no_match) free(data->statuses[i].define_no_match); } data->num_statuses = 0; for (i = data->num_expects, expect = data->expects; i > 0; i --, expect ++) { free(expect->name); if (expect->of_type) free(expect->of_type); if (expect->same_count_as) free(expect->same_count_as); if (expect->if_defined) free(expect->if_defined); if (expect->if_not_defined) free(expect->if_not_defined); if (expect->with_value) free(expect->with_value); if (expect->define_match) free(expect->define_match); if (expect->define_no_match) free(expect->define_no_match); if (expect->define_value) free(expect->define_value); } data->num_expects = 0; for (i = 0; i < data->num_displayed; i ++) free(data->displayed[i]); data->num_displayed = 0; return (data->ignore_errors || data->prev_pass); } /* * 'do_tests()' - Do tests as specified in the test file. */ static int /* O - 1 on success, 0 on failure */ do_tests(const char *testfile, /* I - Test file to use */ _ipp_vars_t *vars, /* I - Variables */ _cups_testdata_t *data) /* I - Test data */ { http_encryption_t encryption; /* Encryption mode */ /* * Connect to the printer/server... */ if (!_cups_strcasecmp(vars->scheme, "https") || !_cups_strcasecmp(vars->scheme, "ipps")) encryption = HTTP_ENCRYPTION_ALWAYS; else encryption = data->encryption; if ((data->http = httpConnect2(vars->host, vars->port, NULL, data->family, encryption, 1, 30000, NULL)) == NULL) { print_fatal_error(data, "Unable to connect to \"%s\" on port %d - %s", vars->host, vars->port, cupsLastErrorString()); return (0); } #ifdef HAVE_LIBZ httpSetDefaultField(data->http, HTTP_FIELD_ACCEPT_ENCODING, "deflate, gzip, identity"); #else httpSetDefaultField(data->http, HTTP_FIELD_ACCEPT_ENCODING, "identity"); #endif /* HAVE_LIBZ */ if (data->timeout > 0.0) httpSetTimeout(data->http, data->timeout, timeout_cb, NULL); /* * Run tests... */ _ippFileParse(vars, testfile, (void *)data); /* * Close connection and return... */ httpClose(data->http); data->http = NULL; return (data->pass); } /* * 'error_cb()' - Print/add an error message. */ static int /* O - 1 to continue, 0 to stop */ error_cb(_ipp_file_t *f, /* I - IPP file data */ _cups_testdata_t *data, /* I - Test data */ const char *error) /* I - Error message */ { (void)f; print_fatal_error(data, "%s", error); return (1); } /* * 'expect_matches()' - Return true if the tag matches the specification. */ static int /* O - 1 if matches, 0 otherwise */ expect_matches( _cups_expect_t *expect, /* I - Expected attribute */ ipp_tag_t value_tag) /* I - Value tag for attribute */ { int match; /* Match? */ char *of_type, /* Type name to match */ *next, /* Next name to match */ sep; /* Separator character */ /* * If we don't expect a particular type, return immediately... */ if (!expect->of_type) return (1); /* * Parse the "of_type" value since the string can contain multiple attribute * types separated by "," or "|"... */ for (of_type = expect->of_type, match = 0; !match && *of_type; of_type = next) { /* * Find the next separator, and set it (temporarily) to nul if present. */ for (next = of_type; *next && *next != '|' && *next != ','; next ++); if ((sep = *next) != '\0') *next = '\0'; /* * Support some meta-types to make it easier to write the test file. */ if (!strcmp(of_type, "text")) match = value_tag == IPP_TAG_TEXTLANG || value_tag == IPP_TAG_TEXT; else if (!strcmp(of_type, "name")) match = value_tag == IPP_TAG_NAMELANG || value_tag == IPP_TAG_NAME; else if (!strcmp(of_type, "collection")) match = value_tag == IPP_TAG_BEGIN_COLLECTION; else match = value_tag == ippTagValue(of_type); /* * Restore the separator if we have one... */ if (sep) *next++ = sep; } return (match); } /* * 'get_filename()' - Get a filename based on the current test file. */ static char * /* O - Filename */ get_filename(const char *testfile, /* I - Current test file */ char *dst, /* I - Destination filename */ const char *src, /* I - Source filename */ size_t dstsize) /* I - Size of destination buffer */ { char *dstptr; /* Pointer into destination */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ if (*src == '<' && src[strlen(src) - 1] == '>') { /* * Map to CUPS_DATADIR/ipptool/filename... */ snprintf(dst, dstsize, "%s/ipptool/%s", cg->cups_datadir, src + 1); dstptr = dst + strlen(dst) - 1; if (*dstptr == '>') *dstptr = '\0'; } else if (!access(src, R_OK) || *src == '/' #ifdef WIN32 || (isalpha(*src & 255) && src[1] == ':') #endif /* WIN32 */ ) { /* * Use the path as-is... */ strlcpy(dst, src, dstsize); } else { /* * Make path relative to testfile... */ strlcpy(dst, testfile, dstsize); if ((dstptr = strrchr(dst, '/')) != NULL) dstptr ++; else dstptr = dst; /* Should never happen */ strlcpy(dstptr, src, dstsize - (size_t)(dstptr - dst)); } return (dst); } /* * 'get_string()' - Get a pointer to a string value or the portion of interest. */ static const char * /* O - Pointer to string */ get_string(ipp_attribute_t *attr, /* I - IPP attribute */ int element, /* I - Element to fetch */ int flags, /* I - Value ("with") flags */ char *buffer, /* I - Temporary buffer */ size_t bufsize) /* I - Size of temporary buffer */ { const char *value; /* Value */ char *ptr, /* Pointer into value */ scheme[256], /* URI scheme */ userpass[256], /* Username/password */ hostname[256], /* Hostname */ resource[1024]; /* Resource */ int port; /* Port number */ value = ippGetString(attr, element, NULL); if (flags & _CUPS_WITH_HOSTNAME) { if (httpSeparateURI(HTTP_URI_CODING_ALL, value, scheme, sizeof(scheme), userpass, sizeof(userpass), buffer, (int)bufsize, &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) buffer[0] = '\0'; ptr = buffer + strlen(buffer) - 1; if (ptr >= buffer && *ptr == '.') *ptr = '\0'; /* Drop trailing "." */ return (buffer); } else if (flags & _CUPS_WITH_RESOURCE) { if (httpSeparateURI(HTTP_URI_CODING_ALL, value, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, buffer, (int)bufsize) < HTTP_URI_STATUS_OK) buffer[0] = '\0'; return (buffer); } else if (flags & _CUPS_WITH_SCHEME) { if (httpSeparateURI(HTTP_URI_CODING_ALL, value, buffer, (int)bufsize, userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) buffer[0] = '\0'; return (buffer); } else if (ippGetValueTag(attr) == IPP_TAG_URI && (!strncmp(value, "ipp://", 6) || !strncmp(value, "http://", 7) || !strncmp(value, "ipps://", 7) || !strncmp(value, "https://", 8))) { http_uri_status_t status = httpSeparateURI(HTTP_URI_CODING_ALL, value, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)); if (status < HTTP_URI_STATUS_OK) { /* * Bad URI... */ buffer[0] = '\0'; } else { /* * Normalize URI with no trailing dot... */ if ((ptr = hostname + strlen(hostname) - 1) >= hostname && *ptr == '.') *ptr = '\0'; httpAssembleURI(HTTP_URI_CODING_ALL, buffer, (int)bufsize, scheme, userpass, hostname, port, resource); } return (buffer); } else return (value); } /* * 'init_data()' - Initialize test data. */ static void init_data(_cups_testdata_t *data) /* I - Data */ { memset(data, 0, sizeof(_cups_testdata_t)); data->output = _CUPS_OUTPUT_LIST; data->outfile = cupsFileStdout(); data->family = AF_UNSPEC; data->def_transfer = _CUPS_TRANSFER_AUTO; data->def_version = 11; data->errors = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); data->pass = 1; data->prev_pass = 1; data->request_id = (CUPS_RAND() % 1000) * 137 + 1; data->show_header = 1; } /* * 'iso_date()' - Return an ISO 8601 date/time string for the given IPP dateTime * value. */ static char * /* O - ISO 8601 date/time string */ iso_date(const ipp_uchar_t *date) /* I - IPP (RFC 1903) date/time value */ { time_t utctime; /* UTC time since 1970 */ struct tm *utcdate; /* UTC date/time */ static char buffer[255]; /* String buffer */ utctime = ippDateToTime(date); utcdate = gmtime(&utctime); snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02dZ", utcdate->tm_year + 1900, utcdate->tm_mon + 1, utcdate->tm_mday, utcdate->tm_hour, utcdate->tm_min, utcdate->tm_sec); return (buffer); } /* * 'pause_message()' - Display the message and pause until the user presses a key. */ static void pause_message(const char *message) /* I - Message */ { #ifdef WIN32 HANDLE tty; /* Console handle */ DWORD mode; /* Console mode */ char key; /* Key press */ DWORD bytes; /* Bytes read for key press */ /* * Disable input echo and set raw input... */ if ((tty = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) return; if (!GetConsoleMode(tty, &mode)) return; if (!SetConsoleMode(tty, 0)) return; #else int tty; /* /dev/tty - never read from stdin */ struct termios original, /* Original input mode */ noecho; /* No echo input mode */ char key; /* Current key press */ /* * Disable input echo and set raw input... */ if ((tty = open("/dev/tty", O_RDONLY)) < 0) return; if (tcgetattr(tty, &original)) { close(tty); return; } noecho = original; noecho.c_lflag &= (tcflag_t)~(ICANON | ECHO | ECHOE | ISIG); if (tcsetattr(tty, TCSAFLUSH, &noecho)) { close(tty); return; } #endif /* WIN32 */ /* * Display the prompt... */ cupsFilePrintf(cupsFileStdout(), "%s\n---- PRESS ANY KEY ----", message); #ifdef WIN32 /* * Read a key... */ ReadFile(tty, &key, 1, &bytes, NULL); /* * Cleanup... */ SetConsoleMode(tty, mode); #else /* * Read a key... */ read(tty, &key, 1); /* * Cleanup... */ tcsetattr(tty, TCSAFLUSH, &original); close(tty); #endif /* WIN32 */ /* * Erase the "press any key" prompt... */ cupsFilePuts(cupsFileStdout(), "\r \r"); } /* * 'print_attr()' - Print an attribute on the screen. */ static void print_attr(cups_file_t *outfile, /* I - Output file */ int output, /* I - Output format */ ipp_attribute_t *attr, /* I - Attribute to print */ ipp_tag_t *group) /* IO - Current group */ { int i, /* Looping var */ count; /* Number of values */ ipp_attribute_t *colattr; /* Collection attribute */ if (output == _CUPS_OUTPUT_PLIST) { if (!ippGetName(attr) || (group && *group != ippGetGroupTag(attr))) { if (ippGetGroupTag(attr) != IPP_TAG_ZERO) { cupsFilePuts(outfile, "\n"); cupsFilePuts(outfile, "\n"); } if (group) *group = ippGetGroupTag(attr); } if (!ippGetName(attr)) return; print_xml_string(outfile, "key", ippGetName(attr)); if ((count = ippGetCount(attr)) > 1) cupsFilePuts(outfile, "\n"); switch (ippGetValueTag(attr)) { case IPP_TAG_INTEGER : case IPP_TAG_ENUM : for (i = 0; i < count; i ++) cupsFilePrintf(outfile, "%d\n", ippGetInteger(attr, i)); break; case IPP_TAG_BOOLEAN : for (i = 0; i < count; i ++) cupsFilePuts(outfile, ippGetBoolean(attr, i) ? "\n" : "\n"); break; case IPP_TAG_RANGE : for (i = 0; i < count; i ++) { int lower, upper; /* Lower and upper ranges */ lower = ippGetRange(attr, i, &upper); cupsFilePrintf(outfile, "lower%dupper%d\n", lower, upper); } break; case IPP_TAG_RESOLUTION : for (i = 0; i < count; i ++) { int xres, yres; /* Resolution values */ ipp_res_t units; /* Resolution units */ xres = ippGetResolution(attr, i, &yres, &units); cupsFilePrintf(outfile, "xres%dyres%dunits%s\n", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); } break; case IPP_TAG_DATE : for (i = 0; i < count; i ++) cupsFilePrintf(outfile, "%s\n", iso_date(ippGetDate(attr, i))); break; case IPP_TAG_STRING : for (i = 0; i < count; i ++) { int datalen; /* Length of data */ void *data = ippGetOctetString(attr, i, &datalen); /* Data */ char buffer[IPP_MAX_LENGTH * 5 / 4 + 1]; /* Base64 output buffer */ cupsFilePrintf(outfile, "%s\n", httpEncode64_2(buffer, sizeof(buffer), data, datalen)); } break; case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : for (i = 0; i < count; i ++) print_xml_string(outfile, "string", ippGetString(attr, i, NULL)); break; case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : for (i = 0; i < count; i ++) { const char *s, /* String */ *lang; /* Language */ s = ippGetString(attr, i, &lang); cupsFilePuts(outfile, "language"); print_xml_string(outfile, NULL, lang); cupsFilePuts(outfile, "string"); print_xml_string(outfile, NULL, s); cupsFilePuts(outfile, "\n"); } break; case IPP_TAG_BEGIN_COLLECTION : for (i = 0; i < count; i ++) { ipp_t *col = ippGetCollection(attr, i); /* Collection value */ cupsFilePuts(outfile, "\n"); for (colattr = ippFirstAttribute(col); colattr; colattr = ippNextAttribute(col)) print_attr(outfile, output, colattr, NULL); cupsFilePuts(outfile, "\n"); } break; default : cupsFilePrintf(outfile, "<<%s>>\n", ippTagString(ippGetValueTag(attr))); break; } if (count > 1) cupsFilePuts(outfile, "\n"); } else { char buffer[131072]; /* Value buffer */ if (output == _CUPS_OUTPUT_TEST) { if (!ippGetName(attr)) { cupsFilePuts(outfile, " -- separator --\n"); return; } cupsFilePrintf(outfile, " %s (%s%s) = ", ippGetName(attr), ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr))); } ippAttributeString(attr, buffer, sizeof(buffer)); cupsFilePrintf(outfile, "%s\n", buffer); } } /* * 'print_csv()' - Print a line of CSV text. */ static void print_csv( _cups_testdata_t *data, /* I - Test data */ ipp_t *ipp, /* I - Response message */ ipp_attribute_t *attr, /* I - First attribute for line */ int num_displayed, /* I - Number of attributes to display */ char **displayed, /* I - Attributes to display */ size_t *widths) /* I - Column widths */ { int i; /* Looping var */ size_t maxlength; /* Max length of all columns */ char *buffer, /* String buffer */ *bufptr; /* Pointer into buffer */ ipp_attribute_t *current; /* Current attribute */ /* * Get the maximum string length we have to show and allocate... */ for (i = 1, maxlength = widths[0]; i < num_displayed; i ++) if (widths[i] > maxlength) maxlength = widths[i]; maxlength += 2; if ((buffer = malloc(maxlength)) == NULL) return; /* * Loop through the attributes to display... */ if (attr) { for (i = 0; i < num_displayed; i ++) { if (i) cupsFilePutChar(data->outfile, ','); buffer[0] = '\0'; for (current = attr; current; current = ippNextAttribute(ipp)) { if (!ippGetName(current)) break; else if (!strcmp(ippGetName(current), displayed[i])) { ippAttributeString(current, buffer, maxlength); break; } } if (strchr(buffer, ',') != NULL || strchr(buffer, '\"') != NULL || strchr(buffer, '\\') != NULL) { cupsFilePutChar(cupsFileStdout(), '\"'); for (bufptr = buffer; *bufptr; bufptr ++) { if (*bufptr == '\\' || *bufptr == '\"') cupsFilePutChar(cupsFileStdout(), '\\'); cupsFilePutChar(cupsFileStdout(), *bufptr); } cupsFilePutChar(cupsFileStdout(), '\"'); } else cupsFilePuts(data->outfile, buffer); } cupsFilePutChar(cupsFileStdout(), '\n'); } else { for (i = 0; i < num_displayed; i ++) { if (i) cupsFilePutChar(cupsFileStdout(), ','); cupsFilePuts(data->outfile, displayed[i]); } cupsFilePutChar(cupsFileStdout(), '\n'); } free(buffer); } /* * 'print_fatal_error()' - Print a fatal error message. */ static void print_fatal_error( _cups_testdata_t *data, /* I - Test data */ const char *s, /* I - Printf-style format string */ ...) /* I - Additional arguments as needed */ { char buffer[10240]; /* Format buffer */ va_list ap; /* Pointer to arguments */ /* * Format the error message... */ va_start(ap, s); vsnprintf(buffer, sizeof(buffer), s, ap); va_end(ap); /* * Then output it... */ if (data->output == _CUPS_OUTPUT_PLIST) { print_xml_header(data); print_xml_trailer(data, 0, buffer); } _cupsLangPrintf(stderr, "ipptool: %s", buffer); } /* * 'print_ippserver_attr()' - Print a attribute suitable for use by ippserver. */ static void print_ippserver_attr( _cups_testdata_t *data, /* I - Test data */ ipp_attribute_t *attr, /* I - Attribute to print */ int indent) /* I - Indentation level */ { int i, /* Looping var */ count = ippGetCount(attr); /* Number of values */ ipp_attribute_t *colattr; /* Collection attribute */ if (indent == 0) cupsFilePrintf(data->outfile, "ATTR %s %s", ippTagString(ippGetValueTag(attr)), ippGetName(attr)); else cupsFilePrintf(data->outfile, "%*sMEMBER %s %s", indent, "", ippTagString(ippGetValueTag(attr)), ippGetName(attr)); switch (ippGetValueTag(attr)) { case IPP_TAG_INTEGER : case IPP_TAG_ENUM : for (i = 0; i < count; i ++) cupsFilePrintf(data->outfile, "%s%d", i ? "," : " ", ippGetInteger(attr, i)); break; case IPP_TAG_BOOLEAN : cupsFilePuts(data->outfile, ippGetBoolean(attr, 0) ? " true" : " false"); for (i = 1; i < count; i ++) cupsFilePuts(data->outfile, ippGetBoolean(attr, 1) ? ",true" : ",false"); break; case IPP_TAG_RANGE : for (i = 0; i < count; i ++) { int upper, lower = ippGetRange(attr, i, &upper); cupsFilePrintf(data->outfile, "%s%d-%d", i ? "," : " ", lower, upper); } break; case IPP_TAG_RESOLUTION : for (i = 0; i < count; i ++) { ipp_res_t units; int yres, xres = ippGetResolution(attr, i, &yres, &units); cupsFilePrintf(data->outfile, "%s%dx%d%s", i ? "," : " ", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); } break; case IPP_TAG_DATE : for (i = 0; i < count; i ++) cupsFilePrintf(data->outfile, "%s%s", i ? "," : " ", iso_date(ippGetDate(attr, i))); break; case IPP_TAG_STRING : for (i = 0; i < count; i ++) { int len; const char *s = (const char *)ippGetOctetString(attr, i, &len); cupsFilePuts(data->outfile, i ? "," : " "); print_ippserver_string(data, s, (size_t)len); } break; case IPP_TAG_TEXT : case IPP_TAG_TEXTLANG : case IPP_TAG_NAME : case IPP_TAG_NAMELANG : case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : for (i = 0; i < count; i ++) { const char *s = ippGetString(attr, i, NULL); cupsFilePuts(data->outfile, i ? "," : " "); print_ippserver_string(data, s, strlen(s)); } break; case IPP_TAG_BEGIN_COLLECTION : for (i = 0; i < count; i ++) { ipp_t *col = ippGetCollection(attr, i); cupsFilePuts(data->outfile, i ? ",{\n" : " {\n"); for (colattr = ippFirstAttribute(col); colattr; colattr = ippNextAttribute(col)) print_ippserver_attr(data, colattr, indent + 4); cupsFilePrintf(data->outfile, "%*s}", indent, ""); } break; default : cupsFilePuts(data->outfile, " \"\""); break; } cupsFilePuts(data->outfile, "\n"); } /* * 'print_ippserver_string()' - Print a string suitable for use by ippserver. */ static void print_ippserver_string( _cups_testdata_t *data, /* I - Test data */ const char *s, /* I - String to print */ size_t len) /* I - Length of string */ { cupsFilePutChar(data->outfile, '\"'); while (len > 0) { if (*s == '\"') cupsFilePutChar(data->outfile, '\\'); cupsFilePutChar(data->outfile, *s); s ++; len --; } cupsFilePutChar(data->outfile, '\"'); } /* * 'print_line()' - Print a line of formatted or CSV text. */ static void print_line( _cups_testdata_t *data, /* I - Test data */ ipp_t *ipp, /* I - Response message */ ipp_attribute_t *attr, /* I - First attribute for line */ int num_displayed, /* I - Number of attributes to display */ char **displayed, /* I - Attributes to display */ size_t *widths) /* I - Column widths */ { int i; /* Looping var */ size_t maxlength; /* Max length of all columns */ char *buffer; /* String buffer */ ipp_attribute_t *current; /* Current attribute */ /* * Get the maximum string length we have to show and allocate... */ for (i = 1, maxlength = widths[0]; i < num_displayed; i ++) if (widths[i] > maxlength) maxlength = widths[i]; maxlength += 2; if ((buffer = malloc(maxlength)) == NULL) return; /* * Loop through the attributes to display... */ if (attr) { for (i = 0; i < num_displayed; i ++) { if (i) cupsFilePutChar(cupsFileStdout(), ' '); buffer[0] = '\0'; for (current = attr; current; current = ippNextAttribute(ipp)) { if (!ippGetName(current)) break; else if (!strcmp(ippGetName(current), displayed[i])) { ippAttributeString(current, buffer, maxlength); break; } } cupsFilePrintf(data->outfile, "%*s", (int)-widths[i], buffer); } cupsFilePutChar(cupsFileStdout(), '\n'); } else { for (i = 0; i < num_displayed; i ++) { if (i) cupsFilePutChar(cupsFileStdout(), ' '); cupsFilePrintf(data->outfile, "%*s", (int)-widths[i], displayed[i]); } cupsFilePutChar(cupsFileStdout(), '\n'); for (i = 0; i < num_displayed; i ++) { if (i) cupsFilePutChar(cupsFileStdout(), ' '); memset(buffer, '-', widths[i]); buffer[widths[i]] = '\0'; cupsFilePuts(data->outfile, buffer); } cupsFilePutChar(cupsFileStdout(), '\n'); } free(buffer); } /* * 'print_xml_header()' - Print a standard XML plist header. */ static void print_xml_header(_cups_testdata_t *data)/* I - Test data */ { if (!data->xml_header) { cupsFilePuts(data->outfile, "\n"); cupsFilePuts(data->outfile, "\n"); cupsFilePuts(data->outfile, "\n"); cupsFilePuts(data->outfile, "\n"); cupsFilePuts(data->outfile, "ipptoolVersion\n"); cupsFilePuts(data->outfile, "" CUPS_SVERSION "\n"); cupsFilePuts(data->outfile, "Transfer\n"); cupsFilePrintf(data->outfile, "%s\n", data->transfer == _CUPS_TRANSFER_AUTO ? "auto" : data->transfer == _CUPS_TRANSFER_CHUNKED ? "chunked" : "length"); cupsFilePuts(data->outfile, "Tests\n"); cupsFilePuts(data->outfile, "\n"); data->xml_header = 1; } } /* * 'print_xml_string()' - Print an XML string with escaping. */ static void print_xml_string(cups_file_t *outfile, /* I - Test data */ const char *element, /* I - Element name or NULL */ const char *s) /* I - String to print */ { if (element) cupsFilePrintf(outfile, "<%s>", element); while (*s) { if (*s == '&') cupsFilePuts(outfile, "&"); else if (*s == '<') cupsFilePuts(outfile, "<"); else if (*s == '>') cupsFilePuts(outfile, ">"); else if ((*s & 0xe0) == 0xc0) { /* * Validate UTF-8 two-byte sequence... */ if ((s[1] & 0xc0) != 0x80) { cupsFilePutChar(outfile, '?'); s ++; } else { cupsFilePutChar(outfile, *s++); cupsFilePutChar(outfile, *s); } } else if ((*s & 0xf0) == 0xe0) { /* * Validate UTF-8 three-byte sequence... */ if ((s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80) { cupsFilePutChar(outfile, '?'); s += 2; } else { cupsFilePutChar(outfile, *s++); cupsFilePutChar(outfile, *s++); cupsFilePutChar(outfile, *s); } } else if ((*s & 0xf8) == 0xf0) { /* * Validate UTF-8 four-byte sequence... */ if ((s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 || (s[3] & 0xc0) != 0x80) { cupsFilePutChar(outfile, '?'); s += 3; } else { cupsFilePutChar(outfile, *s++); cupsFilePutChar(outfile, *s++); cupsFilePutChar(outfile, *s++); cupsFilePutChar(outfile, *s); } } else if ((*s & 0x80) || (*s < ' ' && !isspace(*s & 255))) { /* * Invalid control character... */ cupsFilePutChar(outfile, '?'); } else cupsFilePutChar(outfile, *s); s ++; } if (element) cupsFilePrintf(outfile, "\n", element); } /* * 'print_xml_trailer()' - Print the XML trailer with success/fail value. */ static void print_xml_trailer( _cups_testdata_t *data, /* I - Test data */ int success, /* I - 1 on success, 0 on failure */ const char *message) /* I - Error message or NULL */ { if (data->xml_header) { cupsFilePuts(data->outfile, "\n"); cupsFilePuts(data->outfile, "Successful\n"); cupsFilePuts(data->outfile, success ? "\n" : "\n"); if (message) { cupsFilePuts(data->outfile, "ErrorMessage\n"); print_xml_string(data->outfile, "string", message); } cupsFilePuts(data->outfile, "\n"); cupsFilePuts(data->outfile, "\n"); data->xml_header = 0; } } #ifndef WIN32 /* * 'sigterm_handler()' - Handle SIGINT and SIGTERM. */ static void sigterm_handler(int sig) /* I - Signal number (unused) */ { (void)sig; Cancel = 1; signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); } #endif /* !WIN32 */ /* * 'timeout_cb()' - Handle HTTP timeouts. */ static int /* O - 1 to continue, 0 to cancel */ timeout_cb(http_t *http, /* I - Connection to server */ void *user_data) /* I - User data (unused) */ { int buffered = 0; /* Bytes buffered but not yet sent */ (void)user_data; /* * If the socket still have data waiting to be sent to the printer (as can * happen if the printer runs out of paper), continue to wait until the output * buffer is empty... */ #ifdef SO_NWRITE /* macOS and some versions of Linux */ socklen_t len = sizeof(buffered); /* Size of return value */ if (getsockopt(httpGetFd(http), SOL_SOCKET, SO_NWRITE, &buffered, &len)) buffered = 0; #elif defined(SIOCOUTQ) /* Others except Windows */ if (ioctl(httpGetFd(http), SIOCOUTQ, &buffered)) buffered = 0; #else /* Windows (not possible) */ (void)http; #endif /* SO_NWRITE */ return (buffered > 0); } /* * 'token_cb()' - Parse test file-specific tokens and run tests. */ static int /* O - 1 to continue, 0 to stop */ token_cb(_ipp_file_t *f, /* I - IPP file data */ _ipp_vars_t *vars, /* I - IPP variables */ _cups_testdata_t *data, /* I - Test data */ const char *token) /* I - Current token */ { char name[1024], /* Name string */ temp[1024], /* Temporary string */ value[1024], /* Value string */ *ptr; /* Pointer into value */ if (!token) { /* * Initialize state as needed (nothing for now...) */ return (1); } else if (f->attrs) { /* * Parse until we see a close brace... */ if (_cups_strcasecmp(token, "COUNT") && _cups_strcasecmp(token, "DEFINE-MATCH") && _cups_strcasecmp(token, "DEFINE-NO-MATCH") && _cups_strcasecmp(token, "DEFINE-VALUE") && _cups_strcasecmp(token, "IF-DEFINED") && _cups_strcasecmp(token, "IF-NOT-DEFINED") && _cups_strcasecmp(token, "IN-GROUP") && _cups_strcasecmp(token, "OF-TYPE") && _cups_strcasecmp(token, "REPEAT-LIMIT") && _cups_strcasecmp(token, "REPEAT-MATCH") && _cups_strcasecmp(token, "REPEAT-NO-MATCH") && _cups_strcasecmp(token, "SAME-COUNT-AS") && _cups_strcasecmp(token, "WITH-ALL-VALUES") && _cups_strcasecmp(token, "WITH-ALL-HOSTNAMES") && _cups_strcasecmp(token, "WITH-ALL-RESOURCES") && _cups_strcasecmp(token, "WITH-ALL-SCHEMES") && _cups_strcasecmp(token, "WITH-HOSTNAME") && _cups_strcasecmp(token, "WITH-RESOURCE") && _cups_strcasecmp(token, "WITH-SCHEME") && _cups_strcasecmp(token, "WITH-VALUE") && _cups_strcasecmp(token, "WITH-VALUE-FROM")) data->last_expect = NULL; if (_cups_strcasecmp(token, "DEFINE-MATCH") && _cups_strcasecmp(token, "DEFINE-NO-MATCH") && _cups_strcasecmp(token, "IF-DEFINED") && _cups_strcasecmp(token, "IF-NOT-DEFINED") && _cups_strcasecmp(token, "REPEAT-LIMIT") && _cups_strcasecmp(token, "REPEAT-MATCH") && _cups_strcasecmp(token, "REPEAT-NO-MATCH")) data->last_status = NULL; if (!strcmp(token, "}")) { return (do_test(f, vars, data)); } else if (!strcmp(token, "COMPRESSION")) { /* * COMPRESSION none * COMPRESSION deflate * COMPRESSION gzip */ if (_ippFileReadToken(f, temp, sizeof(temp))) { _ippVarsExpand(vars, data->compression, temp, sizeof(data->compression)); #ifdef HAVE_LIBZ if (strcmp(data->compression, "none") && strcmp(data->compression, "deflate") && strcmp(data->compression, "gzip")) #else if (strcmp(data->compression, "none")) #endif /* HAVE_LIBZ */ { print_fatal_error(data, "Unsupported COMPRESSION value \"%s\" on line %d of \"%s\".", data->compression, f->linenum, f->filename); return (0); } if (!strcmp(data->compression, "none")) data->compression[0] = '\0'; } else { print_fatal_error(data, "Missing COMPRESSION value on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "DEFINE")) { /* * DEFINE name value */ if (_ippFileReadToken(f, name, sizeof(name)) && _ippFileReadToken(f, temp, sizeof(temp))) { _ippVarsExpand(vars, value, temp, sizeof(value)); _ippVarsSet(vars, name, value); } else { print_fatal_error(data, "Missing DEFINE name and/or value on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "IGNORE-ERRORS")) { /* * IGNORE-ERRORS yes * IGNORE-ERRORS no */ if (_ippFileReadToken(f, temp, sizeof(temp)) && (!_cups_strcasecmp(temp, "yes") || !_cups_strcasecmp(temp, "no"))) { data->ignore_errors = !_cups_strcasecmp(temp, "yes"); } else { print_fatal_error(data, "Missing IGNORE-ERRORS value on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "NAME")) { /* * Name of test... */ _ippFileReadToken(f, temp, sizeof(temp)); _ippVarsExpand(vars, data->name, temp, sizeof(data->name)); } else if (!_cups_strcasecmp(token, "PAUSE")) { /* * Pause with a message... */ if (_ippFileReadToken(f, temp, sizeof(temp))) { pause_message(temp); } else { print_fatal_error(data, "Missing PAUSE message on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "REQUEST-ID")) { /* * REQUEST-ID # * REQUEST-ID random */ if (_ippFileReadToken(f, temp, sizeof(temp))) { if (isdigit(temp[0] & 255)) { data->request_id = atoi(temp); } else if (!_cups_strcasecmp(temp, "random")) { data->request_id = (CUPS_RAND() % 1000) * 137 + 1; } else { print_fatal_error(data, "Bad REQUEST-ID value \"%s\" on line %d of \"%s\".", temp, f->linenum, f->filename); return (0); } } else { print_fatal_error(data, "Missing REQUEST-ID value on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "SKIP-IF-DEFINED")) { /* * SKIP-IF-DEFINED variable */ if (_ippFileReadToken(f, name, sizeof(name))) { if (_ippVarsGet(vars, name)) data->skip_test = 1; } else { print_fatal_error(data, "Missing SKIP-IF-DEFINED value on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "SKIP-IF-MISSING")) { /* * SKIP-IF-MISSING filename */ if (_ippFileReadToken(f, temp, sizeof(temp))) { char filename[1024]; /* Filename */ _ippVarsExpand(vars, value, temp, sizeof(value)); get_filename(f->filename, filename, temp, sizeof(filename)); if (access(filename, R_OK)) data->skip_test = 1; } else { print_fatal_error(data, "Missing SKIP-IF-MISSING filename on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "SKIP-IF-NOT-DEFINED")) { /* * SKIP-IF-NOT-DEFINED variable */ if (_ippFileReadToken(f, name, sizeof(name))) { if (!_ippVarsGet(vars, name)) data->skip_test = 1; } else { print_fatal_error(data, "Missing SKIP-IF-NOT-DEFINED value on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "SKIP-PREVIOUS-ERROR")) { /* * SKIP-PREVIOUS-ERROR yes * SKIP-PREVIOUS-ERROR no */ if (_ippFileReadToken(f, temp, sizeof(temp)) && (!_cups_strcasecmp(temp, "yes") || !_cups_strcasecmp(temp, "no"))) { data->skip_previous = !_cups_strcasecmp(temp, "yes"); } else { print_fatal_error(data, "Missing SKIP-PREVIOUS-ERROR value on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "TEST-ID")) { /* * TEST-ID "string" */ if (_ippFileReadToken(f, temp, sizeof(temp))) { _ippVarsExpand(vars, data->test_id, temp, sizeof(data->test_id)); } else { print_fatal_error(data, "Missing TEST-ID value on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "TRANSFER")) { /* * TRANSFER auto * TRANSFER chunked * TRANSFER length */ if (_ippFileReadToken(f, temp, sizeof(temp))) { if (!strcmp(temp, "auto")) { data->transfer = _CUPS_TRANSFER_AUTO; } else if (!strcmp(temp, "chunked")) { data->transfer = _CUPS_TRANSFER_CHUNKED; } else if (!strcmp(temp, "length")) { data->transfer = _CUPS_TRANSFER_LENGTH; } else { print_fatal_error(data, "Bad TRANSFER value \"%s\" on line %d of \"%s\".", temp, f->linenum, f->filename); return (0); } } else { print_fatal_error(data, "Missing TRANSFER value on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "VERSION")) { if (_ippFileReadToken(f, temp, sizeof(temp))) { if (!strcmp(temp, "0.0")) { data->version = 0; } else if (!strcmp(temp, "1.0")) { data->version = 10; } else if (!strcmp(temp, "1.1")) { data->version = 11; } else if (!strcmp(temp, "2.0")) { data->version = 20; } else if (!strcmp(temp, "2.1")) { data->version = 21; } else if (!strcmp(temp, "2.2")) { data->version = 22; } else { print_fatal_error(data, "Bad VERSION \"%s\" on line %d of \"%s\".", temp, f->linenum, f->filename); return (0); } } else { print_fatal_error(data, "Missing VERSION number on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "RESOURCE")) { /* * Resource name... */ if (!_ippFileReadToken(f, data->resource, sizeof(data->resource))) { print_fatal_error(data, "Missing RESOURCE path on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "OPERATION")) { /* * Operation... */ ipp_op_t op; /* Operation code */ if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing OPERATION code on line %d of \"%s\".", f->linenum, f->filename); return (0); } _ippVarsExpand(vars, value, temp, sizeof(value)); if ((op = ippOpValue(value)) == (ipp_op_t)-1 && (op = (ipp_op_t)strtol(value, NULL, 0)) == 0) { print_fatal_error(data, "Bad OPERATION code \"%s\" on line %d of \"%s\".", temp, f->linenum, f->filename); return (0); } ippSetOperation(f->attrs, op); } else if (!_cups_strcasecmp(token, "GROUP")) { /* * Attribute group... */ ipp_tag_t group_tag; /* Group tag */ if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing GROUP tag on line %d of \"%s\".", f->linenum, f->filename); return (0); } if ((group_tag = ippTagValue(temp)) == IPP_TAG_ZERO || group_tag >= IPP_TAG_UNSUPPORTED_VALUE) { print_fatal_error(data, "Bad GROUP tag \"%s\" on line %d of \"%s\".", temp, f->linenum, f->filename); return (0); } if (group_tag == f->group_tag) ippAddSeparator(f->attrs); f->group_tag = group_tag; } else if (!_cups_strcasecmp(token, "DELAY")) { /* * Delay before operation... */ double dval; /* Delay value */ if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing DELAY value on line %d of \"%s\".", f->linenum, f->filename); return (0); } _ippVarsExpand(vars, value, temp, sizeof(value)); if ((dval = _cupsStrScand(value, &ptr, localeconv())) < 0.0 || (*ptr && *ptr != ',')) { print_fatal_error(data, "Bad DELAY value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename); return (0); } data->delay = (useconds_t)(1000000.0 * dval); if (*ptr == ',') { if ((dval = _cupsStrScand(ptr + 1, &ptr, localeconv())) <= 0.0 || *ptr) { print_fatal_error(data, "Bad DELAY value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename); return (0); } data->repeat_interval = (useconds_t)(1000000.0 * dval); } else data->repeat_interval = data->delay; } else if (!_cups_strcasecmp(token, "FILE")) { /* * File... */ if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing FILE filename on line %d of \"%s\".", f->linenum, f->filename); return (0); } _ippVarsExpand(vars, value, temp, sizeof(value)); get_filename(f->filename, data->file, value, sizeof(data->file)); if (access(data->file, R_OK)) { print_fatal_error(data, "Filename \"%s\" (mapped to \"%s\") on line %d of \"%s\" cannot be read.", value, data->file, f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "STATUS")) { /* * Status... */ if (data->num_statuses >= (int)(sizeof(data->statuses) / sizeof(data->statuses[0]))) { print_fatal_error(data, "Too many STATUS's on line %d of \"%s\".", f->linenum, f->filename); return (0); } if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing STATUS code on line %d of \"%s\".", f->linenum, f->filename); return (0); } if ((data->statuses[data->num_statuses].status = ippErrorValue(temp)) == (ipp_status_t)-1 && (data->statuses[data->num_statuses].status = (ipp_status_t)strtol(temp, NULL, 0)) == 0) { print_fatal_error(data, "Bad STATUS code \"%s\" on line %d of \"%s\".", temp, f->linenum, f->filename); return (0); } data->last_status = data->statuses + data->num_statuses; data->num_statuses ++; data->last_status->define_match = NULL; data->last_status->define_no_match = NULL; data->last_status->if_defined = NULL; data->last_status->if_not_defined = NULL; data->last_status->repeat_limit = 1000; data->last_status->repeat_match = 0; data->last_status->repeat_no_match = 0; } else if (!_cups_strcasecmp(token, "EXPECT") || !_cups_strcasecmp(token, "EXPECT-ALL")) { /* * Expected attributes... */ int expect_all = !_cups_strcasecmp(token, "EXPECT-ALL"); if (data->num_expects >= (int)(sizeof(data->expects) / sizeof(data->expects[0]))) { print_fatal_error(data, "Too many EXPECT's on line %d of \"%s\".", f->linenum, f->filename); return (0); } if (!_ippFileReadToken(f, name, sizeof(name))) { print_fatal_error(data, "Missing EXPECT name on line %d of \"%s\".", f->linenum, f->filename); return (0); } data->last_expect = data->expects + data->num_expects; data->num_expects ++; memset(data->last_expect, 0, sizeof(_cups_expect_t)); data->last_expect->repeat_limit = 1000; data->last_expect->expect_all = expect_all; if (name[0] == '!') { data->last_expect->not_expect = 1; data->last_expect->name = strdup(name + 1); } else if (name[0] == '?') { data->last_expect->optional = 1; data->last_expect->name = strdup(name + 1); } else data->last_expect->name = strdup(name); } else if (!_cups_strcasecmp(token, "COUNT")) { int count; /* Count value */ if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing COUNT number on line %d of \"%s\".", f->linenum, f->filename); return (0); } if ((count = atoi(temp)) <= 0) { print_fatal_error(data, "Bad COUNT \"%s\" on line %d of \"%s\".", temp, f->linenum, f->filename); return (0); } if (data->last_expect) { data->last_expect->count = count; } else { print_fatal_error(data, "COUNT without a preceding EXPECT on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "DEFINE-MATCH")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing DEFINE-MATCH variable on line %d of \"%s\".", f->linenum, f->filename); return (0); } if (data->last_expect) { data->last_expect->define_match = strdup(temp); } else if (data->last_status) { data->last_status->define_match = strdup(temp); } else { print_fatal_error(data, "DEFINE-MATCH without a preceding EXPECT or STATUS on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "DEFINE-NO-MATCH")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing DEFINE-NO-MATCH variable on line %d of \"%s\".", f->linenum, f->filename); return (0); } if (data->last_expect) { data->last_expect->define_no_match = strdup(temp); } else if (data->last_status) { data->last_status->define_no_match = strdup(temp); } else { print_fatal_error(data, "DEFINE-NO-MATCH without a preceding EXPECT or STATUS on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "DEFINE-VALUE")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing DEFINE-VALUE variable on line %d of \"%s\".", f->linenum, f->filename); return (0); } if (data->last_expect) { data->last_expect->define_value = strdup(temp); } else { print_fatal_error(data, "DEFINE-VALUE without a preceding EXPECT on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "OF-TYPE")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing OF-TYPE value tag(s) on line %d of \"%s\".", f->linenum, f->filename); return (0); } if (data->last_expect) { data->last_expect->of_type = strdup(temp); } else { print_fatal_error(data, "OF-TYPE without a preceding EXPECT on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "IN-GROUP")) { ipp_tag_t in_group; /* IN-GROUP value */ if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing IN-GROUP group tag on line %d of \"%s\".", f->linenum, f->filename); return (0); } if ((in_group = ippTagValue(temp)) == IPP_TAG_ZERO || in_group >= IPP_TAG_UNSUPPORTED_VALUE) { print_fatal_error(data, "Bad IN-GROUP group tag \"%s\" on line %d of \"%s\".", temp, f->linenum, f->filename); return (0); } else if (data->last_expect) { data->last_expect->in_group = in_group; } else { print_fatal_error(data, "IN-GROUP without a preceding EXPECT on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "REPEAT-LIMIT")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing REPEAT-LIMIT value on line %d of \"%s\".", f->linenum, f->filename); return (0); } else if (atoi(temp) <= 0) { print_fatal_error(data, "Bad REPEAT-LIMIT value on line %d of \"%s\".", f->linenum, f->filename); return (0); } if (data->last_status) { data->last_status->repeat_limit = atoi(temp); } else if (data->last_expect) { data->last_expect->repeat_limit = atoi(temp); } else { print_fatal_error(data, "REPEAT-LIMIT without a preceding EXPECT or STATUS on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "REPEAT-MATCH")) { if (data->last_status) { data->last_status->repeat_match = 1; } else if (data->last_expect) { data->last_expect->repeat_match = 1; } else { print_fatal_error(data, "REPEAT-MATCH without a preceding EXPECT or STATUS on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "REPEAT-NO-MATCH")) { if (data->last_status) { data->last_status->repeat_no_match = 1; } else if (data->last_expect) { data->last_expect->repeat_no_match = 1; } else { print_fatal_error(data, "REPEAT-NO-MATCH without a preceding EXPECT or STATUS on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "SAME-COUNT-AS")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing SAME-COUNT-AS name on line %d of \"%s\".", f->linenum, f->filename); return (0); } if (data->last_expect) { data->last_expect->same_count_as = strdup(temp); } else { print_fatal_error(data, "SAME-COUNT-AS without a preceding EXPECT on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "IF-DEFINED")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing IF-DEFINED name on line %d of \"%s\".", f->linenum, f->filename); return (0); } if (data->last_expect) { data->last_expect->if_defined = strdup(temp); } else if (data->last_status) { data->last_status->if_defined = strdup(temp); } else { print_fatal_error(data, "IF-DEFINED without a preceding EXPECT or STATUS on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "IF-NOT-DEFINED")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing IF-NOT-DEFINED name on line %d of \"%s\".", f->linenum, f->filename); return (0); } if (data->last_expect) { data->last_expect->if_not_defined = strdup(temp); } else if (data->last_status) { data->last_status->if_not_defined = strdup(temp); } else { print_fatal_error(data, "IF-NOT-DEFINED without a preceding EXPECT or STATUS on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "WITH-ALL-VALUES") || !_cups_strcasecmp(token, "WITH-ALL-HOSTNAMES") || !_cups_strcasecmp(token, "WITH-ALL-RESOURCES") || !_cups_strcasecmp(token, "WITH-ALL-SCHEMES") || !_cups_strcasecmp(token, "WITH-HOSTNAME") || !_cups_strcasecmp(token, "WITH-RESOURCE") || !_cups_strcasecmp(token, "WITH-SCHEME") || !_cups_strcasecmp(token, "WITH-VALUE")) { off_t lastpos; /* Last file position */ if (data->last_expect) { if (!_cups_strcasecmp(token, "WITH-ALL-HOSTNAMES") || !_cups_strcasecmp(token, "WITH-HOSTNAME")) data->last_expect->with_flags = _CUPS_WITH_HOSTNAME; else if (!_cups_strcasecmp(token, "WITH-ALL-RESOURCES") || !_cups_strcasecmp(token, "WITH-RESOURCE")) data->last_expect->with_flags = _CUPS_WITH_RESOURCE; else if (!_cups_strcasecmp(token, "WITH-ALL-SCHEMES") || !_cups_strcasecmp(token, "WITH-SCHEME")) data->last_expect->with_flags = _CUPS_WITH_SCHEME; if (!_cups_strncasecmp(token, "WITH-ALL-", 9)) data->last_expect->with_flags |= _CUPS_WITH_ALL; } if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing %s value on line %d of \"%s\".", token, f->linenum, f->filename); return (0); } /* * Read additional comma-delimited values - needed since legacy test files * will have unquoted WITH-VALUE values with commas... */ ptr = temp + strlen(temp); for (;;) { lastpos = cupsFileTell(f->fp); ptr += strlen(ptr); if (!_ippFileReadToken(f, ptr, (sizeof(temp) - (size_t)(ptr - temp)))) break; if (!strcmp(ptr, ",")) { /* * Append a value... */ ptr += strlen(ptr); if (!_ippFileReadToken(f, ptr, (sizeof(temp) - (size_t)(ptr - temp)))) break; } else { /* * Not another value, stop here... */ cupsFileSeek(f->fp, lastpos); *ptr = '\0'; break; } } if (data->last_expect) { /* * Expand any variables in the value and then save it. */ _ippVarsExpand(vars, value, temp, sizeof(value)); ptr = value + strlen(value) - 1; if (value[0] == '/' && ptr > value && *ptr == '/') { /* * WITH-VALUE is a POSIX extended regular expression. */ data->last_expect->with_value = calloc(1, (size_t)(ptr - value)); data->last_expect->with_flags |= _CUPS_WITH_REGEX; if (data->last_expect->with_value) memcpy(data->last_expect->with_value, value + 1, (size_t)(ptr - value - 1)); } else { /* * WITH-VALUE is a literal value... */ for (ptr = value; *ptr; ptr ++) { if (*ptr == '\\' && ptr[1]) { /* * Remove \ from \foo... */ _cups_strcpy(ptr, ptr + 1); } } data->last_expect->with_value = strdup(value); data->last_expect->with_flags |= _CUPS_WITH_LITERAL; } } else { print_fatal_error(data, "%s without a preceding EXPECT on line %d of \"%s\".", token, f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "WITH-VALUE-FROM")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing %s value on line %d of \"%s\".", token, f->linenum, f->filename); return (0); } if (data->last_expect) { /* * Expand any variables in the value and then save it. */ _ippVarsExpand(vars, value, temp, sizeof(value)); data->last_expect->with_value_from = strdup(value); data->last_expect->with_flags = _CUPS_WITH_LITERAL; } else { print_fatal_error(data, "%s without a preceding EXPECT on line %d of \"%s\".", token, f->linenum, f->filename); return (0); } } else if (!_cups_strcasecmp(token, "DISPLAY")) { /* * Display attributes... */ if (data->num_displayed >= (int)(sizeof(data->displayed) / sizeof(data->displayed[0]))) { print_fatal_error(data, "Too many DISPLAY's on line %d of \"%s\".", f->linenum, f->filename); return (0); } if (!_ippFileReadToken(f, temp, sizeof(temp))) { print_fatal_error(data, "Missing DISPLAY name on line %d of \"%s\".", f->linenum, f->filename); return (0); } data->displayed[data->num_displayed] = strdup(temp); data->num_displayed ++; } else { print_fatal_error(data, "Unexpected token %s seen on line %d of \"%s\".", token, f->linenum, f->filename); return (0); } } else { /* * Scan for the start of a test (open brace)... */ if (!strcmp(token, "{")) { /* * Start new test... */ if (data->show_header) { if (data->output == _CUPS_OUTPUT_PLIST) print_xml_header(data); if (data->output == _CUPS_OUTPUT_TEST || (data->output == _CUPS_OUTPUT_PLIST && data->outfile != cupsFileStdout())) cupsFilePrintf(cupsFileStdout(), "\"%s\":\n", f->filename); data->show_header = 0; } data->compression[0] = '\0'; data->delay = 0; data->num_expects = 0; data->last_expect = NULL; data->file[0] = '\0'; data->ignore_errors = data->def_ignore_errors; strlcpy(data->name, f->filename, sizeof(data->name)); if ((ptr = strrchr(data->name, '.')) != NULL) *ptr = '\0'; data->repeat_interval = 5000000; data->request_id ++; strlcpy(data->resource, vars->resource, sizeof(data->resource)); data->skip_previous = 0; data->skip_test = 0; data->num_statuses = 0; data->last_status = NULL; data->test_id[0] = '\0'; data->transfer = data->def_transfer; data->version = data->def_version; f->attrs = ippNew(); f->group_tag = IPP_TAG_ZERO; } else if (!strcmp(token, "DEFINE")) { /* * DEFINE name value */ if (_ippFileReadToken(f, name, sizeof(name)) && _ippFileReadToken(f, temp, sizeof(temp))) { _ippVarsExpand(vars, value, temp, sizeof(value)); _ippVarsSet(vars, name, value); } else { print_fatal_error(data, "Missing DEFINE name and/or value on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "DEFINE-DEFAULT")) { /* * DEFINE-DEFAULT name value */ if (_ippFileReadToken(f, name, sizeof(name)) && _ippFileReadToken(f, temp, sizeof(temp))) { if (!_ippVarsGet(vars, name)) { _ippVarsExpand(vars, value, temp, sizeof(value)); _ippVarsSet(vars, name, value); } } else { print_fatal_error(data, "Missing DEFINE-DEFAULT name and/or value on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "FILE-ID")) { /* * FILE-ID "string" */ if (_ippFileReadToken(f, temp, sizeof(temp))) { _ippVarsExpand(vars, data->file_id, temp, sizeof(data->file_id)); } else { print_fatal_error(data, "Missing FILE-ID value on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "IGNORE-ERRORS")) { /* * IGNORE-ERRORS yes * IGNORE-ERRORS no */ if (_ippFileReadToken(f, temp, sizeof(temp)) && (!_cups_strcasecmp(temp, "yes") || !_cups_strcasecmp(temp, "no"))) { data->def_ignore_errors = !_cups_strcasecmp(temp, "yes"); } else { print_fatal_error(data, "Missing IGNORE-ERRORS value on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "INCLUDE")) { /* * INCLUDE "filename" * INCLUDE */ if (_ippFileReadToken(f, temp, sizeof(temp))) { /* * Map the filename to and then run the tests... */ _cups_testdata_t inc_data; /* Data for included file */ char filename[1024]; /* Mapped filename */ memcpy(&inc_data, data, sizeof(inc_data)); inc_data.http = NULL; inc_data.pass = 1; inc_data.prev_pass = 1; inc_data.show_header = 1; if (!do_tests(get_filename(f->filename, filename, temp, sizeof(filename)), vars, &inc_data) && data->stop_after_include_error) { data->pass = data->prev_pass = 0; return (0); } } else { print_fatal_error(data, "Missing INCLUDE filename on line %d of \"%s\".", f->linenum, f->filename); return (0); } data->show_header = 1; } else if (!strcmp(token, "INCLUDE-IF-DEFINED")) { /* * INCLUDE-IF-DEFINED name "filename" * INCLUDE-IF-DEFINED name */ if (_ippFileReadToken(f, name, sizeof(name)) && _ippFileReadToken(f, temp, sizeof(temp))) { /* * Map the filename to and then run the tests... */ _cups_testdata_t inc_data; /* Data for included file */ char filename[1024]; /* Mapped filename */ memcpy(&inc_data, data, sizeof(inc_data)); inc_data.http = NULL; inc_data.pass = 1; inc_data.prev_pass = 1; inc_data.show_header = 1; if (!do_tests(get_filename(f->filename, filename, temp, sizeof(filename)), vars, &inc_data) && data->stop_after_include_error) { data->pass = data->prev_pass = 0; return (0); } } else { print_fatal_error(data, "Missing INCLUDE-IF-DEFINED name or filename on line %d of \"%s\".", f->linenum, f->filename); return (0); } data->show_header = 1; } else if (!strcmp(token, "INCLUDE-IF-NOT-DEFINED")) { /* * INCLUDE-IF-NOT-DEFINED name "filename" * INCLUDE-IF-NOT-DEFINED name */ if (_ippFileReadToken(f, name, sizeof(name)) && _ippFileReadToken(f, temp, sizeof(temp))) { /* * Map the filename to and then run the tests... */ _cups_testdata_t inc_data; /* Data for included file */ char filename[1024]; /* Mapped filename */ memcpy(&inc_data, data, sizeof(inc_data)); inc_data.http = NULL; inc_data.pass = 1; inc_data.prev_pass = 1; inc_data.show_header = 1; if (!do_tests(get_filename(f->filename, filename, temp, sizeof(filename)), vars, &inc_data) && data->stop_after_include_error) { data->pass = data->prev_pass = 0; return (0); } } else { print_fatal_error(data, "Missing INCLUDE-IF-NOT-DEFINED name or filename on line %d of \"%s\".", f->linenum, f->filename); return (0); } data->show_header = 1; } else if (!strcmp(token, "SKIP-IF-DEFINED")) { /* * SKIP-IF-DEFINED variable */ if (_ippFileReadToken(f, name, sizeof(name))) { if (_ippVarsGet(vars, name)) data->skip_test = 1; } else { print_fatal_error(data, "Missing SKIP-IF-DEFINED variable on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "SKIP-IF-NOT-DEFINED")) { /* * SKIP-IF-NOT-DEFINED variable */ if (_ippFileReadToken(f, name, sizeof(name))) { if (!_ippVarsGet(vars, name)) data->skip_test = 1; } else { print_fatal_error(data, "Missing SKIP-IF-NOT-DEFINED variable on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "STOP-AFTER-INCLUDE-ERROR")) { /* * STOP-AFTER-INCLUDE-ERROR yes * STOP-AFTER-INCLUDE-ERROR no */ if (_ippFileReadToken(f, temp, sizeof(temp)) && (!_cups_strcasecmp(temp, "yes") || !_cups_strcasecmp(temp, "no"))) { data->stop_after_include_error = !_cups_strcasecmp(temp, "yes"); } else { print_fatal_error(data, "Missing STOP-AFTER-INCLUDE-ERROR value on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "TRANSFER")) { /* * TRANSFER auto * TRANSFER chunked * TRANSFER length */ if (_ippFileReadToken(f, temp, sizeof(temp))) { if (!strcmp(temp, "auto")) data->def_transfer = _CUPS_TRANSFER_AUTO; else if (!strcmp(temp, "chunked")) data->def_transfer = _CUPS_TRANSFER_CHUNKED; else if (!strcmp(temp, "length")) data->def_transfer = _CUPS_TRANSFER_LENGTH; else { print_fatal_error(data, "Bad TRANSFER value \"%s\" on line %d of \"%s\".", temp, f->linenum, f->filename); return (0); } } else { print_fatal_error(data, "Missing TRANSFER value on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else if (!strcmp(token, "VERSION")) { if (_ippFileReadToken(f, temp, sizeof(temp))) { if (!strcmp(temp, "1.0")) data->def_version = 10; else if (!strcmp(temp, "1.1")) data->def_version = 11; else if (!strcmp(temp, "2.0")) data->def_version = 20; else if (!strcmp(temp, "2.1")) data->def_version = 21; else if (!strcmp(temp, "2.2")) data->def_version = 22; else { print_fatal_error(data, "Bad VERSION \"%s\" on line %d of \"%s\".", temp, f->linenum, f->filename); return (0); } } else { print_fatal_error(data, "Missing VERSION number on line %d of \"%s\".", f->linenum, f->filename); return (0); } } else { print_fatal_error(data, "Unexpected token %s seen on line %d of \"%s\".", token, f->linenum, f->filename); return (0); } } return (1); } /* * 'usage()' - Show program usage. */ static void usage(void) { _cupsLangPuts(stderr, _("Usage: ipptool [options] URI filename [ ... filenameN ]")); _cupsLangPuts(stderr, _("Options:")); _cupsLangPuts(stderr, _(" --help Show help.")); _cupsLangPuts(stderr, _(" --ippserver filename Produce ippserver attribute file.")); _cupsLangPuts(stderr, _(" --stop-after-include-error\n" " Stop tests after a failed INCLUDE.")); _cupsLangPuts(stderr, _(" --version Show version.")); _cupsLangPuts(stderr, _(" -4 Connect using IPv4.")); _cupsLangPuts(stderr, _(" -6 Connect using IPv6.")); _cupsLangPuts(stderr, _(" -C Send requests using " "chunking (default).")); _cupsLangPuts(stderr, _(" -E Test with encryption using HTTP Upgrade to TLS.")); _cupsLangPuts(stderr, _(" -I Ignore errors.")); _cupsLangPuts(stderr, _(" -L Send requests using content-length.")); _cupsLangPuts(stderr, _(" -P filename.plist Produce XML plist to a file and test report to standard output.")); _cupsLangPuts(stderr, _(" -S Test with encryption using HTTPS.")); _cupsLangPuts(stderr, _(" -T seconds Set the receive/send timeout in seconds.")); _cupsLangPuts(stderr, _(" -V version Set default IPP version.")); _cupsLangPuts(stderr, _(" -X Produce XML plist instead of plain text.")); _cupsLangPuts(stderr, _(" -c Produce CSV output.")); _cupsLangPuts(stderr, _(" -d name=value Set named variable to value.")); _cupsLangPuts(stderr, _(" -f filename Set default request filename.")); _cupsLangPuts(stderr, _(" -h Validate HTTP response headers.")); _cupsLangPuts(stderr, _(" -i seconds Repeat the last file with the given time interval.")); _cupsLangPuts(stderr, _(" -l Produce plain text output.")); _cupsLangPuts(stderr, _(" -n count Repeat the last file the given number of times.")); _cupsLangPuts(stderr, _(" -q Run silently.")); _cupsLangPuts(stderr, _(" -t Produce a test report.")); _cupsLangPuts(stderr, _(" -v Be verbose.")); exit(1); } /* * 'with_flags_string()' - Return the "WITH-xxx" predicate that corresponds to the flags. */ static const char * /* O - WITH-xxx string */ with_flags_string(int flags) /* I - WITH flags */ { if (flags & _CUPS_WITH_ALL) { if (flags & _CUPS_WITH_HOSTNAME) return ("WITH-ALL-HOSTNAMES"); else if (flags & _CUPS_WITH_RESOURCE) return ("WITH-ALL-RESOURCES"); else if (flags & _CUPS_WITH_SCHEME) return ("WITH-ALL-SCHEMES"); else return ("WITH-ALL-VALUES"); } else if (flags & _CUPS_WITH_HOSTNAME) return ("WITH-HOSTNAME"); else if (flags & _CUPS_WITH_RESOURCE) return ("WITH-RESOURCE"); else if (flags & _CUPS_WITH_SCHEME) return ("WITH-SCHEME"); else return ("WITH-VALUE"); } /* * 'with_value()' - Test a WITH-VALUE predicate. */ static int /* O - 1 on match, 0 on non-match */ with_value(_cups_testdata_t *data, /* I - Test data */ cups_array_t *errors, /* I - Errors array */ char *value, /* I - Value string */ int flags, /* I - Flags for match */ ipp_attribute_t *attr, /* I - Attribute to compare */ char *matchbuf, /* I - Buffer to hold matching value */ size_t matchlen) /* I - Length of match buffer */ { int i, /* Looping var */ count, /* Number of values */ match; /* Match? */ char temp[1024], /* Temporary value string */ *valptr; /* Pointer into value */ const char *name; /* Attribute name */ *matchbuf = '\0'; match = (flags & _CUPS_WITH_ALL) ? 1 : 0; /* * NULL matches everything. */ if (!value || !*value) return (1); /* * Compare the value string to the attribute value. */ name = ippGetName(attr); count = ippGetCount(attr); switch (ippGetValueTag(attr)) { case IPP_TAG_INTEGER : case IPP_TAG_ENUM : for (i = 0; i < count; i ++) { char op, /* Comparison operator */ *nextptr; /* Next pointer */ int intvalue, /* Integer value */ attrvalue = ippGetInteger(attr, i), /* Attribute value */ valmatch = 0; /* Does the current value match? */ valptr = value; while (isspace(*valptr & 255) || isdigit(*valptr & 255) || *valptr == '-' || *valptr == ',' || *valptr == '<' || *valptr == '=' || *valptr == '>') { op = '='; while (*valptr && !isdigit(*valptr & 255) && *valptr != '-') { if (*valptr == '<' || *valptr == '>' || *valptr == '=') op = *valptr; valptr ++; } if (!*valptr) break; intvalue = (int)strtol(valptr, &nextptr, 0); if (nextptr == valptr) break; valptr = nextptr; if ((op == '=' && attrvalue == intvalue) || (op == '<' && attrvalue < intvalue) || (op == '>' && attrvalue > intvalue)) { if (!matchbuf[0]) snprintf(matchbuf, matchlen, "%d", attrvalue); valmatch = 1; break; } } if (flags & _CUPS_WITH_ALL) { if (!valmatch) { match = 0; break; } } else if (valmatch) { match = 1; break; } } if (!match && errors) { for (i = 0; i < count; i ++) add_stringf(data->errors, "GOT: %s=%d", name, ippGetInteger(attr, i)); } break; case IPP_TAG_RANGE : for (i = 0; i < count; i ++) { char op, /* Comparison operator */ *nextptr; /* Next pointer */ int intvalue, /* Integer value */ lower, /* Lower range */ upper, /* Upper range */ valmatch = 0; /* Does the current value match? */ lower = ippGetRange(attr, i, &upper); valptr = value; while (isspace(*valptr & 255) || isdigit(*valptr & 255) || *valptr == '-' || *valptr == ',' || *valptr == '<' || *valptr == '=' || *valptr == '>') { op = '='; while (*valptr && !isdigit(*valptr & 255) && *valptr != '-') { if (*valptr == '<' || *valptr == '>' || *valptr == '=') op = *valptr; valptr ++; } if (!*valptr) break; intvalue = (int)strtol(valptr, &nextptr, 0); if (nextptr == valptr) break; valptr = nextptr; if ((op == '=' && (lower == intvalue || upper == intvalue)) || (op == '<' && upper < intvalue) || (op == '>' && upper > intvalue)) { if (!matchbuf[0]) snprintf(matchbuf, matchlen, "%d-%d", lower, upper); valmatch = 1; break; } } if (flags & _CUPS_WITH_ALL) { if (!valmatch) { match = 0; break; } } else if (valmatch) { match = 1; break; } } if (!match && errors) { for (i = 0; i < count; i ++) { int lower, upper; /* Range values */ lower = ippGetRange(attr, i, &upper); add_stringf(data->errors, "GOT: %s=%d-%d", name, lower, upper); } } break; case IPP_TAG_BOOLEAN : for (i = 0; i < count; i ++) { if ((!strcmp(value, "true")) == ippGetBoolean(attr, i)) { if (!matchbuf[0]) strlcpy(matchbuf, value, matchlen); if (!(flags & _CUPS_WITH_ALL)) { match = 1; break; } } else if (flags & _CUPS_WITH_ALL) { match = 0; break; } } if (!match && errors) { for (i = 0; i < count; i ++) add_stringf(data->errors, "GOT: %s=%s", name, ippGetBoolean(attr, i) ? "true" : "false"); } break; case IPP_TAG_RESOLUTION : for (i = 0; i < count; i ++) { int xres, yres; /* Resolution values */ ipp_res_t units; /* Resolution units */ xres = ippGetResolution(attr, i, &yres, &units); if (xres == yres) snprintf(temp, sizeof(temp), "%d%s", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); else snprintf(temp, sizeof(temp), "%dx%d%s", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); if (!strcmp(value, temp)) { if (!matchbuf[0]) strlcpy(matchbuf, value, matchlen); if (!(flags & _CUPS_WITH_ALL)) { match = 1; break; } } else if (flags & _CUPS_WITH_ALL) { match = 0; break; } } if (!match && errors) { for (i = 0; i < count; i ++) { int xres, yres; /* Resolution values */ ipp_res_t units; /* Resolution units */ xres = ippGetResolution(attr, i, &yres, &units); if (xres == yres) snprintf(temp, sizeof(temp), "%d%s", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); else snprintf(temp, sizeof(temp), "%dx%d%s", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); if (strcmp(value, temp)) add_stringf(data->errors, "GOT: %s=%s", name, temp); } } break; case IPP_TAG_NOVALUE : case IPP_TAG_UNKNOWN : return (1); case IPP_TAG_CHARSET : case IPP_TAG_KEYWORD : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : case IPP_TAG_NAME : case IPP_TAG_NAMELANG : case IPP_TAG_TEXT : case IPP_TAG_TEXTLANG : case IPP_TAG_URI : case IPP_TAG_URISCHEME : if (flags & _CUPS_WITH_REGEX) { /* * Value is an extended, case-sensitive POSIX regular expression... */ regex_t re; /* Regular expression */ if ((i = regcomp(&re, value, REG_EXTENDED | REG_NOSUB)) != 0) { regerror(i, &re, temp, sizeof(temp)); print_fatal_error(data, "Unable to compile WITH-VALUE regular expression \"%s\" - %s", value, temp); return (0); } /* * See if ALL of the values match the given regular expression. */ for (i = 0; i < count; i ++) { if (!regexec(&re, get_string(attr, i, flags, temp, sizeof(temp)), 0, NULL, 0)) { if (!matchbuf[0]) strlcpy(matchbuf, get_string(attr, i, flags, temp, sizeof(temp)), matchlen); if (!(flags & _CUPS_WITH_ALL)) { match = 1; break; } } else if (flags & _CUPS_WITH_ALL) { match = 0; break; } } regfree(&re); } else if (ippGetValueTag(attr) == IPP_TAG_URI && !(flags & (_CUPS_WITH_SCHEME | _CUPS_WITH_HOSTNAME | _CUPS_WITH_RESOURCE))) { /* * Value is a literal URI string, see if the value(s) match... */ for (i = 0; i < count; i ++) { if (!compare_uris(value, get_string(attr, i, flags, temp, sizeof(temp)))) { if (!matchbuf[0]) strlcpy(matchbuf, get_string(attr, i, flags, temp, sizeof(temp)), matchlen); if (!(flags & _CUPS_WITH_ALL)) { match = 1; break; } } else if (flags & _CUPS_WITH_ALL) { match = 0; break; } } } else { /* * Value is a literal string, see if the value(s) match... */ for (i = 0; i < count; i ++) { int result; switch (ippGetValueTag(attr)) { case IPP_TAG_URI : /* * Some URI components are case-sensitive, some not... */ if (flags & (_CUPS_WITH_SCHEME | _CUPS_WITH_HOSTNAME)) result = _cups_strcasecmp(value, get_string(attr, i, flags, temp, sizeof(temp))); else result = strcmp(value, get_string(attr, i, flags, temp, sizeof(temp))); break; case IPP_TAG_MIMETYPE : case IPP_TAG_NAME : case IPP_TAG_NAMELANG : case IPP_TAG_TEXT : case IPP_TAG_TEXTLANG : /* * mimeMediaType, nameWithoutLanguage, nameWithLanguage, * textWithoutLanguage, and textWithLanguage are defined to * be case-insensitive strings... */ result = _cups_strcasecmp(value, get_string(attr, i, flags, temp, sizeof(temp))); break; default : /* * Other string syntaxes are defined as lowercased so we use * case-sensitive comparisons to catch problems... */ result = strcmp(value, get_string(attr, i, flags, temp, sizeof(temp))); break; } if (!result) { if (!matchbuf[0]) strlcpy(matchbuf, get_string(attr, i, flags, temp, sizeof(temp)), matchlen); if (!(flags & _CUPS_WITH_ALL)) { match = 1; break; } } else if (flags & _CUPS_WITH_ALL) { match = 0; break; } } } if (!match && errors) { for (i = 0; i < count; i ++) add_stringf(data->errors, "GOT: %s=\"%s\"", name, ippGetString(attr, i, NULL)); } break; default : break; } return (match); } /* * 'with_value_from()' - Test a WITH-VALUE-FROM predicate. */ static int /* O - 1 on match, 0 on non-match */ with_value_from( cups_array_t *errors, /* I - Errors array */ ipp_attribute_t *fromattr, /* I - "From" attribute */ ipp_attribute_t *attr, /* I - Attribute to compare */ char *matchbuf, /* I - Buffer to hold matching value */ size_t matchlen) /* I - Length of match buffer */ { int i, j, /* Looping vars */ count = ippGetCount(attr), /* Number of attribute values */ match = 1; /* Match? */ *matchbuf = '\0'; /* * Compare the from value(s) to the attribute value(s)... */ switch (ippGetValueTag(attr)) { case IPP_TAG_INTEGER : if (ippGetValueTag(fromattr) != IPP_TAG_INTEGER && ippGetValueTag(fromattr) != IPP_TAG_RANGE) goto wrong_value_tag; for (i = 0; i < count; i ++) { int value = ippGetInteger(attr, i); /* Current integer value */ if (ippContainsInteger(fromattr, value)) { if (!matchbuf[0]) snprintf(matchbuf, matchlen, "%d", value); } else { add_stringf(errors, "GOT: %s=%d", ippGetName(attr), value); match = 0; } } break; case IPP_TAG_ENUM : if (ippGetValueTag(fromattr) != IPP_TAG_ENUM) goto wrong_value_tag; for (i = 0; i < count; i ++) { int value = ippGetInteger(attr, i); /* Current integer value */ if (ippContainsInteger(fromattr, value)) { if (!matchbuf[0]) snprintf(matchbuf, matchlen, "%d", value); } else { add_stringf(errors, "GOT: %s=%d", ippGetName(attr), value); match = 0; } } break; case IPP_TAG_RESOLUTION : if (ippGetValueTag(fromattr) != IPP_TAG_RESOLUTION) goto wrong_value_tag; for (i = 0; i < count; i ++) { int xres, yres; ipp_res_t units; int fromcount = ippGetCount(fromattr); int fromxres, fromyres; ipp_res_t fromunits; xres = ippGetResolution(attr, i, &yres, &units); for (j = 0; j < fromcount; j ++) { fromxres = ippGetResolution(fromattr, j, &fromyres, &fromunits); if (fromxres == xres && fromyres == yres && fromunits == units) break; } if (j < fromcount) { if (!matchbuf[0]) { if (xres == yres) snprintf(matchbuf, matchlen, "%d%s", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); else snprintf(matchbuf, matchlen, "%dx%d%s", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); } } else { if (xres == yres) add_stringf(errors, "GOT: %s=%d%s", ippGetName(attr), xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); else add_stringf(errors, "GOT: %s=%dx%d%s", ippGetName(attr), xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); match = 0; } } break; case IPP_TAG_NOVALUE : case IPP_TAG_UNKNOWN : return (1); case IPP_TAG_CHARSET : case IPP_TAG_KEYWORD : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : case IPP_TAG_NAME : case IPP_TAG_NAMELANG : case IPP_TAG_TEXT : case IPP_TAG_TEXTLANG : case IPP_TAG_URISCHEME : for (i = 0; i < count; i ++) { const char *value = ippGetString(attr, i, NULL); /* Current string value */ if (ippContainsString(fromattr, value)) { if (!matchbuf[0]) strlcpy(matchbuf, value, matchlen); } else { add_stringf(errors, "GOT: %s='%s'", ippGetName(attr), value); match = 0; } } break; case IPP_TAG_URI : for (i = 0; i < count; i ++) { const char *value = ippGetString(attr, i, NULL); /* Current string value */ int fromcount = ippGetCount(fromattr); for (j = 0; j < fromcount; j ++) { if (!compare_uris(value, ippGetString(fromattr, j, NULL))) { if (!matchbuf[0]) strlcpy(matchbuf, value, matchlen); break; } } if (j >= fromcount) { add_stringf(errors, "GOT: %s='%s'", ippGetName(attr), value); match = 0; } } break; default : match = 0; break; } return (match); /* value tag mismatch between fromattr and attr */ wrong_value_tag : add_stringf(errors, "GOT: %s OF-TYPE %s", ippGetName(attr), ippTagString(ippGetValueTag(attr))); return (0); } ippsample/tools/ippserver.c0000644000175000017500000064557713240604116015112 0ustar tilltill/* * Sample IPP Everywhere server for CUPS. * * Copyright 2010-2017 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Disable private and deprecated stuff so we can verify that the public API * is sufficient to implement a server. */ #define _IPP_PRIVATE_STRUCTURES 0 /* Disable private IPP stuff */ #define _CUPS_NO_DEPRECATED 1 /* Disable deprecated stuff */ /* * Include necessary headers... */ #include /* CUPS configuration header */ #include /* Public API */ #include /* CUPS string functions */ #include /* For multithreading functions */ #include #include #include #include #include #include #include #ifdef WIN32 # include # include # include # define WEXITSTATUS(s) (s) # include typedef ULONG nfds_t; # define poll WSAPoll #else extern char **environ; # include # include # include #endif /* WIN32 */ #ifdef HAVE_DNSSD # include #elif defined(HAVE_AVAHI) # include # include # include # include #endif /* HAVE_DNSSD */ #ifdef HAVE_SYS_MOUNT_H # include #endif /* HAVE_SYS_MOUNT_H */ #ifdef HAVE_SYS_STATFS_H # include #endif /* HAVE_SYS_STATFS_H */ #ifdef HAVE_SYS_STATVFS_H # include #endif /* HAVE_SYS_STATVFS_H */ #ifdef HAVE_SYS_VFS_H # include #endif /* HAVE_SYS_VFS_H */ /* * Constants... */ enum _ipp_preason_e /* printer-state-reasons bit values */ { _IPP_PREASON_NONE = 0x0000, /* none */ _IPP_PREASON_OTHER = 0x0001, /* other */ _IPP_PREASON_COVER_OPEN = 0x0002, /* cover-open */ _IPP_PREASON_INPUT_TRAY_MISSING = 0x0004, /* input-tray-missing */ _IPP_PREASON_MARKER_SUPPLY_EMPTY = 0x0008, /* marker-supply-empty */ _IPP_PREASON_MARKER_SUPPLY_LOW = 0x0010, /* marker-supply-low */ _IPP_PREASON_MARKER_WASTE_ALMOST_FULL = 0x0020, /* marker-waste-almost-full */ _IPP_PREASON_MARKER_WASTE_FULL = 0x0040, /* marker-waste-full */ _IPP_PREASON_MEDIA_EMPTY = 0x0080, /* media-empty */ _IPP_PREASON_MEDIA_JAM = 0x0100, /* media-jam */ _IPP_PREASON_MEDIA_LOW = 0x0200, /* media-low */ _IPP_PREASON_MEDIA_NEEDED = 0x0400, /* media-needed */ _IPP_PREASON_MOVING_TO_PAUSED = 0x0800, /* moving-to-paused */ _IPP_PREASON_PAUSED = 0x1000, /* paused */ _IPP_PREASON_SPOOL_AREA_FULL = 0x2000,/* spool-area-full */ _IPP_PREASON_TONER_EMPTY = 0x4000, /* toner-empty */ _IPP_PREASON_TONER_LOW = 0x8000 /* toner-low */ }; typedef unsigned int _ipp_preason_t; /* Bitfield for printer-state-reasons */ static const char * const _ipp_preason_strings[] = { /* Strings for each bit */ /* "none" is implied for no bits set */ "other", "cover-open", "input-tray-missing", "marker-supply-empty", "marker-supply-low", "marker-waste-almost-full", "marker-waste-full", "media-empty", "media-jam", "media-low", "media-needed", "moving-to-paused", "paused", "spool-area-full", "toner-empty", "toner-low" }; typedef enum _ipp_media_class_e { _IPP_GENERAL, /* General-purpose size */ _IPP_PHOTO_ONLY, /* Photo-only size */ _IPP_ENV_ONLY /* Envelope-only size */ } _ipp_media_class_t; typedef enum _ipp_media_size_e { _IPP_MEDIA_SIZE_NONE = -1, _IPP_MEDIA_SIZE_A4, _IPP_MEDIA_SIZE_A5, _IPP_MEDIA_SIZE_A6, _IPP_MEDIA_SIZE_DL, _IPP_MEDIA_SIZE_LEGAL, _IPP_MEDIA_SIZE_LETTER, _IPP_MEDIA_SIZE_COM10, _IPP_MEDIA_SIZE_3x5, _IPP_MEDIA_SIZE_L, _IPP_MEDIA_SIZE_4x6, _IPP_MEDIA_SIZE_5x7 } _ipp_media_size_t; static const char * const media_supported[] = { /* media-supported values */ "iso_a4_210x297mm", /* A4 */ "iso_a5_148x210mm", /* A5 */ "iso_a6_105x148mm", /* A6 */ "iso_dl_110x220mm", /* DL */ "na_legal_8.5x14in", /* Legal */ "na_letter_8.5x11in", /* Letter */ "na_number-10_4.125x9.5in", /* #10 */ "na_index-3x5_3x5in", /* 3x5 */ "oe_photo-l_3.5x5in", /* L */ "na_index-4x6_4x6in", /* 4x6 */ "na_5x7_5x7in" /* 5x7 aka 2L */ }; static const int media_col_sizes[][3] = { /* media-col-database sizes */ { 21000, 29700, _IPP_GENERAL }, /* A4 */ { 14800, 21000, _IPP_PHOTO_ONLY }, /* A5 */ { 10500, 14800, _IPP_PHOTO_ONLY }, /* A6 */ { 11000, 22000, _IPP_ENV_ONLY }, /* DL */ { 21590, 35560, _IPP_GENERAL }, /* Legal */ { 21590, 27940, _IPP_GENERAL }, /* Letter */ { 10477, 24130, _IPP_ENV_ONLY }, /* #10 */ { 7630, 12700, _IPP_PHOTO_ONLY }, /* 3x5 */ { 8890, 12700, _IPP_PHOTO_ONLY }, /* L */ { 10160, 15240, _IPP_PHOTO_ONLY }, /* 4x6 */ { 12700, 17780, _IPP_PHOTO_ONLY } /* 5x7 aka 2L */ }; typedef enum _ipp_media_source_e { _IPP_MEDIA_SOURCE_NONE = -1, _IPP_MEDIA_SOURCE_AUTO, _IPP_MEDIA_SOURCE_MAIN, _IPP_MEDIA_SOURCE_MANUAL, _IPP_MEDIA_SOURCE_ENVELOPE, _IPP_MEDIA_SOURCE_PHOTO } _ipp_media_source_t; static const char * const media_source_supported[] = /* media-source-supported values */ { "auto", "main", "manual", "envelope", "photo" }; typedef enum _ipp_media_type_e { _IPP_MEDIA_TYPE_NONE = -1, _IPP_MEDIA_TYPE_AUTO, _IPP_MEDIA_TYPE_CARDSTOCK, _IPP_MEDIA_TYPE_ENVELOPE, _IPP_MEDIA_TYPE_LABELS, _IPP_MEDIA_TYPE_OTHER, _IPP_MEDIA_TYPE_GLOSSY, _IPP_MEDIA_TYPE_HIGH_GLOSS, _IPP_MEDIA_TYPE_MATTE, _IPP_MEDIA_TYPE_SATIN, _IPP_MEDIA_TYPE_SEMI_GLOSS, _IPP_MEDIA_TYPE_STATIONERY, _IPP_MEDIA_TYPE_LETTERHEAD, _IPP_MEDIA_TYPE_TRANSPARENCY } _ipp_media_type_t; static const char * const media_type_supported[] = /* media-type-supported values */ { "auto", "cardstock", "envelope", "labels", "other", "photographic-glossy", "photographic-high-gloss", "photographic-matte", "photographic-satin", "photographic-semi-gloss", "stationery", "stationery-letterhead", "transparency" }; typedef enum _ipp_supply_e { _IPP_SUPPLY_CYAN, /* Cyan Toner */ _IPP_SUPPLY_MAGENTA, /* Magenta Toner */ _IPP_SUPPLY_YELLOW, /* Yellow Toner */ _IPP_SUPPLY_BLACK, /* Black Toner */ _IPP_SUPPLY_WASTE /* Waste Toner */ } _ipp_supply_t; static const char * const printer_supplies[] = { /* printer-supply-description values */ "Cyan Toner", "Magenta Toner", "Yellow Toner", "Black Toner", "Toner Waste" }; /* * URL scheme for web resources... */ #ifdef HAVE_SSL # define WEB_SCHEME "https" #else # define WEB_SCHEME "http" #endif /* HAVE_SSL */ /* * Structures... */ #ifdef HAVE_DNSSD typedef DNSServiceRef _ipp_srv_t; /* Service reference */ typedef TXTRecordRef _ipp_txt_t; /* TXT record */ #elif defined(HAVE_AVAHI) typedef AvahiEntryGroup *_ipp_srv_t; /* Service reference */ typedef AvahiStringList *_ipp_txt_t; /* TXT record */ #else typedef void *_ipp_srv_t; /* Service reference */ typedef void *_ipp_txt_t; /* TXT record */ #endif /* HAVE_DNSSD */ typedef struct _ipp_filter_s /**** Attribute filter ****/ { cups_array_t *ra; /* Requested attributes */ ipp_tag_t group_tag; /* Group to copy */ } _ipp_filter_t; typedef struct _ipp_job_s _ipp_job_t; typedef struct _ipp_printer_s /**** Printer data ****/ { int ipv4, /* IPv4 listener */ ipv6; /* IPv6 listener */ _ipp_srv_t ipp_ref, /* Bonjour IPP service */ ipps_ref, /* Bonjour IPPS service */ http_ref, /* Bonjour HTTP service */ printer_ref; /* Bonjour LPD service */ char *dnssd_name, /* printer-dnssd-name */ *name, /* printer-name */ *icon, /* Icon filename */ *directory, /* Spool directory */ *hostname, /* Hostname */ *uri, /* printer-uri-supported */ *command; /* Command to run with job file */ int port; /* Port */ size_t urilen; /* Length of printer URI */ ipp_t *attrs; /* Static attributes */ time_t start_time; /* Startup time */ time_t config_time; /* printer-config-change-time */ ipp_pstate_t state; /* printer-state value */ _ipp_preason_t state_reasons; /* printer-state-reasons values */ time_t state_time; /* printer-state-change-time */ cups_array_t *jobs; /* Jobs */ _ipp_job_t *active_job; /* Current active/pending job */ int next_job_id; /* Next job-id value */ _cups_rwlock_t rwlock; /* Printer lock */ _ipp_media_size_t main_size; /* Ready media */ _ipp_media_type_t main_type; int main_level; _ipp_media_size_t envelope_size; int envelope_level; _ipp_media_size_t photo_size; _ipp_media_type_t photo_type; int photo_level; int supplies[5]; /* Supply levels (0-100) */ } _ipp_printer_t; struct _ipp_job_s /**** Job data ****/ { int id; /* Job ID */ const char *name, /* job-name */ *username, /* job-originating-user-name */ *format; /* document-format */ ipp_jstate_t state; /* job-state value */ time_t created, /* time-at-creation value */ processing, /* time-at-processing value */ completed; /* time-at-completed value */ int impressions, /* job-impressions value */ impcompleted; /* job-impressions-completed value */ ipp_t *attrs; /* Static attributes */ int cancel; /* Non-zero when job canceled */ char *filename; /* Print file name */ int fd; /* Print file descriptor */ _ipp_printer_t *printer; /* Printer */ }; typedef struct _ipp_client_s /**** Client data ****/ { http_t *http; /* HTTP connection */ ipp_t *request, /* IPP request */ *response; /* IPP response */ time_t start; /* Request start time */ http_state_t operation; /* Request operation */ ipp_op_t operation_id; /* IPP operation-id */ char uri[1024], /* Request URI */ *options; /* URI options */ http_addr_t addr; /* Client address */ char hostname[256]; /* Client hostname */ _ipp_printer_t *printer; /* Printer */ _ipp_job_t *job; /* Current job, if any */ } _ipp_client_t; /* * Local functions... */ static void clean_jobs(_ipp_printer_t *printer); static int compare_jobs(_ipp_job_t *a, _ipp_job_t *b); static void copy_attributes(ipp_t *to, ipp_t *from, cups_array_t *ra, ipp_tag_t group_tag, int quickcopy); static void copy_job_attributes(_ipp_client_t *client, _ipp_job_t *job, cups_array_t *ra); static _ipp_client_t *create_client(_ipp_printer_t *printer, int sock); static _ipp_job_t *create_job(_ipp_client_t *client); static int create_listener(int family, int port); static ipp_t *create_media_col(const char *media, const char *source, const char *type, int width, int length, int margins); static ipp_t *create_media_size(int width, int length); static _ipp_printer_t *create_printer(const char *servername, const char *name, const char *location, const char *make, const char *model, const char *icon, const char *docformats, int ppm, int ppm_color, int duplex, int port, int pin, const char *subtype, const char *directory, const char *command, const char *attrfile); static void debug_attributes(const char *title, ipp_t *ipp, int response); static void delete_client(_ipp_client_t *client); static void delete_job(_ipp_job_t *job); static void delete_printer(_ipp_printer_t *printer); #ifdef HAVE_DNSSD static void DNSSD_API dnssd_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, _ipp_printer_t *printer); #elif defined(HAVE_AVAHI) static void dnssd_callback(AvahiEntryGroup *p, AvahiEntryGroupState state, void *context); static void dnssd_client_cb(AvahiClient *c, AvahiClientState state, void *userdata); #endif /* HAVE_DNSSD */ static void dnssd_init(void); static int filter_cb(_ipp_filter_t *filter, ipp_t *dst, ipp_attribute_t *attr); static _ipp_job_t *find_job(_ipp_client_t *client); static ipp_t *get_collection(FILE *fp, const char *filename, int *linenum); static char *get_token(FILE *fp, char *buf, int buflen, int *linenum); static void html_escape(_ipp_client_t *client, const char *s, size_t slen); static void html_footer(_ipp_client_t *client); static void html_header(_ipp_client_t *client, const char *title); static void html_printf(_ipp_client_t *client, const char *format, ...) __attribute__((__format__(__printf__, 2, 3))); static void ipp_cancel_job(_ipp_client_t *client); static void ipp_close_job(_ipp_client_t *client); static void ipp_create_job(_ipp_client_t *client); static void ipp_get_job_attributes(_ipp_client_t *client); static void ipp_get_jobs(_ipp_client_t *client); static void ipp_get_printer_attributes(_ipp_client_t *client); static void ipp_identify_printer(_ipp_client_t *client); static void ipp_print_job(_ipp_client_t *client); static void ipp_print_uri(_ipp_client_t *client); static void ipp_send_document(_ipp_client_t *client); static void ipp_send_uri(_ipp_client_t *client); static void ipp_validate_job(_ipp_client_t *client); static void load_attributes(const char *filename, ipp_t *attrs); static int parse_options(_ipp_client_t *client, cups_option_t **options); static void process_attr_message(_ipp_job_t *job, char *message); static void *process_client(_ipp_client_t *client); static int process_http(_ipp_client_t *client); static int process_ipp(_ipp_client_t *client); static void *process_job(_ipp_job_t *job); static void process_state_message(_ipp_job_t *job, char *message); static int register_printer(_ipp_printer_t *printer, const char *location, const char *make, const char *model, const char *formats, const char *adminurl, const char *uuid, int color, int duplex, const char *regtype); static int respond_http(_ipp_client_t *client, http_status_t code, const char *content_coding, const char *type, size_t length); static void respond_ipp(_ipp_client_t *client, ipp_status_t status, const char *message, ...) __attribute__ ((__format__ (__printf__, 3, 4))); static void respond_unsupported(_ipp_client_t *client, ipp_attribute_t *attr); static void run_printer(_ipp_printer_t *printer); static char *time_string(time_t tv, char *buffer, size_t bufsize); static void usage(int status) __attribute__((noreturn)); static int valid_doc_attributes(_ipp_client_t *client); static int valid_job_attributes(_ipp_client_t *client); /* * Globals... */ #ifdef HAVE_DNSSD static DNSServiceRef DNSSDMaster = NULL; #elif defined(HAVE_AVAHI) static AvahiThreadedPoll *DNSSDMaster = NULL; static AvahiClient *DNSSDClient = NULL; #endif /* HAVE_DNSSD */ static int KeepFiles = 0, Verbosity = 0; /* * 'main()' - Main entry to the sample server. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ const char *opt, /* Current option character */ *attrfile = NULL, /* Attributes file */ *command = NULL, /* Command to run with job files */ *servername = NULL, /* Server host name */ *name = NULL, /* Printer name */ *location = "", /* Location of printer */ *make = "Test", /* Manufacturer */ *model = "Printer", /* Model */ *icon = "printer.png", /* Icon file */ *formats = "application/pdf,image/jpeg,image/pwg-raster"; /* Supported formats */ #ifdef HAVE_SSL const char *keypath = NULL; /* Keychain path */ #endif /* HAVE_SSL */ const char *subtype = "_print"; /* Bonjour service subtype */ int port = 0, /* Port number (0 = auto) */ duplex = 0, /* Duplex mode */ ppm = 10, /* Pages per minute for mono */ ppm_color = 0, /* Pages per minute for color */ pin = 0; /* PIN printing mode? */ char directory[1024] = "", /* Spool directory */ hostname[1024]; /* Auto-detected hostname */ _ipp_printer_t *printer; /* Printer object */ /* * Parse command-line arguments... */ for (i = 1; i < argc; i ++) if (argv[i][0] == '-') { for (opt = argv[i] + 1; *opt; opt ++) { switch (*opt) { case '2' : /* -2 (enable 2-sided printing) */ duplex = 1; break; #ifdef HAVE_SSL case 'K' : /* -K keypath */ i ++; if (i >= argc) usage(1); keypath = argv[i]; break; #endif /* HAVE_SSL */ case 'M' : /* -M manufacturer */ i ++; if (i >= argc) usage(1); make = argv[i]; break; case 'P' : /* -P (PIN printing mode) */ pin = 1; break; case 'a' : /* -a attributes-file */ i ++; if (i >= argc) usage(1); attrfile = argv[i]; break; case 'c' : /* -c command */ i ++; if (i >= argc) usage(1); command = argv[i]; break; case 'd' : /* -d spool-directory */ i ++; if (i >= argc) usage(1); strlcpy(directory, argv[i], sizeof(directory)); break; case 'f' : /* -f type/subtype[,...] */ i ++; if (i >= argc) usage(1); formats = argv[i]; break; case 'h' : /* -h (show help) */ usage(0); case 'i' : /* -i icon.png */ i ++; if (i >= argc) usage(1); icon = argv[i]; break; case 'k' : /* -k (keep files) */ KeepFiles = 1; break; case 'l' : /* -l location */ i ++; if (i >= argc) usage(1); location = argv[i]; break; case 'm' : /* -m model */ i ++; if (i >= argc) usage(1); model = argv[i]; break; case 'n' : /* -n hostname */ i ++; if (i >= argc) usage(1); servername = argv[i]; break; case 'p' : /* -p port */ i ++; if (i >= argc || !isdigit(argv[i][0] & 255)) usage(1); port = atoi(argv[i]); break; case 'r' : /* -r subtype */ i ++; if (i >= argc) usage(1); subtype = argv[i]; break; case 's' : /* -s speed[,color-speed] */ i ++; if (i >= argc) usage(1); if (sscanf(argv[i], "%d,%d", &ppm, &ppm_color) < 1) usage(1); break; case 'v' : /* -v (be verbose) */ Verbosity ++; break; default : /* Unknown */ fprintf(stderr, "Unknown option \"-%c\".\n", *opt); usage(1); } } } else if (!name) { name = argv[i]; } else { fprintf(stderr, "Unexpected command-line argument \"%s\"\n", argv[i]); usage(1); } if (!name) usage(1); /* * Apply defaults as needed... */ if (!servername) servername = httpGetHostname(NULL, hostname, sizeof(hostname)); if (!port) { #ifdef WIN32 /* * Windows is almost always used as a single user system, so use a default * port number of 8631. */ port = 8631; #else /* * Use 8000 + UID mod 1000 for the default port number... */ port = 8000 + ((int)getuid() % 1000); #endif /* WIN32 */ fprintf(stderr, "Listening on port %d.\n", port); } if (!directory[0]) { const char *tmpdir; /* Temporary directory */ #ifdef WIN32 if ((tmpdir = getenv("TEMP")) == NULL) tmpdir = "C:/TEMP"; #elif defined(__APPLE__) && !TARGET_OS_IOS if ((tmpdir = getenv("TMPDIR")) == NULL) tmpdir = "/private/tmp"; #else if ((tmpdir = getenv("TMPDIR")) == NULL) tmpdir = "/tmp"; #endif /* WIN32 */ snprintf(directory, sizeof(directory), "%s/ippserver.%d", tmpdir, (int)getpid()); if (mkdir(directory, 0755) && errno != EEXIST) { fprintf(stderr, "Unable to create spool directory \"%s\": %s\n", directory, strerror(errno)); usage(1); } if (Verbosity) fprintf(stderr, "Using spool directory \"%s\".\n", directory); } #ifdef HAVE_SSL cupsSetServerCredentials(keypath, servername, 1); #endif /* HAVE_SSL */ /* * Initialize Bonjour... */ dnssd_init(); /* * Create the printer... */ if ((printer = create_printer(servername, name, location, make, model, icon, formats, ppm, ppm_color, duplex, port, pin, subtype, directory, command, attrfile)) == NULL) return (1); /* * Run the print service... */ run_printer(printer); /* * Destroy the printer and exit... */ delete_printer(printer); return (0); } /* * 'clean_jobs()' - Clean out old (completed) jobs. */ static void clean_jobs(_ipp_printer_t *printer) /* I - Printer */ { _ipp_job_t *job; /* Current job */ time_t cleantime; /* Clean time */ if (cupsArrayCount(printer->jobs) == 0) return; cleantime = time(NULL) - 60; _cupsRWLockWrite(&(printer->rwlock)); for (job = (_ipp_job_t *)cupsArrayFirst(printer->jobs); job; job = (_ipp_job_t *)cupsArrayNext(printer->jobs)) if (job->completed && job->completed < cleantime) { cupsArrayRemove(printer->jobs, job); delete_job(job); } else break; _cupsRWUnlock(&(printer->rwlock)); } /* * 'compare_jobs()' - Compare two jobs. */ static int /* O - Result of comparison */ compare_jobs(_ipp_job_t *a, /* I - First job */ _ipp_job_t *b) /* I - Second job */ { return (b->id - a->id); } /* * 'copy_attributes()' - Copy attributes from one request to another. */ static void copy_attributes(ipp_t *to, /* I - Destination request */ ipp_t *from, /* I - Source request */ cups_array_t *ra, /* I - Requested attributes */ ipp_tag_t group_tag, /* I - Group to copy */ int quickcopy) /* I - Do a quick copy? */ { _ipp_filter_t filter; /* Filter data */ filter.ra = ra; filter.group_tag = group_tag; ippCopyAttributes(to, from, quickcopy, (ipp_copycb_t)filter_cb, &filter); } /* * 'copy_job_attrs()' - Copy job attributes to the response. */ static void copy_job_attributes( _ipp_client_t *client, /* I - Client */ _ipp_job_t *job, /* I - Job */ cups_array_t *ra) /* I - requested-attributes */ { copy_attributes(client->response, job->attrs, ra, IPP_TAG_JOB, 0); if (!ra || cupsArrayFind(ra, "date-time-at-completed")) { if (job->completed) ippAddDate(client->response, IPP_TAG_JOB, "date-time-at-completed", ippTimeToDate(job->completed)); else ippAddOutOfBand(client->response, IPP_TAG_JOB, IPP_TAG_NOVALUE, "date-time-at-completed"); } if (!ra || cupsArrayFind(ra, "date-time-at-processing")) { if (job->processing) ippAddDate(client->response, IPP_TAG_JOB, "date-time-at-processing", ippTimeToDate(job->processing)); else ippAddOutOfBand(client->response, IPP_TAG_JOB, IPP_TAG_NOVALUE, "date-time-at-processing"); } if (!ra || cupsArrayFind(ra, "job-impressions")) ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-impressions", job->impressions); if (!ra || cupsArrayFind(ra, "job-impressions-completed")) ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-impressions-completed", job->impcompleted); if (!ra || cupsArrayFind(ra, "job-printer-up-time")) ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-printer-up-time", (int)(time(NULL) - client->printer->start_time)); if (!ra || cupsArrayFind(ra, "job-state")) ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", job->state); if (!ra || cupsArrayFind(ra, "job-state-message")) { switch (job->state) { case IPP_JSTATE_PENDING : ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job pending."); break; case IPP_JSTATE_HELD : if (job->fd >= 0) ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job incoming."); else if (ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_ZERO)) ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job held."); else ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job created."); break; case IPP_JSTATE_PROCESSING : if (job->cancel) ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job canceling."); else ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job printing."); break; case IPP_JSTATE_STOPPED : ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job stopped."); break; case IPP_JSTATE_CANCELED : ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job canceled."); break; case IPP_JSTATE_ABORTED : ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job aborted."); break; case IPP_JSTATE_COMPLETED : ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, "Job completed."); break; } } if (!ra || cupsArrayFind(ra, "job-state-reasons")) { switch (job->state) { case IPP_JSTATE_PENDING : ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "none"); break; case IPP_JSTATE_HELD : if (job->fd >= 0) ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "job-incoming"); else if (ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_ZERO)) ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "job-hold-until-specified"); else ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "job-data-insufficient"); break; case IPP_JSTATE_PROCESSING : if (job->cancel) ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "processing-to-stop-point"); else ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "job-printing"); break; case IPP_JSTATE_STOPPED : ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "job-stopped"); break; case IPP_JSTATE_CANCELED : ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "job-canceled-by-user"); break; case IPP_JSTATE_ABORTED : ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "aborted-by-system"); break; case IPP_JSTATE_COMPLETED : ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "job-completed-successfully"); break; } } if (!ra || cupsArrayFind(ra, "time-at-completed")) ippAddInteger(client->response, IPP_TAG_JOB, job->completed ? IPP_TAG_INTEGER : IPP_TAG_NOVALUE, "time-at-completed", (int)(job->completed - client->printer->start_time)); if (!ra || cupsArrayFind(ra, "time-at-processing")) ippAddInteger(client->response, IPP_TAG_JOB, job->processing ? IPP_TAG_INTEGER : IPP_TAG_NOVALUE, "time-at-processing", (int)(job->processing - client->printer->start_time)); } /* * 'create_client()' - Accept a new network connection and create a client * object. */ static _ipp_client_t * /* O - Client */ create_client(_ipp_printer_t *printer, /* I - Printer */ int sock) /* I - Listen socket */ { _ipp_client_t *client; /* Client */ if ((client = calloc(1, sizeof(_ipp_client_t))) == NULL) { perror("Unable to allocate memory for client"); return (NULL); } client->printer = printer; /* * Accept the client and get the remote address... */ if ((client->http = httpAcceptConnection(sock, 1)) == NULL) { perror("Unable to accept client connection"); free(client); return (NULL); } httpGetHostname(client->http, client->hostname, sizeof(client->hostname)); if (Verbosity) fprintf(stderr, "Accepted connection from %s\n", client->hostname); return (client); } /* * 'create_job()' - Create a new job object from a Print-Job or Create-Job * request. */ static _ipp_job_t * /* O - Job */ create_job(_ipp_client_t *client) /* I - Client */ { _ipp_job_t *job; /* Job */ ipp_attribute_t *attr; /* Job attribute */ char uri[1024], /* job-uri value */ uuid[64]; /* job-uuid value */ _cupsRWLockWrite(&(client->printer->rwlock)); if (client->printer->active_job && client->printer->active_job->state < IPP_JSTATE_CANCELED) { /* * Only accept a single job at a time... */ _cupsRWUnlock(&(client->printer->rwlock)); return (NULL); } /* * Allocate and initialize the job object... */ if ((job = calloc(1, sizeof(_ipp_job_t))) == NULL) { perror("Unable to allocate memory for job"); return (NULL); } job->printer = client->printer; job->attrs = ippNew(); job->state = IPP_JSTATE_HELD; job->fd = -1; /* * Copy all of the job attributes... */ copy_attributes(job->attrs, client->request, NULL, IPP_TAG_JOB, 0); /* * Get the requesting-user-name, document format, and priority... */ if ((attr = ippFindAttribute(client->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) job->username = ippGetString(attr, 0, NULL); else job->username = "anonymous"; ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-user-name", NULL, job->username); if (ippGetOperation(client->request) != IPP_OP_CREATE_JOB) { if ((attr = ippFindAttribute(job->attrs, "document-format-detected", IPP_TAG_MIMETYPE)) != NULL) job->format = ippGetString(attr, 0, NULL); else if ((attr = ippFindAttribute(job->attrs, "document-format-supplied", IPP_TAG_MIMETYPE)) != NULL) job->format = ippGetString(attr, 0, NULL); else job->format = "application/octet-stream"; } if ((attr = ippFindAttribute(client->request, "job-impressions", IPP_TAG_INTEGER)) != NULL) job->impressions = ippGetInteger(attr, 0); if ((attr = ippFindAttribute(client->request, "job-name", IPP_TAG_NAME)) != NULL) job->name = ippGetString(attr, 0, NULL); /* * Add job description attributes and add to the jobs array... */ job->id = client->printer->next_job_id ++; snprintf(uri, sizeof(uri), "%s/%d", client->printer->uri, job->id); httpAssembleUUID(client->printer->hostname, client->printer->port, client->printer->name, job->id, uuid, sizeof(uuid)); ippAddDate(job->attrs, IPP_TAG_JOB, "date-time-at-creation", ippTimeToDate(time(&job->created))); ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, uri); ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uuid", NULL, uuid); if ((attr = ippFindAttribute(client->request, "printer-uri", IPP_TAG_URI)) != NULL) ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, ippGetString(attr, 0, NULL)); else ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, client->printer->uri); ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation", (int)(job->created - client->printer->start_time)); cupsArrayAdd(client->printer->jobs, job); client->printer->active_job = job; _cupsRWUnlock(&(client->printer->rwlock)); return (job); } /* * 'create_job_filename()' - Create the filename for a document in a job. */ static void create_job_filename( _ipp_printer_t *printer, /* I - Printer */ _ipp_job_t *job, /* I - Job */ char *fname, /* I - Filename buffer */ size_t fnamesize) /* I - Size of filename buffer */ { char name[256], /* "Safe" filename */ *nameptr; /* Pointer into filename */ const char *ext, /* Filename extension */ *job_name; /* job-name value */ ipp_attribute_t *job_name_attr; /* job-name attribute */ /* * Make a name from the job-name attribute... */ if ((job_name_attr = ippFindAttribute(job->attrs, "job-name", IPP_TAG_NAME)) != NULL) job_name = ippGetString(job_name_attr, 0, NULL); else job_name = "untitled"; for (nameptr = name; *job_name && nameptr < (name + sizeof(name) - 1); job_name ++) if (isalnum(*job_name & 255) || *job_name == '-') *nameptr++ = (char)tolower(*job_name & 255); else *nameptr++ = '_'; *nameptr = '\0'; /* * Figure out the extension... */ if (!strcasecmp(job->format, "image/jpeg")) ext = "jpg"; else if (!strcasecmp(job->format, "image/png")) ext = "png"; else if (!strcasecmp(job->format, "image/pwg-raster")) ext = "ras"; else if (!strcasecmp(job->format, "image/urf")) ext = "urf"; else if (!strcasecmp(job->format, "application/pdf")) ext = "pdf"; else if (!strcasecmp(job->format, "application/postscript")) ext = "ps"; else ext = "prn"; /* * Create a filename with the job-id, job-name, and document-format (extension)... */ snprintf(fname, fnamesize, "%s/%d-%s.%s", printer->directory, job->id, name, ext); } /* * 'create_listener()' - Create a listener socket. */ static int /* O - Listener socket or -1 on error */ create_listener(int family, /* I - Address family */ int port) /* I - Port number */ { int sock; /* Listener socket */ http_addrlist_t *addrlist; /* Listen address */ char service[255]; /* Service port */ snprintf(service, sizeof(service), "%d", port); if ((addrlist = httpAddrGetList(NULL, family, service)) == NULL) return (-1); sock = httpAddrListen(&(addrlist->addr), port); httpAddrFreeList(addrlist); return (sock); } /* * 'create_media_col()' - Create a media-col value. */ static ipp_t * /* O - media-col collection */ create_media_col(const char *media, /* I - Media name */ const char *source, /* I - Media source */ const char *type, /* I - Media type */ int width, /* I - x-dimension in 2540ths */ int length, /* I - y-dimension in 2540ths */ int margins) /* I - Value for margins */ { ipp_t *media_col = ippNew(), /* media-col value */ *media_size = create_media_size(width, length); /* media-size value */ char media_key[256]; /* media-key value */ if (type && source) snprintf(media_key, sizeof(media_key), "%s_%s_%s%s", media, source, type, margins == 0 ? "_borderless" : ""); else if (type) snprintf(media_key, sizeof(media_key), "%s__%s%s", media, type, margins == 0 ? "_borderless" : ""); else if (source) snprintf(media_key, sizeof(media_key), "%s_%s%s", media, source, margins == 0 ? "_borderless" : ""); else snprintf(media_key, sizeof(media_key), "%s%s", media, margins == 0 ? "_borderless" : ""); ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-key", NULL, media_key); ippAddCollection(media_col, IPP_TAG_PRINTER, "media-size", media_size); ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-size-name", NULL, media); ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin", margins); ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-left-margin", margins); ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-right-margin", margins); ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-top-margin", margins); if (source) ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-source", NULL, source); if (type) ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-type", NULL, type); ippDelete(media_size); return (media_col); } /* * 'create_media_size()' - Create a media-size value. */ static ipp_t * /* O - media-col collection */ create_media_size(int width, /* I - x-dimension in 2540ths */ int length) /* I - y-dimension in 2540ths */ { ipp_t *media_size = ippNew(); /* media-size value */ ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "x-dimension", width); ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "y-dimension", length); return (media_size); } /* * 'create_printer()' - Create, register, and listen for connections to a * printer object. */ static _ipp_printer_t * /* O - Printer */ create_printer(const char *servername, /* I - Server hostname (NULL for default) */ const char *name, /* I - printer-name */ const char *location, /* I - printer-location */ const char *make, /* I - printer-make-and-model */ const char *model, /* I - printer-make-and-model */ const char *icon, /* I - printer-icons */ const char *docformats, /* I - document-format-supported */ int ppm, /* I - Pages per minute in grayscale */ int ppm_color, /* I - Pages per minute in color (0 for gray) */ int duplex, /* I - 1 = duplex, 0 = simplex */ int port, /* I - Port for listeners or 0 for auto */ int pin, /* I - Require PIN printing */ const char *subtype, /* I - Bonjour service subtype */ const char *directory, /* I - Spool directory */ const char *command, /* I - Command to run on job files */ const char *attrfile) /* I - Attributes file */ { int i, j; /* Looping vars */ _ipp_printer_t *printer; /* Printer */ #ifndef WIN32 char path[1024]; /* Full path to command */ #endif /* !WIN32 */ char uri[1024], /* Printer URI */ #ifdef HAVE_SSL securi[1024], /* Secure printer URI */ *uris[2], /* All URIs */ #endif /* HAVE_SSL */ icons[1024], /* printer-icons URI */ adminurl[1024], /* printer-more-info URI */ supplyurl[1024],/* printer-supply-info-uri URI */ device_id[1024],/* printer-device-id */ make_model[128],/* printer-make-and-model */ uuid[128]; /* printer-uuid */ int num_formats; /* Number of document-format-supported values */ char *defformat, /* document-format-default value */ *formats[100], /* document-format-supported values */ *ptr; /* Pointer into string */ const char *prefix; /* Prefix string */ int num_database; /* Number of database values */ ipp_attribute_t *media_col_database, /* media-col-database value */ *media_size_supported; /* media-size-supported value */ ipp_t *media_col_default; /* media-col-default value */ int media_col_index;/* Current media-col-database value */ int k_supported; /* Maximum file size supported */ #ifdef HAVE_STATVFS struct statvfs spoolinfo; /* FS info for spool directory */ double spoolsize; /* FS size */ #elif defined(HAVE_STATFS) struct statfs spoolinfo; /* FS info for spool directory */ double spoolsize; /* FS size */ #endif /* HAVE_STATVFS */ static const int orients[4] = /* orientation-requested-supported values */ { IPP_ORIENT_PORTRAIT, IPP_ORIENT_LANDSCAPE, IPP_ORIENT_REVERSE_LANDSCAPE, IPP_ORIENT_REVERSE_PORTRAIT }; static const char * const versions[] =/* ipp-versions-supported values */ { "1.0", "1.1", "2.0" }; static const char * const features[] =/* ipp-features-supported values */ { "ipp-everywhere" }; static const int ops[] = /* operations-supported values */ { IPP_OP_PRINT_JOB, IPP_OP_PRINT_URI, IPP_OP_VALIDATE_JOB, IPP_OP_CREATE_JOB, IPP_OP_SEND_DOCUMENT, IPP_OP_SEND_URI, IPP_OP_CANCEL_JOB, IPP_OP_GET_JOB_ATTRIBUTES, IPP_OP_GET_JOBS, IPP_OP_GET_PRINTER_ATTRIBUTES, IPP_OP_CANCEL_MY_JOBS, IPP_OP_CLOSE_JOB, IPP_OP_IDENTIFY_PRINTER }; static const char * const charsets[] =/* charset-supported values */ { "us-ascii", "utf-8" }; static const char * const compressions[] =/* compression-supported values */ { #ifdef HAVE_LIBZ "deflate", "gzip", #endif /* HAVE_LIBZ */ "none" }; static const char * const identify_actions[] = { "display", "sound" }; static const char * const job_creation[] = { /* job-creation-attributes-supported values */ "copies", "ipp-attribute-fidelity", "job-account-id", "job-accounting-user-id", "job-name", "job-password", "job-priority", "media", "media-col", "multiple-document-handling", "orientation-requested", "print-quality", "sides" }; static const char * const media_col_supported[] = { /* media-col-supported values */ "media-bottom-margin", "media-left-margin", "media-right-margin", "media-size", "media-source", "media-top-margin", "media-type" }; static const int media_xxx_margin_supported[] = { /* media-xxx-margin-supported values */ 0, 635 }; static const char * const multiple_document_handling[] = { /* multiple-document-handling-supported values */ "separate-documents-uncollated-copies", "separate-documents-collated-copies" }; static const char * const overrides[] = { /* overrides-supported */ "document-number", "pages" }; static const char * const print_color_mode_supported[] = { /* print-color-mode-supported values */ "auto", "color", "monochrome" }; static const int print_quality_supported[] = { /* print-quality-supported values */ IPP_QUALITY_DRAFT, IPP_QUALITY_NORMAL, IPP_QUALITY_HIGH }; static const int pwg_raster_document_resolution_supported[] = { 150, 300 }; static const char * const pwg_raster_document_type_supported[] = { "black_1", "cmyk_8", "sgray_8", "srgb_8", "srgb_16" }; static const char * const reference_uri_schemes_supported[] = { /* reference-uri-schemes-supported */ "file", "ftp", "http" #ifdef HAVE_SSL , "https" #endif /* HAVE_SSL */ }; static const char * const sides_supported[] = { /* sides-supported values */ "one-sided", "two-sided-long-edge", "two-sided-short-edge" }; static const char * const urf_supported[] = { /* urf-supported values */ "CP1", "IS1-5-7", "MT1-2-3-4-5-6-8-9-10-11-12-13", "RS300", "SRGB24", "V1.4", "W8", "DM1" }; #ifdef HAVE_SSL static const char * const uri_authentication_supported[] = { /* uri-authentication-supported values */ "none", "none" }; static const char * const uri_security_supported[] = { /* uri-security-supported values */ "none", "tls" }; #endif /* HAVE_SSL */ static const char * const which_jobs[] = { /* which-jobs-supported values */ "completed", "not-completed", "aborted", "all", "canceled", "pending", "pending-held", "processing", "processing-stopped" }; #ifndef WIN32 /* * If a command was specified, make sure it exists and is executable... */ if (command) { if (*command == '/' || !strncmp(command, "./", 2)) { if (access(command, X_OK)) { fprintf(stderr, "ippserver: Unable to execute command \"%s\": %s\n", command, strerror(errno)); return (NULL); } } else { if (!cupsFileFind(command, getenv("PATH"), 1, path, sizeof(path))) { fprintf(stderr, "ippserver: Unable to find command \"%s\".\n", command); return (NULL); } command = path; } } #endif /* !WIN32 */ /* * Allocate memory for the printer... */ if ((printer = calloc(1, sizeof(_ipp_printer_t))) == NULL) { perror("ippserver: Unable to allocate memory for printer"); return (NULL); } printer->ipv4 = -1; printer->ipv6 = -1; printer->name = strdup(name); printer->dnssd_name = strdup(printer->name); printer->command = command ? strdup(command) : NULL; printer->directory = strdup(directory); printer->hostname = strdup(servername); printer->port = port; printer->start_time = time(NULL); printer->config_time = printer->start_time; printer->state = IPP_PSTATE_IDLE; printer->state_reasons = _IPP_PREASON_NONE; printer->state_time = printer->start_time; printer->jobs = cupsArrayNew((cups_array_func_t)compare_jobs, NULL); printer->next_job_id = 1; httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, printer->hostname, printer->port, "/ipp/print"); printer->uri = strdup(uri); printer->urilen = strlen(uri); #ifdef HAVE_SSL httpAssembleURI(HTTP_URI_CODING_ALL, securi, sizeof(securi), "ipps", NULL, printer->hostname, printer->port, "/ipp/print"); #endif /* HAVE_SSL */ if (icon) printer->icon = strdup(icon); printer->main_size = _IPP_MEDIA_SIZE_A4; printer->main_type = _IPP_MEDIA_TYPE_STATIONERY; printer->main_level = 500; printer->envelope_size = _IPP_MEDIA_SIZE_NONE; printer->envelope_level = 0; printer->photo_size = _IPP_MEDIA_SIZE_NONE; printer->photo_type = _IPP_MEDIA_TYPE_NONE; printer->photo_level = 0; printer->supplies[_IPP_SUPPLY_CYAN] = 100; printer->supplies[_IPP_SUPPLY_MAGENTA] = 100; printer->supplies[_IPP_SUPPLY_YELLOW] = 100; printer->supplies[_IPP_SUPPLY_BLACK] = 100; printer->supplies[_IPP_SUPPLY_WASTE] = 0; _cupsRWInit(&(printer->rwlock)); /* * Create the listener sockets... */ if ((printer->ipv4 = create_listener(AF_INET, printer->port)) < 0) { perror("Unable to create IPv4 listener"); goto bad_printer; } if ((printer->ipv6 = create_listener(AF_INET6, printer->port)) < 0) { perror("Unable to create IPv6 listener"); goto bad_printer; } /* * Prepare values for the printer attributes... */ httpAssembleURI(HTTP_URI_CODING_ALL, icons, sizeof(icons), WEB_SCHEME, NULL, printer->hostname, printer->port, "/icon.png"); httpAssembleURI(HTTP_URI_CODING_ALL, adminurl, sizeof(adminurl), WEB_SCHEME, NULL, printer->hostname, printer->port, "/"); httpAssembleURI(HTTP_URI_CODING_ALL, supplyurl, sizeof(supplyurl), WEB_SCHEME, NULL, printer->hostname, printer->port, "/supplies"); if (Verbosity) { fprintf(stderr, "printer-more-info=\"%s\"\n", adminurl); fprintf(stderr, "printer-supply-info-uri=\"%s\"\n", supplyurl); fprintf(stderr, "printer-uri=\"%s\"\n", uri); } snprintf(make_model, sizeof(make_model), "%s %s", make, model); num_formats = 1; formats[0] = strdup(docformats); defformat = formats[0]; for (ptr = strchr(formats[0], ','); ptr; ptr = strchr(ptr, ',')) { *ptr++ = '\0'; formats[num_formats++] = ptr; if (!strcasecmp(ptr, "application/octet-stream")) defformat = ptr; } snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;", make, model); ptr = device_id + strlen(device_id); prefix = "CMD:"; for (i = 0; i < num_formats; i ++) { if (!strcasecmp(formats[i], "application/pdf")) snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPDF", prefix); else if (!strcasecmp(formats[i], "application/postscript")) snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPS", prefix); else if (!strcasecmp(formats[i], "application/vnd.hp-PCL")) snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPCL", prefix); else if (!strcasecmp(formats[i], "image/jpeg")) snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sJPEG", prefix); else if (!strcasecmp(formats[i], "image/png")) snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPNG", prefix); else if (strcasecmp(formats[i], "application/octet-stream")) snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%s%s", prefix, formats[i]); ptr += strlen(ptr); prefix = ","; } if (ptr < (device_id + sizeof(device_id) - 1)) { *ptr++ = ';'; *ptr = '\0'; } /* * Get the maximum spool size based on the size of the filesystem used for * the spool directory. If the host OS doesn't support the statfs call * or the filesystem is larger than 2TiB, always report INT_MAX. */ #ifdef HAVE_STATVFS if (statvfs(printer->directory, &spoolinfo)) k_supported = INT_MAX; else if ((spoolsize = (double)spoolinfo.f_frsize * spoolinfo.f_blocks / 1024) > INT_MAX) k_supported = INT_MAX; else k_supported = (int)spoolsize; #elif defined(HAVE_STATFS) if (statfs(printer->directory, &spoolinfo)) k_supported = INT_MAX; else if ((spoolsize = (double)spoolinfo.f_bsize * spoolinfo.f_blocks / 1024) > INT_MAX) k_supported = INT_MAX; else k_supported = (int)spoolsize; #else k_supported = INT_MAX; #endif /* HAVE_STATVFS */ /* * Create the printer attributes. This list of attributes is sorted to improve * performance when the client provides a requested-attributes attribute... */ printer->attrs = ippNew(); if (attrfile) load_attributes(attrfile, printer->attrs); /* charset-configured */ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_CHARSET), "charset-configured", NULL, "utf-8"); /* charset-supported */ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_CHARSET), "charset-supported", sizeof(charsets) / sizeof(charsets[0]), NULL, charsets); /* color-supported */ if (!ippFindAttribute(printer->attrs, "color-supported", IPP_TAG_ZERO)) ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "color-supported", ppm_color > 0); /* compression-supported */ if (!ippFindAttribute(printer->attrs, "compression-supported", IPP_TAG_ZERO)) ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "compression-supported", (int)(sizeof(compressions) / sizeof(compressions[0])), NULL, compressions); /* copies-default */ if (!ippFindAttribute(printer->attrs, "copies-default", IPP_TAG_ZERO)) ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default", 1); /* copies-supported */ if (!ippFindAttribute(printer->attrs, "copies-supported", IPP_TAG_ZERO)) ippAddRange(printer->attrs, IPP_TAG_PRINTER, "copies-supported", 1, 999); /* document-format-default */ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, "document-format-default", NULL, defformat); /* document-format-supported */ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, "document-format-supported", num_formats, NULL, (const char * const *)formats); /* document-password-supported */ if (!ippFindAttribute(printer->attrs, "document-password-supported", IPP_TAG_ZERO)) ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "document-password-supported", 127); /* finishings-default */ if (!ippFindAttribute(printer->attrs, "finishings-default", IPP_TAG_ZERO)) ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "finishings-default", IPP_FINISHINGS_NONE); /* finishings-supported */ if (!ippFindAttribute(printer->attrs, "finishings-supported", IPP_TAG_ZERO)) ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "finishings-supported", IPP_FINISHINGS_NONE); /* generated-natural-language-supported */ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_LANGUAGE), "generated-natural-language-supported", NULL, "en"); /* identify-actions-default */ if (!ippFindAttribute(printer->attrs, "identify-actions-default", IPP_TAG_ZERO)) ippAddString (printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "identify-actions-default", NULL, "sound"); /* identify-actions-supported */ if (!ippFindAttribute(printer->attrs, "identify-actions-supported", IPP_TAG_ZERO)) ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "identify-actions-supported", sizeof(identify_actions) / sizeof(identify_actions[0]), NULL, identify_actions); /* ipp-features-supported */ if (!ippFindAttribute(printer->attrs, "ipp-features-supported", IPP_TAG_ZERO)) ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-features-supported", sizeof(features) / sizeof(features[0]), NULL, features); /* ipp-versions-supported */ if (!ippFindAttribute(printer->attrs, "ipp-versions-supported", IPP_TAG_ZERO)) ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]), NULL, versions); /* job-account-id-default */ if (!ippFindAttribute(printer->attrs, "job-account-id-default", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-account-id-default", NULL, ""); /* job-account-id-supported */ if (!ippFindAttribute(printer->attrs, "job-account-id-supported", IPP_TAG_ZERO)) ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "job-account-id-supported", 1); /* job-accounting-user-id-default */ if (!ippFindAttribute(printer->attrs, "job-accounting-user-id-default", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-accounting-user-id-default", NULL, ""); /* job-accounting-user-id-supported */ if (!ippFindAttribute(printer->attrs, "job-accounting-user-id-supported", IPP_TAG_ZERO)) ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "job-accounting-user-id-supported", 1); /* job-creation-attributes-supported */ if (!ippFindAttribute(printer->attrs, "job-creation-attributes-supported", IPP_TAG_ZERO)) ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-creation-attributes-supported", sizeof(job_creation) / sizeof(job_creation[0]), NULL, job_creation); /* job-ids-supported */ ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "job-ids-supported", 1); /* job-k-octets-supported */ ippAddRange(printer->attrs, IPP_TAG_PRINTER, "job-k-octets-supported", 0, k_supported); /* job-password-supported */ if (!ippFindAttribute(printer->attrs, "job-password-supported", IPP_TAG_ZERO)) ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-password-supported", 4); /* job-priority-default */ if (!ippFindAttribute(printer->attrs, "job-priority-default", IPP_TAG_ZERO)) ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-priority-default", 50); /* job-priority-supported */ if (!ippFindAttribute(printer->attrs, "job-priority-supported", IPP_TAG_ZERO)) ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-priority-supported", 100); /* job-sheets-default */ if (!ippFindAttribute(printer->attrs, "job-sheets-default", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-sheets-default", NULL, "none"); /* job-sheets-supported */ if (!ippFindAttribute(printer->attrs, "job-sheets-supported", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-sheets-supported", NULL, "none"); /* media-bottom-margin-supported */ if (!ippFindAttribute(printer->attrs, "media-bottom-margin-supported", IPP_TAG_ZERO)) ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin-supported", (int)(sizeof(media_xxx_margin_supported) / sizeof(media_xxx_margin_supported[0])), media_xxx_margin_supported); /* media-col-database */ if (!ippFindAttribute(printer->attrs, "media-col-database", IPP_TAG_ZERO)) { for (num_database = 0, i = 0; i < (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])); i ++) { if (media_col_sizes[i][2] == _IPP_ENV_ONLY) num_database += 3; /* auto + manual + envelope */ else if (media_col_sizes[i][2] == _IPP_PHOTO_ONLY) num_database += 6 * 3; /* auto + photographic-* from auto, manual, and photo */ else num_database += 2; /* Regular + borderless */ } media_col_database = ippAddCollections(printer->attrs, IPP_TAG_PRINTER, "media-col-database", num_database, NULL); for (media_col_index = 0, i = 0; i < (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])); i ++) { switch (media_col_sizes[i][2]) { case _IPP_GENERAL : /* * Regular + borderless for the general class; no source/type * selectors... */ ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], NULL, NULL, media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[1])); ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], NULL, NULL, media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[0])); break; case _IPP_ENV_ONLY : /* * Regular margins for "auto", "manual", and "envelope" sources. */ ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], "auto", "envelope", media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[1])); ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], "manual", "envelope", media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[1])); ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], "envelope", "envelope", media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[1])); break; case _IPP_PHOTO_ONLY : /* * Photos have specific media types and can only be printed via * the auto, manual, and photo sources... */ for (j = 0; j < (int)(sizeof(media_type_supported) / sizeof(media_type_supported[0])); j ++) { if (strcmp(media_type_supported[j], "auto") && strncmp(media_type_supported[j], "photographic-", 13)) continue; ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], "auto", media_type_supported[j], media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[0])); ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], "manual", media_type_supported[j], media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[0])); ippSetCollection(printer->attrs, &media_col_database, media_col_index ++, create_media_col(media_supported[i], "photo", media_type_supported[j], media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[0])); } break; } } } /* media-col-default */ if (!ippFindAttribute(printer->attrs, "media-col-default", IPP_TAG_ZERO)) { media_col_default = create_media_col(media_supported[0], media_source_supported[0], media_type_supported[0], media_col_sizes[0][0], media_col_sizes[0][1],media_xxx_margin_supported[1]); ippAddCollection(printer->attrs, IPP_TAG_PRINTER, "media-col-default", media_col_default); ippDelete(media_col_default); } /* media-col-supported */ if (!ippFindAttribute(printer->attrs, "media-col-supported", IPP_TAG_ZERO)) ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-col-supported", (int)(sizeof(media_col_supported) / sizeof(media_col_supported[0])), NULL, media_col_supported); /* media-default */ if (!ippFindAttribute(printer->attrs, "media-default", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-default", NULL, media_supported[0]); /* media-left-margin-supported */ if (!ippFindAttribute(printer->attrs, "media-left-margin-supported", IPP_TAG_ZERO)) ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-left-margin-supported", (int)(sizeof(media_xxx_margin_supported) / sizeof(media_xxx_margin_supported[0])), media_xxx_margin_supported); /* media-right-margin-supported */ if (!ippFindAttribute(printer->attrs, "media-right-margin-supported", IPP_TAG_ZERO)) ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-right-margin-supported", (int)(sizeof(media_xxx_margin_supported) / sizeof(media_xxx_margin_supported[0])), media_xxx_margin_supported); /* media-supported */ if (!ippFindAttribute(printer->attrs, "media-supported", IPP_TAG_ZERO)) ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-supported", (int)(sizeof(media_supported) / sizeof(media_supported[0])), NULL, media_supported); /* media-size-supported */ if (!ippFindAttribute(printer->attrs, "media-size-supported", IPP_TAG_ZERO)) { media_size_supported = ippAddCollections(printer->attrs, IPP_TAG_PRINTER, "media-size-supported", (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])), NULL); for (i = 0; i < (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])); i ++) { ipp_t *size = create_media_size(media_col_sizes[i][0], media_col_sizes[i][1]); ippSetCollection(printer->attrs, &media_size_supported, i, size); ippDelete(size); } } /* media-source-supported */ if (!ippFindAttribute(printer->attrs, "media-source-supported", IPP_TAG_ZERO)) ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-source-supported", (int)(sizeof(media_source_supported) / sizeof(media_source_supported[0])), NULL, media_source_supported); /* media-top-margin-supported */ if (!ippFindAttribute(printer->attrs, "media-top-margin-supported", IPP_TAG_ZERO)) ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-top-margin-supported", (int)(sizeof(media_xxx_margin_supported) / sizeof(media_xxx_margin_supported[0])), media_xxx_margin_supported); /* media-type-supported */ if (!ippFindAttribute(printer->attrs, "media-type-supported", IPP_TAG_ZERO)) ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-type-supported", (int)(sizeof(media_type_supported) / sizeof(media_type_supported[0])), NULL, media_type_supported); /* multiple-document-handling-supported */ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "multiple-document-handling-supported", sizeof(multiple_document_handling) / sizeof(multiple_document_handling[0]), NULL, multiple_document_handling); /* multiple-document-jobs-supported */ ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "multiple-document-jobs-supported", 0); /* multiple-operation-time-out */ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "multiple-operation-time-out", 60); /* multiple-operation-time-out-action */ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "multiple-operation-time-out-action", NULL, "abort-job"); /* natural-language-configured */ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_LANGUAGE), "natural-language-configured", NULL, "en"); /* number-up-default */ if (!ippFindAttribute(printer->attrs, "number-up-default", IPP_TAG_ZERO)) ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "number-up-default", 1); /* number-up-supported */ if (!ippFindAttribute(printer->attrs, "number-up-supported", IPP_TAG_ZERO)) ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "number-up-supported", 1); /* operations-supported */ ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "operations-supported", sizeof(ops) / sizeof(ops[0]), ops); /* orientation-requested-default */ if (!ippFindAttribute(printer->attrs, "orientation-requested-default", IPP_TAG_ZERO)) ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "orientation-requested-default", 0); /* orientation-requested-supported */ if (!ippFindAttribute(printer->attrs, "orientation-requested-supported", IPP_TAG_ZERO)) ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "orientation-requested-supported", 4, orients); /* output-bin-default */ if (!ippFindAttribute(printer->attrs, "output-bin-default", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-default", NULL, "face-down"); /* output-bin-supported */ if (!ippFindAttribute(printer->attrs, "output-bin-supported", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-supported", NULL, "face-down"); /* overrides-supported */ if (!ippFindAttribute(printer->attrs, "overrides-supported", IPP_TAG_ZERO)) ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "overrides-supported", (int)(sizeof(overrides) / sizeof(overrides[0])), NULL, overrides); /* page-ranges-supported */ if (!ippFindAttribute(printer->attrs, "page-ranges-supported", IPP_TAG_ZERO)) ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "page-ranges-supported", 1); /* pages-per-minute */ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "pages-per-minute", ppm); /* pages-per-minute-color */ if (ppm_color > 0) ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "pages-per-minute-color", ppm_color); /* pdl-override-supported */ if (!ippFindAttribute(printer->attrs, "pdl-override-supported", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pdl-override-supported", NULL, "attempted"); /* preferred-attributes-supported */ ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "preferred-attributes-supported", 0); /* print-color-mode-default */ if (!ippFindAttribute(printer->attrs, "print-color-mode-default", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-color-mode-default", NULL, "auto"); /* print-color-mode-supported */ if (!ippFindAttribute(printer->attrs, "print-color-mode-supported", IPP_TAG_ZERO)) ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-color-mode-supported", (int)(sizeof(print_color_mode_supported) / sizeof(print_color_mode_supported[0])), NULL, print_color_mode_supported); /* print-content-optimize-default */ if (!ippFindAttribute(printer->attrs, "print-content-optimize-default", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-content-optimize-default", NULL, "auto"); /* print-content-optimize-supported */ if (!ippFindAttribute(printer->attrs, "print-content-optimize-supported", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-content-optimize-supported", NULL, "auto"); /* print-rendering-intent-default */ if (!ippFindAttribute(printer->attrs, "print-rendering-intent-default", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-default", NULL, "auto"); /* print-rendering-intent-supported */ if (!ippFindAttribute(printer->attrs, "print-rendering-intent-supported", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-supported", NULL, "auto"); /* print-quality-default */ if (!ippFindAttribute(printer->attrs, "print-quality-default", IPP_TAG_ZERO)) ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "print-quality-default", IPP_QUALITY_NORMAL); /* print-quality-supported */ if (!ippFindAttribute(printer->attrs, "print-quality-supported", IPP_TAG_ZERO)) ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "print-quality-supported", (int)(sizeof(print_quality_supported) / sizeof(print_quality_supported[0])), print_quality_supported); /* printer-device-id */ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-device-id", NULL, device_id); /* printer-get-attributes-supported */ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "printer-get-attributes-supported", NULL, "document-format"); /* printer-geo-location */ if (!ippFindAttribute(printer->attrs, "printer-geo-location", IPP_TAG_ZERO)) ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_UNKNOWN, "printer-geo-location", 0); /* printer-icons */ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-icons", NULL, icons); /* printer-is-accepting-jobs */ ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1); /* printer-info */ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL, name); /* printer-location */ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", NULL, location); /* printer-make-and-model */ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-make-and-model", NULL, make_model); /* printer-mandatory-job-attributes */ if (pin && !ippFindAttribute(printer->attrs, "", IPP_TAG_ZERO)) { static const char * const names[] = { "job-account-id", "job-accounting-user-id", "job-password" }; ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "printer-mandatory-job-attributes", (int)(sizeof(names) / sizeof(names[0])), NULL, names); } /* printer-more-info */ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info", NULL, adminurl); /* printer-name */ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL, name); /* printer-organization */ if (!ippFindAttribute(printer->attrs, "printer-organization", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-organization", NULL, "Apple Inc."); /* printer-organizational-unit */ if (!ippFindAttribute(printer->attrs, "printer-organizational-unit", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-organizational-unit", NULL, "Printing Engineering"); /* printer-resolution-default */ if (!ippFindAttribute(printer->attrs, "printer-resolution-default", IPP_TAG_ZERO)) ippAddResolution(printer->attrs, IPP_TAG_PRINTER, "printer-resolution-default", IPP_RES_PER_INCH, 600, 600); /* printer-resolution-supported */ if (!ippFindAttribute(printer->attrs, "printer-resolutions-supported", IPP_TAG_ZERO)) ippAddResolution(printer->attrs, IPP_TAG_PRINTER, "printer-resolution-supported", IPP_RES_PER_INCH, 600, 600); /* printer-supply-description */ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-supply-description", (int)(sizeof(printer_supplies) / sizeof(printer_supplies[0])), NULL, printer_supplies); /* printer-supply-info-uri */ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-supply-info-uri", NULL, supplyurl); /* printer-uri-supported */ #ifdef HAVE_SSL uris[0] = uri; uris[1] = securi; ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", 2, NULL, (const char **)uris); #else ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", NULL, uri); #endif /* HAVE_SSL */ /* printer-uuid */ httpAssembleUUID(printer->hostname, port, name, 0, uuid, sizeof(uuid)); ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uuid", NULL, uuid); /* pwg-raster-document-xxx-supported */ for (i = 0; i < num_formats; i ++) if (!strcasecmp(formats[i], "image/pwg-raster")) break; if (i < num_formats) { if (!ippFindAttribute(printer->attrs, "pwg-raster-document-resolution-supported", IPP_TAG_ZERO)) ippAddResolutions(printer->attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", (int)(sizeof(pwg_raster_document_resolution_supported) / sizeof(pwg_raster_document_resolution_supported[0])), IPP_RES_PER_INCH, pwg_raster_document_resolution_supported, pwg_raster_document_resolution_supported); if (!ippFindAttribute(printer->attrs, "pwg-raster-document-sheet-back", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-sheet-back", NULL, "normal"); if (!ippFindAttribute(printer->attrs, "pwg-raster-document-type-supported", IPP_TAG_ZERO)) ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-type-supported", (int)(sizeof(pwg_raster_document_type_supported) / sizeof(pwg_raster_document_type_supported[0])), NULL, pwg_raster_document_type_supported); } /* reference-uri-scheme-supported */ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_URISCHEME), "reference-uri-schemes-supported", (int)(sizeof(reference_uri_schemes_supported) / sizeof(reference_uri_schemes_supported[0])), NULL, reference_uri_schemes_supported); /* sides-default */ if (!ippFindAttribute(printer->attrs, "sides-default", IPP_TAG_ZERO)) ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-default", NULL, "one-sided"); /* sides-supported */ if (!ippFindAttribute(printer->attrs, "sides-supported", IPP_TAG_ZERO)) ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-supported", duplex ? 3 : 1, NULL, sides_supported); /* urf-supported */ for (i = 0; i < num_formats; i ++) if (!strcasecmp(formats[i], "image/urf")) break; if (i < num_formats && !ippFindAttribute(printer->attrs, "urf-supported", IPP_TAG_ZERO)) ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "urf-supported", (int)(sizeof(urf_supported) / sizeof(urf_supported[0])) - !duplex, NULL, urf_supported); /* uri-authentication-supported */ #ifdef HAVE_SSL ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-authentication-supported", 2, NULL, uri_authentication_supported); #else ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-authentication-supported", NULL, "none"); #endif /* HAVE_SSL */ /* uri-security-supported */ #ifdef HAVE_SSL ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-security-supported", 2, NULL, uri_security_supported); #else ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-security-supported", NULL, "none"); #endif /* HAVE_SSL */ /* which-jobs-supported */ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "which-jobs-supported", sizeof(which_jobs) / sizeof(which_jobs[0]), NULL, which_jobs); free(formats[0]); debug_attributes("Printer", printer->attrs, 0); /* * Register the printer with Bonjour... */ if (!register_printer(printer, location, make, model, docformats, adminurl, uuid + 9, ppm_color > 0, duplex, subtype)) goto bad_printer; /* * Return it! */ return (printer); /* * If we get here we were unable to create the printer... */ bad_printer: delete_printer(printer); return (NULL); } /* * 'debug_attributes()' - Print attributes in a request or response. */ static void debug_attributes(const char *title, /* I - Title */ ipp_t *ipp, /* I - Request/response */ int type) /* I - 0 = object, 1 = request, 2 = response */ { ipp_tag_t group_tag; /* Current group */ ipp_attribute_t *attr; /* Current attribute */ char buffer[2048]; /* String buffer for value */ int major, minor; /* Version */ if (Verbosity <= 1) return; fprintf(stderr, "%s:\n", title); major = ippGetVersion(ipp, &minor); fprintf(stderr, " version=%d.%d\n", major, minor); if (type == 1) fprintf(stderr, " operation-id=%s(%04x)\n", ippOpString(ippGetOperation(ipp)), ippGetOperation(ipp)); else if (type == 2) fprintf(stderr, " status-code=%s(%04x)\n", ippErrorString(ippGetStatusCode(ipp)), ippGetStatusCode(ipp)); fprintf(stderr, " request-id=%d\n\n", ippGetRequestId(ipp)); for (attr = ippFirstAttribute(ipp), group_tag = IPP_TAG_ZERO; attr; attr = ippNextAttribute(ipp)) { if (ippGetGroupTag(attr) != group_tag) { group_tag = ippGetGroupTag(attr); fprintf(stderr, " %s\n", ippTagString(group_tag)); } if (ippGetName(attr)) { ippAttributeString(attr, buffer, sizeof(buffer)); fprintf(stderr, " %s (%s%s) %s\n", ippGetName(attr), ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr)), buffer); } } } /* * 'delete_client()' - Close the socket and free all memory used by a client * object. */ static void delete_client(_ipp_client_t *client) /* I - Client */ { if (Verbosity) fprintf(stderr, "Closing connection from %s\n", client->hostname); /* * Flush pending writes before closing... */ httpFlushWrite(client->http); /* * Free memory... */ httpClose(client->http); ippDelete(client->request); ippDelete(client->response); free(client); } /* * 'delete_job()' - Remove from the printer and free all memory used by a job * object. */ static void delete_job(_ipp_job_t *job) /* I - Job */ { if (Verbosity) fprintf(stderr, "Removing job #%d from history.\n", job->id); ippDelete(job->attrs); if (job->filename) { if (!KeepFiles) unlink(job->filename); free(job->filename); } free(job); } /* * 'delete_printer()' - Unregister, close listen sockets, and free all memory * used by a printer object. */ static void delete_printer(_ipp_printer_t *printer) /* I - Printer */ { if (printer->ipv4 >= 0) close(printer->ipv4); if (printer->ipv6 >= 0) close(printer->ipv6); #if HAVE_DNSSD if (printer->printer_ref) DNSServiceRefDeallocate(printer->printer_ref); if (printer->ipp_ref) DNSServiceRefDeallocate(printer->ipp_ref); if (printer->ipps_ref) DNSServiceRefDeallocate(printer->ipps_ref); if (printer->http_ref) DNSServiceRefDeallocate(printer->http_ref); #elif defined(HAVE_AVAHI) avahi_threaded_poll_lock(DNSSDMaster); if (printer->printer_ref) avahi_entry_group_free(printer->printer_ref); if (printer->ipp_ref) avahi_entry_group_free(printer->ipp_ref); if (printer->ipps_ref) avahi_entry_group_free(printer->ipps_ref); if (printer->http_ref) avahi_entry_group_free(printer->http_ref); avahi_threaded_poll_unlock(DNSSDMaster); #endif /* HAVE_DNSSD */ if (printer->dnssd_name) free(printer->dnssd_name); if (printer->name) free(printer->name); if (printer->icon) free(printer->icon); if (printer->command) free(printer->command); if (printer->directory) free(printer->directory); if (printer->hostname) free(printer->hostname); if (printer->uri) free(printer->uri); ippDelete(printer->attrs); cupsArrayDelete(printer->jobs); free(printer); } #ifdef HAVE_DNSSD /* * 'dnssd_callback()' - Handle Bonjour registration events. */ static void DNSSD_API dnssd_callback( DNSServiceRef sdRef, /* I - Service reference */ DNSServiceFlags flags, /* I - Status flags */ DNSServiceErrorType errorCode, /* I - Error, if any */ const char *name, /* I - Service name */ const char *regtype, /* I - Service type */ const char *domain, /* I - Domain for service */ _ipp_printer_t *printer) /* I - Printer */ { (void)sdRef; (void)flags; (void)domain; if (errorCode) { fprintf(stderr, "DNSServiceRegister for %s failed with error %d.\n", regtype, (int)errorCode); return; } else if (strcasecmp(name, printer->dnssd_name)) { if (Verbosity) fprintf(stderr, "Now using DNS-SD service name \"%s\".\n", name); /* No lock needed since only the main thread accesses/changes this */ free(printer->dnssd_name); printer->dnssd_name = strdup(name); } } #elif defined(HAVE_AVAHI) /* * 'dnssd_callback()' - Handle Bonjour registration events. */ static void dnssd_callback( AvahiEntryGroup *srv, /* I - Service */ AvahiEntryGroupState state, /* I - Registration state */ void *context) /* I - Printer */ { (void)srv; (void)state; (void)context; } /* * 'dnssd_client_cb()' - Client callback for Avahi. * * Called whenever the client or server state changes... */ static void dnssd_client_cb( AvahiClient *c, /* I - Client */ AvahiClientState state, /* I - Current state */ void *userdata) /* I - User data (unused) */ { (void)userdata; if (!c) return; switch (state) { default : fprintf(stderr, "Ignore Avahi state %d.\n", state); break; case AVAHI_CLIENT_FAILURE: if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) { fputs("Avahi server crashed, exiting.\n", stderr); exit(1); } break; } } #endif /* HAVE_DNSSD */ /* * 'dnssd_init()' - Initialize the DNS-SD service connections... */ static void dnssd_init(void) { #ifdef HAVE_DNSSD if (DNSServiceCreateConnection(&DNSSDMaster) != kDNSServiceErr_NoError) { fputs("Error: Unable to initialize Bonjour.\n", stderr); exit(1); } #elif defined(HAVE_AVAHI) int error; /* Error code, if any */ if ((DNSSDMaster = avahi_threaded_poll_new()) == NULL) { fputs("Error: Unable to initialize Bonjour.\n", stderr); exit(1); } if ((DNSSDClient = avahi_client_new(avahi_threaded_poll_get(DNSSDMaster), AVAHI_CLIENT_NO_FAIL, dnssd_client_cb, NULL, &error)) == NULL) { fputs("Error: Unable to initialize Bonjour.\n", stderr); exit(1); } avahi_threaded_poll_start(DNSSDMaster); #endif /* HAVE_DNSSD */ } /* * 'filter_cb()' - Filter printer attributes based on the requested array. */ static int /* O - 1 to copy, 0 to ignore */ filter_cb(_ipp_filter_t *filter, /* I - Filter parameters */ ipp_t *dst, /* I - Destination (unused) */ ipp_attribute_t *attr) /* I - Source attribute */ { /* * Filter attributes as needed... */ #ifndef WIN32 /* Avoid MS compiler bug */ (void)dst; #endif /* !WIN32 */ ipp_tag_t group = ippGetGroupTag(attr); const char *name = ippGetName(attr); if ((filter->group_tag != IPP_TAG_ZERO && group != filter->group_tag && group != IPP_TAG_ZERO) || !name || (!strcmp(name, "media-col-database") && !cupsArrayFind(filter->ra, (void *)name))) return (0); return (!filter->ra || cupsArrayFind(filter->ra, (void *)name) != NULL); } /* * 'find_job()' - Find a job specified in a request. */ static _ipp_job_t * /* O - Job or NULL */ find_job(_ipp_client_t *client) /* I - Client */ { ipp_attribute_t *attr; /* job-id or job-uri attribute */ _ipp_job_t key, /* Job search key */ *job; /* Matching job, if any */ if ((attr = ippFindAttribute(client->request, "job-uri", IPP_TAG_URI)) != NULL) { const char *uri = ippGetString(attr, 0, NULL); if (!strncmp(uri, client->printer->uri, client->printer->urilen) && uri[client->printer->urilen] == '/') key.id = atoi(uri + client->printer->urilen + 1); else return (NULL); } else if ((attr = ippFindAttribute(client->request, "job-id", IPP_TAG_INTEGER)) != NULL) key.id = ippGetInteger(attr, 0); _cupsRWLockRead(&(client->printer->rwlock)); job = (_ipp_job_t *)cupsArrayFind(client->printer->jobs, &key); _cupsRWUnlock(&(client->printer->rwlock)); return (job); } /* * 'get_collection()' - Get a collection value from a file. */ static ipp_t * /* O - Collection value */ get_collection(FILE *fp, /* I - File to read from */ const char *filename, /* I - Attributes filename */ int *linenum) /* IO - Line number */ { char token[1024], /* Token from file */ attr[128]; /* Attribute name */ ipp_tag_t value; /* Current value type */ ipp_t *col = ippNew(); /* Collection value */ ipp_attribute_t *lastcol = NULL; /* Last collection attribute */ while (get_token(fp, token, sizeof(token), linenum) != NULL) { if (!strcmp(token, "}")) break; else if (!strcmp(token, "{") && lastcol) { /* * Another collection value */ ipp_t *subcol = get_collection(fp, filename, linenum); /* Collection value */ if (subcol) ippSetCollection(col, &lastcol, ippGetCount(lastcol), subcol); else goto col_error; } else if (!_cups_strcasecmp(token, "MEMBER")) { /* * Attribute... */ lastcol = NULL; if (!get_token(fp, token, sizeof(token), linenum)) { fprintf(stderr, "ippserver: Missing MEMBER value tag on line %d of \"%s\".\n", *linenum, filename); goto col_error; } if ((value = ippTagValue(token)) == IPP_TAG_ZERO) { fprintf(stderr, "ippserver: Bad MEMBER value tag \"%s\" on line %d of \"%s\".\n", token, *linenum, filename); goto col_error; } if (!get_token(fp, attr, sizeof(attr), linenum)) { fprintf(stderr, "ippserver: Missing MEMBER name on line %d of \"%s\".\n", *linenum, filename); goto col_error; } if (!get_token(fp, token, sizeof(token), linenum)) { fprintf(stderr, "ippserver: Missing MEMBER value on line %d of \"%s\".\n", *linenum, filename); goto col_error; } switch (value) { case IPP_TAG_BOOLEAN : if (!_cups_strcasecmp(token, "true")) ippAddBoolean(col, IPP_TAG_ZERO, attr, 1); else ippAddBoolean(col, IPP_TAG_ZERO, attr, (char)atoi(token)); break; case IPP_TAG_INTEGER : case IPP_TAG_ENUM : ippAddInteger(col, IPP_TAG_ZERO, value, attr, atoi(token)); break; case IPP_TAG_RESOLUTION : { int xres, /* X resolution */ yres; /* Y resolution */ char units[6]; /* Units */ if (sscanf(token, "%dx%d%5s", &xres, &yres, units) != 3 || (_cups_strcasecmp(units, "dpi") && _cups_strcasecmp(units, "dpc") && _cups_strcasecmp(units, "dpcm") && _cups_strcasecmp(units, "other"))) { fprintf(stderr, "ippserver: Bad resolution value \"%s\" on line %d of \"%s\".\n", token, *linenum, filename); goto col_error; } if (!_cups_strcasecmp(units, "dpi")) ippAddResolution(col, IPP_TAG_ZERO, attr, IPP_RES_PER_INCH, xres, yres); else if (!_cups_strcasecmp(units, "dpc") || !_cups_strcasecmp(units, "dpcm")) ippAddResolution(col, IPP_TAG_ZERO, attr, IPP_RES_PER_CM, xres, yres); else ippAddResolution(col, IPP_TAG_ZERO, attr, (ipp_res_t)0, xres, yres); } break; case IPP_TAG_RANGE : { int lowers[4], /* Lower value */ uppers[4], /* Upper values */ num_vals; /* Number of values */ num_vals = sscanf(token, "%d-%d,%d-%d,%d-%d,%d-%d", lowers + 0, uppers + 0, lowers + 1, uppers + 1, lowers + 2, uppers + 2, lowers + 3, uppers + 3); if ((num_vals & 1) || num_vals == 0) { fprintf(stderr, "ippserver: Bad rangeOfInteger value \"%s\" on line %d of \"%s\".\n", token, *linenum, filename); goto col_error; } ippAddRanges(col, IPP_TAG_ZERO, attr, num_vals / 2, lowers, uppers); } break; case IPP_TAG_BEGIN_COLLECTION : if (!strcmp(token, "{")) { ipp_t *subcol = get_collection(fp, filename, linenum); /* Collection value */ if (subcol) { lastcol = ippAddCollection(col, IPP_TAG_ZERO, attr, subcol); ippDelete(subcol); } else goto col_error; } else { fprintf(stderr, "ippserver: Bad collection value on line %d of \"%s\".\n", *linenum, filename); goto col_error; } break; case IPP_TAG_STRING : ippAddOctetString(col, IPP_TAG_ZERO, attr, token, (int)strlen(token)); break; default : if (!strchr(token, ',')) ippAddString(col, IPP_TAG_ZERO, value, attr, NULL, token); else { /* * Multiple string values... */ int num_values; /* Number of values */ char *values[100], /* Values */ *ptr; /* Pointer to next value */ values[0] = token; num_values = 1; for (ptr = strchr(token, ','); ptr; ptr = strchr(ptr, ',')) { *ptr++ = '\0'; values[num_values] = ptr; num_values ++; if (num_values >= (int)(sizeof(values) / sizeof(values[0]))) break; } ippAddStrings(col, IPP_TAG_ZERO, value, attr, num_values, NULL, (const char **)values); } break; } } } return (col); /* * If we get here there was a parse error; free memory and return. */ col_error: ippDelete(col); return (NULL); } /* * 'get_token()' - Get a token from a file. */ static char * /* O - Token from file or NULL on EOF */ get_token(FILE *fp, /* I - File to read from */ char *buf, /* I - Buffer to read into */ int buflen, /* I - Length of buffer */ int *linenum) /* IO - Current line number */ { int ch, /* Character from file */ quote; /* Quoting character */ char *bufptr, /* Pointer into buffer */ *bufend; /* End of buffer */ for (;;) { /* * Skip whitespace... */ while (isspace(ch = getc(fp))) { if (ch == '\n') (*linenum) ++; } /* * Read a token... */ if (ch == EOF) return (NULL); else if (ch == '\'' || ch == '\"') { /* * Quoted text or regular expression... */ quote = ch; bufptr = buf; bufend = buf + buflen - 1; while ((ch = getc(fp)) != EOF) { if (ch == '\\') { /* * Escape next character... */ if (bufptr < bufend) *bufptr++ = (char)ch; if ((ch = getc(fp)) != EOF && bufptr < bufend) *bufptr++ = (char)ch; } else if (ch == quote) break; else if (bufptr < bufend) *bufptr++ = (char)ch; } *bufptr = '\0'; return (buf); } else if (ch == '#') { /* * Comment... */ while ((ch = getc(fp)) != EOF) if (ch == '\n') break; (*linenum) ++; } else if (ch == '{' || ch == '}' || ch == ',') { buf[0] = (char)ch; buf[1] = '\0'; return (buf); } else { /* * Whitespace delimited text... */ ungetc(ch, fp); bufptr = buf; bufend = buf + buflen - 1; while ((ch = getc(fp)) != EOF) if (isspace(ch) || ch == '#') break; else if (bufptr < bufend) *bufptr++ = (char)ch; if (ch == '#') ungetc(ch, fp); else if (ch == '\n') (*linenum) ++; *bufptr = '\0'; return (buf); } } } /* * 'html_escape()' - Write a HTML-safe string. */ static void html_escape(_ipp_client_t *client, /* I - Client */ const char *s, /* I - String to write */ size_t slen) /* I - Number of characters to write */ { const char *start, /* Start of segment */ *end; /* End of string */ start = s; end = s + (slen > 0 ? slen : strlen(s)); while (*s && s < end) { if (*s == '&' || *s == '<') { if (s > start) httpWrite2(client->http, start, (size_t)(s - start)); if (*s == '&') httpWrite2(client->http, "&", 5); else httpWrite2(client->http, "<", 4); start = s + 1; } s ++; } if (s > start) httpWrite2(client->http, start, (size_t)(s - start)); } /* * 'html_footer()' - Show the web interface footer. * * This function also writes the trailing 0-length chunk. */ static void html_footer(_ipp_client_t *client) /* I - Client */ { html_printf(client, "\n" "\n" "\n"); httpWrite2(client->http, "", 0); } /* * 'html_header()' - Show the web interface header and title. */ static void html_header(_ipp_client_t *client, /* I - Client */ const char *title) /* I - Title */ { html_printf(client, "\n" "\n" "\n" "%s\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "" "" "" "" "
StatusSuppliesMedia
\n" "
\n", title, !strcmp(client->uri, "/") ? " sel" : "", !strcmp(client->uri, "/supplies") ? " sel" : "", !strcmp(client->uri, "/media") ? " sel" : ""); } /* * 'html_printf()' - Send formatted text to the client, quoting as needed. */ static void html_printf(_ipp_client_t *client, /* I - Client */ const char *format, /* I - Printf-style format string */ ...) /* I - Additional arguments as needed */ { va_list ap; /* Pointer to arguments */ const char *start; /* Start of string */ char size, /* Size character (h, l, L) */ type; /* Format type character */ int width, /* Width of field */ prec; /* Number of characters of precision */ char tformat[100], /* Temporary format string for sprintf() */ *tptr, /* Pointer into temporary format */ temp[1024]; /* Buffer for formatted numbers */ char *s; /* Pointer to string */ /* * Loop through the format string, formatting as needed... */ va_start(ap, format); start = format; while (*format) { if (*format == '%') { if (format > start) httpWrite2(client->http, start, (size_t)(format - start)); tptr = tformat; *tptr++ = *format++; if (*format == '%') { httpWrite2(client->http, "%", 1); format ++; start = format; continue; } else if (strchr(" -+#\'", *format)) *tptr++ = *format++; if (*format == '*') { /* * Get width from argument... */ format ++; width = va_arg(ap, int); snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", width); tptr += strlen(tptr); } else { width = 0; while (isdigit(*format & 255)) { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; width = width * 10 + *format++ - '0'; } } if (*format == '.') { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; format ++; if (*format == '*') { /* * Get precision from argument... */ format ++; prec = va_arg(ap, int); snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", prec); tptr += strlen(tptr); } else { prec = 0; while (isdigit(*format & 255)) { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; prec = prec * 10 + *format++ - '0'; } } } if (*format == 'l' && format[1] == 'l') { size = 'L'; if (tptr < (tformat + sizeof(tformat) - 2)) { *tptr++ = 'l'; *tptr++ = 'l'; } format += 2; } else if (*format == 'h' || *format == 'l' || *format == 'L') { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; size = *format++; } else size = 0; if (!*format) { start = format; break; } if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; type = *format++; *tptr = '\0'; start = format; switch (type) { case 'E' : /* Floating point formats */ case 'G' : case 'e' : case 'f' : case 'g' : if ((size_t)(width + 2) > sizeof(temp)) break; sprintf(temp, tformat, va_arg(ap, double)); httpWrite2(client->http, temp, strlen(temp)); break; case 'B' : /* Integer formats */ case 'X' : case 'b' : case 'd' : case 'i' : case 'o' : case 'u' : case 'x' : if ((size_t)(width + 2) > sizeof(temp)) break; # ifdef HAVE_LONG_LONG if (size == 'L') sprintf(temp, tformat, va_arg(ap, long long)); else # endif /* HAVE_LONG_LONG */ if (size == 'l') sprintf(temp, tformat, va_arg(ap, long)); else sprintf(temp, tformat, va_arg(ap, int)); httpWrite2(client->http, temp, strlen(temp)); break; case 'p' : /* Pointer value */ if ((size_t)(width + 2) > sizeof(temp)) break; sprintf(temp, tformat, va_arg(ap, void *)); httpWrite2(client->http, temp, strlen(temp)); break; case 'c' : /* Character or character array */ if (width <= 1) { temp[0] = (char)va_arg(ap, int); temp[1] = '\0'; html_escape(client, temp, 1); } else html_escape(client, va_arg(ap, char *), (size_t)width); break; case 's' : /* String */ if ((s = va_arg(ap, char *)) == NULL) s = "(null)"; html_escape(client, s, strlen(s)); break; } } else format ++; } if (format > start) httpWrite2(client->http, start, (size_t)(format - start)); va_end(ap); } /* * 'ipp_cancel_job()' - Cancel a job. */ static void ipp_cancel_job(_ipp_client_t *client) /* I - Client */ { _ipp_job_t *job; /* Job information */ /* * Get the job... */ if ((job = find_job(client)) == NULL) { respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); return; } /* * See if the job is already completed, canceled, or aborted; if so, * we can't cancel... */ switch (job->state) { case IPP_JSTATE_CANCELED : respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job #%d is already canceled - can\'t cancel.", job->id); break; case IPP_JSTATE_ABORTED : respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job #%d is already aborted - can\'t cancel.", job->id); break; case IPP_JSTATE_COMPLETED : respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job #%d is already completed - can\'t cancel.", job->id); break; default : /* * Cancel the job... */ _cupsRWLockWrite(&(client->printer->rwlock)); if (job->state == IPP_JSTATE_PROCESSING || (job->state == IPP_JSTATE_HELD && job->fd >= 0)) job->cancel = 1; else { job->state = IPP_JSTATE_CANCELED; job->completed = time(NULL); } _cupsRWUnlock(&(client->printer->rwlock)); respond_ipp(client, IPP_STATUS_OK, NULL); break; } } /* * 'ipp_close_job()' - Close an open job. */ static void ipp_close_job(_ipp_client_t *client) /* I - Client */ { _ipp_job_t *job; /* Job information */ /* * Get the job... */ if ((job = find_job(client)) == NULL) { respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); return; } /* * See if the job is already completed, canceled, or aborted; if so, * we can't cancel... */ switch (job->state) { case IPP_JSTATE_CANCELED : respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job #%d is canceled - can\'t close.", job->id); break; case IPP_JSTATE_ABORTED : respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job #%d is aborted - can\'t close.", job->id); break; case IPP_JSTATE_COMPLETED : respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job #%d is completed - can\'t close.", job->id); break; case IPP_JSTATE_PROCESSING : case IPP_JSTATE_STOPPED : respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job #%d is already closed.", job->id); break; default : respond_ipp(client, IPP_STATUS_OK, NULL); break; } } /* * 'ipp_create_job()' - Create a job object. */ static void ipp_create_job(_ipp_client_t *client) /* I - Client */ { _ipp_job_t *job; /* New job */ cups_array_t *ra; /* Attributes to send in response */ /* * Validate print job attributes... */ if (!valid_job_attributes(client)) { httpFlush(client->http); return; } /* * Do we have a file to print? */ if (httpGetState(client->http) == HTTP_STATE_POST_RECV) { respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Unexpected document data following request."); return; } /* * Create the job... */ if ((job = create_job(client)) == NULL) { respond_ipp(client, IPP_STATUS_ERROR_BUSY, "Currently printing another job."); return; } /* * Return the job info... */ respond_ipp(client, IPP_STATUS_OK, NULL); ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); cupsArrayAdd(ra, "job-id"); cupsArrayAdd(ra, "job-state"); cupsArrayAdd(ra, "job-state-message"); cupsArrayAdd(ra, "job-state-reasons"); cupsArrayAdd(ra, "job-uri"); copy_job_attributes(client, job, ra); cupsArrayDelete(ra); } /* * 'ipp_get_job_attributes()' - Get the attributes for a job object. */ static void ipp_get_job_attributes( _ipp_client_t *client) /* I - Client */ { _ipp_job_t *job; /* Job */ cups_array_t *ra; /* requested-attributes */ if ((job = find_job(client)) == NULL) { respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job not found."); return; } respond_ipp(client, IPP_STATUS_OK, NULL); ra = ippCreateRequestedArray(client->request); copy_job_attributes(client, job, ra); cupsArrayDelete(ra); } /* * 'ipp_get_jobs()' - Get a list of job objects. */ static void ipp_get_jobs(_ipp_client_t *client) /* I - Client */ { ipp_attribute_t *attr; /* Current attribute */ const char *which_jobs = NULL; /* which-jobs values */ int job_comparison; /* Job comparison */ ipp_jstate_t job_state; /* job-state value */ int first_job_id, /* First job ID */ limit, /* Maximum number of jobs to return */ count; /* Number of jobs that match */ const char *username; /* Username */ _ipp_job_t *job; /* Current job pointer */ cups_array_t *ra; /* Requested attributes array */ /* * See if the "which-jobs" attribute have been specified... */ if ((attr = ippFindAttribute(client->request, "which-jobs", IPP_TAG_KEYWORD)) != NULL) { which_jobs = ippGetString(attr, 0, NULL); fprintf(stderr, "%s Get-Jobs which-jobs=%s", client->hostname, which_jobs); } if (!which_jobs || !strcmp(which_jobs, "not-completed")) { job_comparison = -1; job_state = IPP_JSTATE_STOPPED; } else if (!strcmp(which_jobs, "completed")) { job_comparison = 1; job_state = IPP_JSTATE_CANCELED; } else if (!strcmp(which_jobs, "aborted")) { job_comparison = 0; job_state = IPP_JSTATE_ABORTED; } else if (!strcmp(which_jobs, "all")) { job_comparison = 1; job_state = IPP_JSTATE_PENDING; } else if (!strcmp(which_jobs, "canceled")) { job_comparison = 0; job_state = IPP_JSTATE_CANCELED; } else if (!strcmp(which_jobs, "pending")) { job_comparison = 0; job_state = IPP_JSTATE_PENDING; } else if (!strcmp(which_jobs, "pending-held")) { job_comparison = 0; job_state = IPP_JSTATE_HELD; } else if (!strcmp(which_jobs, "processing")) { job_comparison = 0; job_state = IPP_JSTATE_PROCESSING; } else if (!strcmp(which_jobs, "processing-stopped")) { job_comparison = 0; job_state = IPP_JSTATE_STOPPED; } else { respond_ipp(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, "The which-jobs value \"%s\" is not supported.", which_jobs); ippAddString(client->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, "which-jobs", NULL, which_jobs); return; } /* * See if they want to limit the number of jobs reported... */ if ((attr = ippFindAttribute(client->request, "limit", IPP_TAG_INTEGER)) != NULL) { limit = ippGetInteger(attr, 0); fprintf(stderr, "%s Get-Jobs limit=%d", client->hostname, limit); } else limit = 0; if ((attr = ippFindAttribute(client->request, "first-job-id", IPP_TAG_INTEGER)) != NULL) { first_job_id = ippGetInteger(attr, 0); fprintf(stderr, "%s Get-Jobs first-job-id=%d", client->hostname, first_job_id); } else first_job_id = 1; /* * See if we only want to see jobs for a specific user... */ username = NULL; if ((attr = ippFindAttribute(client->request, "my-jobs", IPP_TAG_BOOLEAN)) != NULL) { int my_jobs = ippGetBoolean(attr, 0); fprintf(stderr, "%s Get-Jobs my-jobs=%s\n", client->hostname, my_jobs ? "true" : "false"); if (my_jobs) { if ((attr = ippFindAttribute(client->request, "requesting-user-name", IPP_TAG_NAME)) == NULL) { respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Need requesting-user-name with my-jobs."); return; } username = ippGetString(attr, 0, NULL); fprintf(stderr, "%s Get-Jobs requesting-user-name=\"%s\"\n", client->hostname, username); } } /* * OK, build a list of jobs for this printer... */ ra = ippCreateRequestedArray(client->request); respond_ipp(client, IPP_STATUS_OK, NULL); _cupsRWLockRead(&(client->printer->rwlock)); for (count = 0, job = (_ipp_job_t *)cupsArrayFirst(client->printer->jobs); (limit <= 0 || count < limit) && job; job = (_ipp_job_t *)cupsArrayNext(client->printer->jobs)) { /* * Filter out jobs that don't match... */ if ((job_comparison < 0 && job->state > job_state) || (job_comparison == 0 && job->state != job_state) || (job_comparison > 0 && job->state < job_state) || job->id < first_job_id || (username && job->username && strcasecmp(username, job->username))) continue; if (count > 0) ippAddSeparator(client->response); count ++; copy_job_attributes(client, job, ra); } cupsArrayDelete(ra); _cupsRWUnlock(&(client->printer->rwlock)); } /* * 'ipp_get_printer_attributes()' - Get the attributes for a printer object. */ static void ipp_get_printer_attributes( _ipp_client_t *client) /* I - Client */ { cups_array_t *ra; /* Requested attributes array */ _ipp_printer_t *printer; /* Printer */ /* * Send the attributes... */ ra = ippCreateRequestedArray(client->request); printer = client->printer; respond_ipp(client, IPP_STATUS_OK, NULL); _cupsRWLockRead(&(printer->rwlock)); copy_attributes(client->response, printer->attrs, ra, IPP_TAG_ZERO, IPP_TAG_CUPS_CONST); if (!ra || cupsArrayFind(ra, "media-col-ready")) { int i, /* Looping var */ num_ready = 0; /* Number of ready media */ ipp_t *ready[3]; /* Ready media */ if (printer->main_size != _IPP_MEDIA_SIZE_NONE) { if (printer->main_type != _IPP_MEDIA_TYPE_NONE) ready[num_ready ++] = create_media_col(media_supported[printer->main_size], "main", media_type_supported[printer->main_type], media_col_sizes[printer->main_size][0], media_col_sizes[printer->main_size][1], 635); else ready[num_ready ++] = create_media_col(media_supported[printer->main_size], "main", NULL, media_col_sizes[printer->main_size][0], media_col_sizes[printer->main_size][1], 635); } if (printer->envelope_size != _IPP_MEDIA_SIZE_NONE) ready[num_ready ++] = create_media_col(media_supported[printer->envelope_size], "envelope", NULL, media_col_sizes[printer->envelope_size][0], media_col_sizes[printer->envelope_size][1], 635); if (printer->photo_size != _IPP_MEDIA_SIZE_NONE) { if (printer->photo_type != _IPP_MEDIA_TYPE_NONE) ready[num_ready ++] = create_media_col(media_supported[printer->photo_size], "photo", media_type_supported[printer->photo_type], media_col_sizes[printer->photo_size][0], media_col_sizes[printer->photo_size][1], 0); else ready[num_ready ++] = create_media_col(media_supported[printer->photo_size], "photo", NULL, media_col_sizes[printer->photo_size][0], media_col_sizes[printer->photo_size][1], 0); } if (num_ready) { ippAddCollections(client->response, IPP_TAG_PRINTER, "media-col-ready", num_ready, (const ipp_t **)ready); for (i = 0; i < num_ready; i ++) ippDelete(ready[i]); } else ippAddOutOfBand(client->response, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "media-col-ready"); } if (!ra || cupsArrayFind(ra, "media-ready")) { int num_ready = 0; /* Number of ready media */ const char *ready[3]; /* Ready media */ if (printer->main_size != _IPP_MEDIA_SIZE_NONE) ready[num_ready ++] = media_supported[printer->main_size]; if (printer->envelope_size != _IPP_MEDIA_SIZE_NONE) ready[num_ready ++] = media_supported[printer->envelope_size]; if (printer->photo_size != _IPP_MEDIA_SIZE_NONE) ready[num_ready ++] = media_supported[printer->photo_size]; if (num_ready) ippAddStrings(client->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-ready", num_ready, NULL, ready); else ippAddOutOfBand(client->response, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "media-ready"); } if (!ra || cupsArrayFind(ra, "printer-config-change-date-time")) ippAddDate(client->response, IPP_TAG_PRINTER, "printer-config-change-date-time", ippTimeToDate(printer->config_time)); if (!ra || cupsArrayFind(ra, "printer-config-change-time")) ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-config-change-time", (int)(printer->config_time - printer->start_time)); if (!ra || cupsArrayFind(ra, "printer-current-time")) ippAddDate(client->response, IPP_TAG_PRINTER, "printer-current-time", ippTimeToDate(time(NULL))); if (!ra || cupsArrayFind(ra, "printer-state")) ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", printer->state); if (!ra || cupsArrayFind(ra, "printer-state-change-date-time")) ippAddDate(client->response, IPP_TAG_PRINTER, "printer-state-change-date-time", ippTimeToDate(printer->state_time)); if (!ra || cupsArrayFind(ra, "printer-state-change-time")) ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-state-change-time", (int)(printer->state_time - printer->start_time)); if (!ra || cupsArrayFind(ra, "printer-state-message")) { static const char * const messages[] = { "Idle.", "Printing.", "Stopped." }; ippAddString(client->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-state-message", NULL, messages[printer->state - IPP_PSTATE_IDLE]); } if (!ra || cupsArrayFind(ra, "printer-state-reasons")) { if (printer->state_reasons == _IPP_PREASON_NONE) ippAddString(client->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "printer-state-reasons", NULL, "none"); else { ipp_attribute_t *attr = NULL; /* printer-state-reasons */ _ipp_preason_t bit; /* Reason bit */ int i; /* Looping var */ char reason[32]; /* Reason string */ for (i = 0, bit = 1; i < (int)(sizeof(_ipp_preason_strings) / sizeof(_ipp_preason_strings[0])); i ++, bit *= 2) { if (printer->state_reasons & bit) { snprintf(reason, sizeof(reason), "%s-%s", _ipp_preason_strings[i], printer->state == IPP_PSTATE_IDLE ? "report" : printer->state == IPP_PSTATE_PROCESSING ? "warning" : "error"); if (attr) ippSetString(client->response, &attr, ippGetCount(attr), reason); else attr = ippAddString(client->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "printer-state-reasons", NULL, reason); } } } } if (!ra || cupsArrayFind(ra, "printer-supply")) { int i; /* Looping var */ char buffer[256]; /* Supply value buffer */ ipp_attribute_t *attr = NULL; /* Attribute */ static const char * const colorants[] = { "cyan", "magenta", "yellow", "black", "unknown" }; for (i = 0; i < 5; i ++) { snprintf(buffer, sizeof(buffer), "index=%d;class=%s;type=%s;unit=percent;maxcapacity=100;level=%d;colorantname=%s;", i + 1, i < 4 ? "supplyThatIsConsumed" : "receptacleThatIsFilled", i < 4 ? "toner" : "wasteToner", printer->supplies[i], colorants[i]); if (!attr) attr = ippAddOctetString(client->response, IPP_TAG_PRINTER, "printer-supply", buffer, (int)strlen(buffer)); else ippSetOctetString(client->response, &attr, i, buffer, (int)strlen(buffer)); } } if (!ra || cupsArrayFind(ra, "printer-up-time")) ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-up-time", (int)(time(NULL) - printer->start_time)); if (!ra || cupsArrayFind(ra, "queued-job-count")) ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "queued-job-count", printer->active_job && printer->active_job->state < IPP_JSTATE_CANCELED); _cupsRWUnlock(&(printer->rwlock)); cupsArrayDelete(ra); } /* * 'ipp_identify_printer()' - Beep or display a message. */ static void ipp_identify_printer( _ipp_client_t *client) /* I - Client */ { ipp_attribute_t *actions, /* identify-actions */ *message; /* message */ actions = ippFindAttribute(client->request, "identify-actions", IPP_TAG_KEYWORD); message = ippFindAttribute(client->request, "message", IPP_TAG_TEXT); if (!actions || ippContainsString(actions, "sound")) { putchar(0x07); fflush(stdout); } if (ippContainsString(actions, "display")) printf("IDENTIFY from %s: %s\n", client->hostname, message ? ippGetString(message, 0, NULL) : "No message supplied"); respond_ipp(client, IPP_STATUS_OK, NULL); } /* * 'ipp_print_job()' - Create a job object with an attached document. */ static void ipp_print_job(_ipp_client_t *client) /* I - Client */ { _ipp_job_t *job; /* New job */ char filename[1024], /* Filename buffer */ buffer[4096]; /* Copy buffer */ ssize_t bytes; /* Bytes read */ cups_array_t *ra; /* Attributes to send in response */ _cups_thread_t t; /* Thread */ /* * Validate print job attributes... */ if (!valid_job_attributes(client)) { httpFlush(client->http); return; } /* * Do we have a file to print? */ if (httpGetState(client->http) == HTTP_STATE_POST_SEND) { respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "No file in request."); return; } /* * Print the job... */ if ((job = create_job(client)) == NULL) { respond_ipp(client, IPP_STATUS_ERROR_BUSY, "Currently printing another job."); return; } /* * Create a file for the request data... */ create_job_filename(client->printer, job, filename, sizeof(filename)); if (Verbosity) fprintf(stderr, "Creating job file \"%s\", format \"%s\".\n", filename, job->format); if ((job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { job->state = IPP_JSTATE_ABORTED; respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to create print file: %s", strerror(errno)); return; } while ((bytes = httpRead2(client->http, buffer, sizeof(buffer))) > 0) { if (write(job->fd, buffer, (size_t)bytes) < bytes) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } } if (bytes < 0) { /* * Got an error while reading the print data, so abort this job. */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to read print file."); return; } if (close(job->fd)) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; job->fd = -1; unlink(filename); respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } job->fd = -1; job->filename = strdup(filename); job->state = IPP_JSTATE_PENDING; /* * Process the job... */ t = _cupsThreadCreate((_cups_thread_func_t)process_job, job); if (t) { _cupsThreadDetach(t); } else { job->state = IPP_JSTATE_ABORTED; respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to process job."); return; } /* * Return the job info... */ respond_ipp(client, IPP_STATUS_OK, NULL); ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); cupsArrayAdd(ra, "job-id"); cupsArrayAdd(ra, "job-state"); cupsArrayAdd(ra, "job-state-message"); cupsArrayAdd(ra, "job-state-reasons"); cupsArrayAdd(ra, "job-uri"); copy_job_attributes(client, job, ra); cupsArrayDelete(ra); } /* * 'ipp_print_uri()' - Create a job object with a referenced document. */ static void ipp_print_uri(_ipp_client_t *client) /* I - Client */ { _ipp_job_t *job; /* New job */ ipp_attribute_t *uri; /* document-uri */ char scheme[256], /* URI scheme */ userpass[256], /* Username and password info */ hostname[256], /* Hostname */ resource[1024]; /* Resource path */ int port; /* Port number */ http_uri_status_t uri_status; /* URI decode status */ http_encryption_t encryption; /* Encryption to use, if any */ http_t *http; /* Connection for http/https URIs */ http_status_t status; /* Access status for http/https URIs */ int infile; /* Input file for local file URIs */ char filename[1024], /* Filename buffer */ buffer[4096]; /* Copy buffer */ ssize_t bytes; /* Bytes read */ cups_array_t *ra; /* Attributes to send in response */ static const char * const uri_status_strings[] = { /* URI decode errors */ "URI too large.", "Bad arguments to function.", "Bad resource in URI.", "Bad port number in URI.", "Bad hostname in URI.", "Bad username in URI.", "Bad scheme in URI.", "Bad/empty URI." }; /* * Validate print job attributes... */ if (!valid_job_attributes(client)) { httpFlush(client->http); return; } /* * Do we have a file to print? */ if (httpGetState(client->http) == HTTP_STATE_POST_RECV) { respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Unexpected document data following request."); return; } /* * Do we have a document URI? */ if ((uri = ippFindAttribute(client->request, "document-uri", IPP_TAG_URI)) == NULL) { respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing document-uri."); return; } if (ippGetCount(uri) != 1) { respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Too many document-uri values."); return; } uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL), scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)); if (uri_status < HTTP_URI_STATUS_OK) { respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad document-uri: %s", uri_status_strings[uri_status - HTTP_URI_STATUS_OVERFLOW]); return; } if (strcmp(scheme, "file") && #ifdef HAVE_SSL strcmp(scheme, "https") && #endif /* HAVE_SSL */ strcmp(scheme, "http")) { respond_ipp(client, IPP_STATUS_ERROR_URI_SCHEME, "URI scheme \"%s\" not supported.", scheme); return; } if (!strcmp(scheme, "file") && access(resource, R_OK)) { respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to access URI: %s", strerror(errno)); return; } /* * Print the job... */ if ((job = create_job(client)) == NULL) { respond_ipp(client, IPP_STATUS_ERROR_BUSY, "Currently printing another job."); return; } /* * Create a file for the request data... */ if (!strcasecmp(job->format, "image/jpeg")) snprintf(filename, sizeof(filename), "%s/%d.jpg", client->printer->directory, job->id); else if (!strcasecmp(job->format, "image/png")) snprintf(filename, sizeof(filename), "%s/%d.png", client->printer->directory, job->id); else if (!strcasecmp(job->format, "application/pdf")) snprintf(filename, sizeof(filename), "%s/%d.pdf", client->printer->directory, job->id); else if (!strcasecmp(job->format, "application/postscript")) snprintf(filename, sizeof(filename), "%s/%d.ps", client->printer->directory, job->id); else snprintf(filename, sizeof(filename), "%s/%d.prn", client->printer->directory, job->id); if ((job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { job->state = IPP_JSTATE_ABORTED; respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to create print file: %s", strerror(errno)); return; } if (!strcmp(scheme, "file")) { if ((infile = open(resource, O_RDONLY)) < 0) { respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to access URI: %s", strerror(errno)); return; } do { if ((bytes = read(infile, buffer, sizeof(buffer))) < 0 && (errno == EAGAIN || errno == EINTR)) bytes = 1; else if (bytes > 0 && write(job->fd, buffer, (size_t)bytes) < bytes) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); close(infile); respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } } while (bytes > 0); close(infile); } else { #ifdef HAVE_SSL if (port == 443 || !strcmp(scheme, "https")) encryption = HTTP_ENCRYPTION_ALWAYS; else #endif /* HAVE_SSL */ encryption = HTTP_ENCRYPTION_IF_REQUESTED; if ((http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL) { respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to connect to %s: %s", hostname, cupsLastErrorString()); job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); return; } httpClearFields(http); httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); if (httpGet(http, resource)) { respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to GET URI: %s", strerror(errno)); job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); httpClose(http); return; } while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); if (status != HTTP_STATUS_OK) { respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to GET URI: %s", httpStatus(status)); job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); httpClose(http); return; } while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) { if (write(job->fd, buffer, (size_t)bytes) < bytes) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); httpClose(http); respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } } httpClose(http); } if (close(job->fd)) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; job->fd = -1; unlink(filename); respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } job->fd = -1; job->filename = strdup(filename); job->state = IPP_JSTATE_PENDING; /* * Process the job... */ process_job(job); /* * Return the job info... */ respond_ipp(client, IPP_STATUS_OK, NULL); ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); cupsArrayAdd(ra, "job-id"); cupsArrayAdd(ra, "job-state"); cupsArrayAdd(ra, "job-state-reasons"); cupsArrayAdd(ra, "job-uri"); copy_job_attributes(client, job, ra); cupsArrayDelete(ra); } /* * 'ipp_send_document()' - Add an attached document to a job object created with * Create-Job. */ static void ipp_send_document(_ipp_client_t *client)/* I - Client */ { _ipp_job_t *job; /* Job information */ char filename[1024], /* Filename buffer */ buffer[4096]; /* Copy buffer */ ssize_t bytes; /* Bytes read */ ipp_attribute_t *attr; /* Current attribute */ cups_array_t *ra; /* Attributes to send in response */ /* * Get the job... */ if ((job = find_job(client)) == NULL) { respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); httpFlush(client->http); return; } /* * See if we already have a document for this job or the job has already * in a non-pending state... */ if (job->state > IPP_JSTATE_HELD) { respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job is not in a pending state."); httpFlush(client->http); return; } else if (job->filename || job->fd >= 0) { respond_ipp(client, IPP_STATUS_ERROR_MULTIPLE_JOBS_NOT_SUPPORTED, "Multiple document jobs are not supported."); httpFlush(client->http); return; } if ((attr = ippFindAttribute(client->request, "last-document", IPP_TAG_ZERO)) == NULL) { respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing required last-document attribute."); httpFlush(client->http); return; } else if (ippGetValueTag(attr) != IPP_TAG_BOOLEAN || ippGetCount(attr) != 1 || !ippGetBoolean(attr, 0)) { respond_unsupported(client, attr); httpFlush(client->http); return; } /* * Validate document attributes... */ if (!valid_doc_attributes(client)) { httpFlush(client->http); return; } copy_attributes(job->attrs, client->request, NULL, IPP_TAG_JOB, 0); /* * Get the document format for the job... */ _cupsRWLockWrite(&(client->printer->rwlock)); if ((attr = ippFindAttribute(job->attrs, "document-format-detected", IPP_TAG_MIMETYPE)) != NULL) job->format = ippGetString(attr, 0, NULL); else if ((attr = ippFindAttribute(job->attrs, "document-format-supplied", IPP_TAG_MIMETYPE)) != NULL) job->format = ippGetString(attr, 0, NULL); else job->format = "application/octet-stream"; /* * Create a file for the request data... */ create_job_filename(client->printer, job, filename, sizeof(filename)); if (Verbosity) fprintf(stderr, "Creating job file \"%s\", format \"%s\".\n", filename, job->format); job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); _cupsRWUnlock(&(client->printer->rwlock)); if (job->fd < 0) { job->state = IPP_JSTATE_ABORTED; respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to create print file: %s", strerror(errno)); return; } while ((bytes = httpRead2(client->http, buffer, sizeof(buffer))) > 0) { if (write(job->fd, buffer, (size_t)bytes) < bytes) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } } if (bytes < 0) { /* * Got an error while reading the print data, so abort this job. */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to read print file."); return; } if (close(job->fd)) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; job->fd = -1; unlink(filename); respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } _cupsRWLockWrite(&(client->printer->rwlock)); job->fd = -1; job->filename = strdup(filename); job->state = IPP_JSTATE_PENDING; _cupsRWUnlock(&(client->printer->rwlock)); /* * Process the job... */ process_job(job); /* * Return the job info... */ respond_ipp(client, IPP_STATUS_OK, NULL); ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); cupsArrayAdd(ra, "job-id"); cupsArrayAdd(ra, "job-state"); cupsArrayAdd(ra, "job-state-reasons"); cupsArrayAdd(ra, "job-uri"); copy_job_attributes(client, job, ra); cupsArrayDelete(ra); } /* * 'ipp_send_uri()' - Add a referenced document to a job object created with * Create-Job. */ static void ipp_send_uri(_ipp_client_t *client) /* I - Client */ { _ipp_job_t *job; /* Job information */ ipp_attribute_t *uri; /* document-uri */ char scheme[256], /* URI scheme */ userpass[256], /* Username and password info */ hostname[256], /* Hostname */ resource[1024]; /* Resource path */ int port; /* Port number */ http_uri_status_t uri_status; /* URI decode status */ http_encryption_t encryption; /* Encryption to use, if any */ http_t *http; /* Connection for http/https URIs */ http_status_t status; /* Access status for http/https URIs */ int infile; /* Input file for local file URIs */ char filename[1024], /* Filename buffer */ buffer[4096]; /* Copy buffer */ ssize_t bytes; /* Bytes read */ ipp_attribute_t *attr; /* Current attribute */ cups_array_t *ra; /* Attributes to send in response */ static const char * const uri_status_strings[] = { /* URI decode errors */ "URI too large.", "Bad arguments to function.", "Bad resource in URI.", "Bad port number in URI.", "Bad hostname in URI.", "Bad username in URI.", "Bad scheme in URI.", "Bad/empty URI." }; /* * Get the job... */ if ((job = find_job(client)) == NULL) { respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); httpFlush(client->http); return; } /* * See if we already have a document for this job or the job has already * in a non-pending state... */ if (job->state > IPP_JSTATE_HELD) { respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job is not in a pending state."); httpFlush(client->http); return; } else if (job->filename || job->fd >= 0) { respond_ipp(client, IPP_STATUS_ERROR_MULTIPLE_JOBS_NOT_SUPPORTED, "Multiple document jobs are not supported."); httpFlush(client->http); return; } if ((attr = ippFindAttribute(client->request, "last-document", IPP_TAG_ZERO)) == NULL) { respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing required last-document attribute."); httpFlush(client->http); return; } else if (ippGetValueTag(attr) != IPP_TAG_BOOLEAN || ippGetCount(attr) != 1 || !ippGetBoolean(attr, 0)) { respond_unsupported(client, attr); httpFlush(client->http); return; } /* * Validate document attributes... */ if (!valid_doc_attributes(client)) { httpFlush(client->http); return; } /* * Do we have a file to print? */ if (httpGetState(client->http) == HTTP_STATE_POST_RECV) { respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Unexpected document data following request."); return; } /* * Do we have a document URI? */ if ((uri = ippFindAttribute(client->request, "document-uri", IPP_TAG_URI)) == NULL) { respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing document-uri."); return; } if (ippGetCount(uri) != 1) { respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Too many document-uri values."); return; } uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL), scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)); if (uri_status < HTTP_URI_STATUS_OK) { respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad document-uri: %s", uri_status_strings[uri_status - HTTP_URI_STATUS_OVERFLOW]); return; } if (strcmp(scheme, "file") && #ifdef HAVE_SSL strcmp(scheme, "https") && #endif /* HAVE_SSL */ strcmp(scheme, "http")) { respond_ipp(client, IPP_STATUS_ERROR_URI_SCHEME, "URI scheme \"%s\" not supported.", scheme); return; } if (!strcmp(scheme, "file") && access(resource, R_OK)) { respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to access URI: %s", strerror(errno)); return; } /* * Get the document format for the job... */ _cupsRWLockWrite(&(client->printer->rwlock)); if ((attr = ippFindAttribute(job->attrs, "document-format", IPP_TAG_MIMETYPE)) != NULL) job->format = ippGetString(attr, 0, NULL); else job->format = "application/octet-stream"; /* * Create a file for the request data... */ if (!strcasecmp(job->format, "image/jpeg")) snprintf(filename, sizeof(filename), "%s/%d.jpg", client->printer->directory, job->id); else if (!strcasecmp(job->format, "image/png")) snprintf(filename, sizeof(filename), "%s/%d.png", client->printer->directory, job->id); else if (!strcasecmp(job->format, "application/pdf")) snprintf(filename, sizeof(filename), "%s/%d.pdf", client->printer->directory, job->id); else if (!strcasecmp(job->format, "application/postscript")) snprintf(filename, sizeof(filename), "%s/%d.ps", client->printer->directory, job->id); else snprintf(filename, sizeof(filename), "%s/%d.prn", client->printer->directory, job->id); job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); _cupsRWUnlock(&(client->printer->rwlock)); if (job->fd < 0) { job->state = IPP_JSTATE_ABORTED; respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to create print file: %s", strerror(errno)); return; } if (!strcmp(scheme, "file")) { if ((infile = open(resource, O_RDONLY)) < 0) { respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to access URI: %s", strerror(errno)); return; } do { if ((bytes = read(infile, buffer, sizeof(buffer))) < 0 && (errno == EAGAIN || errno == EINTR)) bytes = 1; else if (bytes > 0 && write(job->fd, buffer, (size_t)bytes) < bytes) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); close(infile); respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } } while (bytes > 0); close(infile); } else { #ifdef HAVE_SSL if (port == 443 || !strcmp(scheme, "https")) encryption = HTTP_ENCRYPTION_ALWAYS; else #endif /* HAVE_SSL */ encryption = HTTP_ENCRYPTION_IF_REQUESTED; if ((http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL) { respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to connect to %s: %s", hostname, cupsLastErrorString()); job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); return; } httpClearFields(http); httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); if (httpGet(http, resource)) { respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to GET URI: %s", strerror(errno)); job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); httpClose(http); return; } while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); if (status != HTTP_STATUS_OK) { respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to GET URI: %s", httpStatus(status)); job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); httpClose(http); return; } while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) { if (write(job->fd, buffer, (size_t)bytes) < bytes) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); httpClose(http); respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } } httpClose(http); } if (close(job->fd)) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; job->fd = -1; unlink(filename); respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } _cupsRWLockWrite(&(client->printer->rwlock)); job->fd = -1; job->filename = strdup(filename); job->state = IPP_JSTATE_PENDING; _cupsRWUnlock(&(client->printer->rwlock)); /* * Process the job... */ process_job(job); /* * Return the job info... */ respond_ipp(client, IPP_STATUS_OK, NULL); ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); cupsArrayAdd(ra, "job-id"); cupsArrayAdd(ra, "job-state"); cupsArrayAdd(ra, "job-state-reasons"); cupsArrayAdd(ra, "job-uri"); copy_job_attributes(client, job, ra); cupsArrayDelete(ra); } /* * 'ipp_validate_job()' - Validate job creation attributes. */ static void ipp_validate_job(_ipp_client_t *client) /* I - Client */ { if (valid_job_attributes(client)) respond_ipp(client, IPP_STATUS_OK, NULL); } /* * 'load_attributes()' - Load printer attributes from a file. * * Syntax is based on ipptool format: * * ATTR value-tag name value */ static void load_attributes(const char *filename, /* I - File to load */ ipp_t *attrs) /* I - Printer attributes */ { int linenum = 0; /* Current line number */ FILE *fp = NULL; /* Test file */ char attr[128], /* Attribute name */ token[1024], /* Token from file */ *tokenptr; /* Pointer into token */ ipp_tag_t value; /* Current value type */ ipp_attribute_t *attrptr, /* Attribute pointer */ *lastcol = NULL; /* Last collection attribute */ if ((fp = fopen(filename, "r")) == NULL) { fprintf(stderr, "ippserver: Unable to open \"%s\": %s\n", filename, strerror(errno)); exit(1); } while (get_token(fp, token, sizeof(token), &linenum) != NULL) { if (!_cups_strcasecmp(token, "ATTR")) { /* * Attribute... */ if (!get_token(fp, token, sizeof(token), &linenum)) { fprintf(stderr, "ippserver: Missing ATTR value tag on line %d of \"%s\".\n", linenum, filename); exit(1); } if ((value = ippTagValue(token)) == IPP_TAG_ZERO) { fprintf(stderr, "ippserver: Bad ATTR value tag \"%s\" on line %d of \"%s\".\n", token, linenum, filename); exit(1); } if (!get_token(fp, attr, sizeof(attr), &linenum)) { fprintf(stderr, "ippserver: Missing ATTR name on line %d of \"%s\".\n", linenum, filename); exit(1); } if (!get_token(fp, token, sizeof(token), &linenum)) { fprintf(stderr, "ippserver: Missing ATTR value on line %d of \"%s\".\n", linenum, filename); exit(1); } attrptr = NULL; switch (value) { case IPP_TAG_BOOLEAN : if (!_cups_strcasecmp(token, "true")) attrptr = ippAddBoolean(attrs, IPP_TAG_PRINTER, attr, 1); else attrptr = ippAddBoolean(attrs, IPP_TAG_PRINTER, attr, (char)atoi(token)); break; case IPP_TAG_INTEGER : case IPP_TAG_ENUM : if (!strchr(token, ',')) attrptr = ippAddInteger(attrs, IPP_TAG_PRINTER, value, attr, (int)strtol(token, &tokenptr, 0)); else { int values[100], /* Values */ num_values = 1; /* Number of values */ values[0] = (int)strtol(token, &tokenptr, 10); while (tokenptr && *tokenptr && num_values < (int)(sizeof(values) / sizeof(values[0]))) { if (*tokenptr == ',') tokenptr ++; else if (!isdigit(*tokenptr & 255) && *tokenptr != '-') break; values[num_values] = (int)strtol(tokenptr, &tokenptr, 0); num_values ++; } attrptr = ippAddIntegers(attrs, IPP_TAG_PRINTER, value, attr, num_values, values); } if (!tokenptr || *tokenptr) { fprintf(stderr, "ippserver: Bad %s value \"%s\" on line %d of \"%s\".\n", ippTagString(value), token, linenum, filename); exit(1); } break; case IPP_TAG_RESOLUTION : { int xres, /* X resolution */ yres; /* Y resolution */ ipp_res_t units; /* Units */ char *start, /* Start of value */ *ptr, /* Pointer into value */ *next = NULL; /* Next value */ for (start = token; start; start = next) { xres = yres = (int)strtol(start, (char **)&ptr, 10); if (ptr > start && xres > 0) { if (*ptr == 'x') yres = (int)strtol(ptr + 1, (char **)&ptr, 10); } if (ptr && (next = strchr(ptr, ',')) != NULL) *next++ = '\0'; if (ptr <= start || xres <= 0 || yres <= 0 || !ptr || (_cups_strcasecmp(ptr, "dpi") && _cups_strcasecmp(ptr, "dpc") && _cups_strcasecmp(ptr, "dpcm") && _cups_strcasecmp(ptr, "other"))) { fprintf(stderr, "ippserver: Bad resolution value \"%s\" on line %d of \"%s\".\n", token, linenum, filename); exit(1); } if (!_cups_strcasecmp(ptr, "dpc") || !_cups_strcasecmp(ptr, "dpcm")) units = IPP_RES_PER_CM; else units = IPP_RES_PER_INCH; if (attrptr) ippSetResolution(attrs, &attrptr, ippGetCount(attrptr), units, xres, yres); else attrptr = ippAddResolution(attrs, IPP_TAG_PRINTER, attr, units, xres, yres); } } break; case IPP_TAG_RANGE : { int lowers[4], /* Lower value */ uppers[4], /* Upper values */ num_vals; /* Number of values */ num_vals = sscanf(token, "%d-%d,%d-%d,%d-%d,%d-%d", lowers + 0, uppers + 0, lowers + 1, uppers + 1, lowers + 2, uppers + 2, lowers + 3, uppers + 3); if ((num_vals & 1) || num_vals == 0) { fprintf(stderr, "ippserver: Bad rangeOfInteger value \"%s\" on line %d of \"%s\".", token, linenum, filename); exit(1); } attrptr = ippAddRanges(attrs, IPP_TAG_PRINTER, attr, num_vals / 2, lowers, uppers); } break; case IPP_TAG_BEGIN_COLLECTION : if (!strcmp(token, "{")) { ipp_t *col = get_collection(fp, filename, &linenum); /* Collection value */ if (col) { attrptr = lastcol = ippAddCollection(attrs, IPP_TAG_PRINTER, attr, col); ippDelete(col); } else exit(1); } else { fprintf(stderr, "ippserver: Bad ATTR collection value on line %d of \"%s\".\n", linenum, filename); exit(1); } do { ipp_t *col; /* Collection value */ long pos = ftell(fp); /* Save position of file */ if (!get_token(fp, token, sizeof(token), &linenum)) break; if (strcmp(token, ",")) { fseek(fp, pos, SEEK_SET); break; } if (!get_token(fp, token, sizeof(token), &linenum) || strcmp(token, "{")) { fprintf(stderr, "ippserver: Unexpected \"%s\" on line %d of \"%s\".\n", token, linenum, filename); exit(1); } if ((col = get_collection(fp, filename, &linenum)) == NULL) break; ippSetCollection(attrs, &attrptr, ippGetCount(attrptr), col); } while (!strcmp(token, "{")); break; case IPP_TAG_STRING : attrptr = ippAddOctetString(attrs, IPP_TAG_PRINTER, attr, token, (int)strlen(token)); break; default : fprintf(stderr, "ippserver: Unsupported ATTR value tag %s on line %d of \"%s\".\n", ippTagString(value), linenum, filename); exit(1); case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : if (!strchr(token, ',')) attrptr = ippAddString(attrs, IPP_TAG_PRINTER, value, attr, NULL, token); else { /* * Multiple string values... */ int num_values; /* Number of values */ char *values[100], /* Values */ *ptr; /* Pointer to next value */ values[0] = token; num_values = 1; for (ptr = strchr(token, ','); ptr; ptr = strchr(ptr, ',')) { if (ptr > token && ptr[-1] == '\\') _cups_strcpy(ptr - 1, ptr); else { *ptr++ = '\0'; values[num_values] = ptr; num_values ++; if (num_values >= (int)(sizeof(values) / sizeof(values[0]))) break; } } attrptr = ippAddStrings(attrs, IPP_TAG_PRINTER, value, attr, num_values, NULL, (const char **)values); } break; } if (!attrptr) { fprintf(stderr, "ippserver: Unable to add attribute on line %d of \"%s\": %s\n", linenum, filename, cupsLastErrorString()); exit(1); } } else { fprintf(stderr, "ippserver: Unknown directive \"%s\" on line %d of \"%s\".\n", token, linenum, filename); exit(1); } } fclose(fp); } /* * 'parse_options()' - Parse URL options into CUPS options. * * The client->options string is destroyed by this function. */ static int /* O - Number of options */ parse_options(_ipp_client_t *client, /* I - Client */ cups_option_t **options) /* O - Options */ { char *name, /* Name */ *value, /* Value */ *next; /* Next name=value pair */ int num_options = 0; /* Number of options */ *options = NULL; for (name = client->options; name && *name; name = next) { if ((value = strchr(name, '=')) == NULL) break; *value++ = '\0'; if ((next = strchr(value, '&')) != NULL) *next++ = '\0'; num_options = cupsAddOption(name, value, num_options, options); } return (num_options); } /* * 'process_attr_message()' - Process an ATTR: message from a command. */ static void process_attr_message( _ipp_job_t *job, /* I - Job */ char *message) /* I - Message */ { (void)job; (void)message; } /* * 'process_client()' - Process client requests on a thread. */ static void * /* O - Exit status */ process_client(_ipp_client_t *client) /* I - Client */ { /* * Loop until we are out of requests or timeout (30 seconds)... */ #ifdef HAVE_SSL int first_time = 1; /* First time request? */ #endif /* HAVE_SSL */ while (httpWait(client->http, 30000)) { #ifdef HAVE_SSL if (first_time) { /* * See if we need to negotiate a TLS connection... */ char buf[1]; /* First byte from client */ if (recv(httpGetFd(client->http), buf, 1, MSG_PEEK) == 1 && (!buf[0] || !strchr("DGHOPT", buf[0]))) { fprintf(stderr, "%s Starting HTTPS session.\n", client->hostname); if (httpEncryption(client->http, HTTP_ENCRYPTION_ALWAYS)) { fprintf(stderr, "%s Unable to encrypt connection: %s\n", client->hostname, cupsLastErrorString()); break; } fprintf(stderr, "%s Connection now encrypted.\n", client->hostname); } first_time = 0; } #endif /* HAVE_SSL */ if (!process_http(client)) break; } /* * Close the conection to the client and return... */ delete_client(client); return (NULL); } /* * 'process_http()' - Process a HTTP request. */ int /* O - 1 on success, 0 on failure */ process_http(_ipp_client_t *client) /* I - Client connection */ { char uri[1024]; /* URI */ http_state_t http_state; /* HTTP state */ http_status_t http_status; /* HTTP status */ ipp_state_t ipp_state; /* State of IPP transfer */ char scheme[32], /* Method/scheme */ userpass[128], /* Username:password */ hostname[HTTP_MAX_HOST]; /* Hostname */ int port; /* Port number */ const char *encoding; /* Content-Encoding value */ static const char * const http_states[] = { /* Strings for logging HTTP method */ "WAITING", "OPTIONS", "GET", "GET_SEND", "HEAD", "POST", "POST_RECV", "POST_SEND", "PUT", "PUT_RECV", "DELETE", "TRACE", "CONNECT", "STATUS", "UNKNOWN_METHOD", "UNKNOWN_VERSION" }; /* * Clear state variables... */ ippDelete(client->request); ippDelete(client->response); client->request = NULL; client->response = NULL; client->operation = HTTP_STATE_WAITING; /* * Read a request from the connection... */ while ((http_state = httpReadRequest(client->http, uri, sizeof(uri))) == HTTP_STATE_WAITING) usleep(1); /* * Parse the request line... */ if (http_state == HTTP_STATE_ERROR) { if (httpError(client->http) == EPIPE) fprintf(stderr, "%s Client closed connection.\n", client->hostname); else fprintf(stderr, "%s Bad request line (%s).\n", client->hostname, strerror(httpError(client->http))); return (0); } else if (http_state == HTTP_STATE_UNKNOWN_METHOD) { fprintf(stderr, "%s Bad/unknown operation.\n", client->hostname); respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); return (0); } else if (http_state == HTTP_STATE_UNKNOWN_VERSION) { fprintf(stderr, "%s Bad HTTP version.\n", client->hostname); respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); return (0); } fprintf(stderr, "%s %s %s\n", client->hostname, http_states[http_state], uri); /* * Separate the URI into its components... */ if (httpSeparateURI(HTTP_URI_CODING_MOST, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, client->uri, sizeof(client->uri)) < HTTP_URI_STATUS_OK && (http_state != HTTP_STATE_OPTIONS || strcmp(uri, "*"))) { fprintf(stderr, "%s Bad URI \"%s\".\n", client->hostname, uri); respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); return (0); } if ((client->options = strchr(client->uri, '?')) != NULL) *(client->options)++ = '\0'; /* * Process the request... */ client->start = time(NULL); client->operation = httpGetState(client->http); /* * Parse incoming parameters until the status changes... */ while ((http_status = httpUpdate(client->http)) == HTTP_STATUS_CONTINUE); if (http_status != HTTP_STATUS_OK) { respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); return (0); } if (!httpGetField(client->http, HTTP_FIELD_HOST)[0] && httpGetVersion(client->http) >= HTTP_VERSION_1_1) { /* * HTTP/1.1 and higher require the "Host:" field... */ respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); return (0); } /* * Handle HTTP Upgrade... */ if (!strcasecmp(httpGetField(client->http, HTTP_FIELD_CONNECTION), "Upgrade")) { #ifdef HAVE_SSL if (strstr(httpGetField(client->http, HTTP_FIELD_UPGRADE), "TLS/") != NULL && !httpIsEncrypted(client->http)) { if (!respond_http(client, HTTP_STATUS_SWITCHING_PROTOCOLS, NULL, NULL, 0)) return (0); fprintf(stderr, "%s Upgrading to encrypted connection.\n", client->hostname); if (httpEncryption(client->http, HTTP_ENCRYPTION_REQUIRED)) { fprintf(stderr, "%s Unable to encrypt connection: %s\n", client->hostname, cupsLastErrorString()); return (0); } fprintf(stderr, "%s Connection now encrypted.\n", client->hostname); } else #endif /* HAVE_SSL */ if (!respond_http(client, HTTP_STATUS_NOT_IMPLEMENTED, NULL, NULL, 0)) return (0); } /* * Handle HTTP Expect... */ if (httpGetExpect(client->http) && (client->operation == HTTP_STATE_POST || client->operation == HTTP_STATE_PUT)) { if (httpGetExpect(client->http) == HTTP_STATUS_CONTINUE) { /* * Send 100-continue header... */ if (!respond_http(client, HTTP_STATUS_CONTINUE, NULL, NULL, 0)) return (0); } else { /* * Send 417-expectation-failed header... */ if (!respond_http(client, HTTP_STATUS_EXPECTATION_FAILED, NULL, NULL, 0)) return (0); } } /* * Handle new transfers... */ encoding = httpGetContentEncoding(client->http); switch (client->operation) { case HTTP_STATE_OPTIONS : /* * Do OPTIONS command... */ return (respond_http(client, HTTP_STATUS_OK, NULL, NULL, 0)); case HTTP_STATE_HEAD : if (!strcmp(client->uri, "/icon.png")) return (respond_http(client, HTTP_STATUS_OK, NULL, "image/png", 0)); else if (!strcmp(client->uri, "/") || !strcmp(client->uri, "/media") || !strcmp(client->uri, "/supplies")) return (respond_http(client, HTTP_STATUS_OK, NULL, "text/html", 0)); else return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0)); case HTTP_STATE_GET : if (!strcmp(client->uri, "/icon.png")) { /* * Send PNG icon file. */ int fd; /* Icon file */ struct stat fileinfo; /* Icon file information */ char buffer[4096]; /* Copy buffer */ ssize_t bytes; /* Bytes */ fprintf(stderr, "Icon file is \"%s\".\n", client->printer->icon); if (!stat(client->printer->icon, &fileinfo) && (fd = open(client->printer->icon, O_RDONLY)) >= 0) { if (!respond_http(client, HTTP_STATUS_OK, NULL, "image/png", (size_t)fileinfo.st_size)) { close(fd); return (0); } while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) httpWrite2(client->http, buffer, (size_t)bytes); httpFlushWrite(client->http); close(fd); } else return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0)); } else if (!strcmp(client->uri, "/")) { /* * Show web status page... */ _ipp_job_t *job; /* Current job */ int i; /* Looping var */ _ipp_preason_t reason; /* Current reason */ static const char * const reasons[] = { /* Reason strings */ "Other", "Cover Open", "Input Tray Missing", "Marker Supply Empty", "Marker Supply Low", "Marker Waste Almost Full", "Marker Waste Full", "Media Empty", "Media Jam", "Media Low", "Media Needed", "Moving to Paused", "Paused", "Spool Area Full", "Toner Empty", "Toner Low" }; if (!respond_http(client, HTTP_STATUS_OK, encoding, "text/html", 0)) return (0); html_header(client, client->printer->name); html_printf(client, "

ippserver (" CUPS_SVERSION ")

\n" "

%s, %d job(s).", client->printer->state == IPP_PSTATE_IDLE ? "Idle" : client->printer->state == IPP_PSTATE_PROCESSING ? "Printing" : "Stopped", cupsArrayCount(client->printer->jobs)); for (i = 0, reason = 1; i < (int)(sizeof(reasons) / sizeof(reasons[0])); i ++, reason <<= 1) if (client->printer->state_reasons & reason) html_printf(client, "\n
    %s", reasons[i]); html_printf(client, "

\n"); if (cupsArrayCount(client->printer->jobs) > 0) { _cupsRWLockRead(&(client->printer->rwlock)); html_printf(client, "\n"); for (job = (_ipp_job_t *)cupsArrayFirst(client->printer->jobs); job; job = (_ipp_job_t *)cupsArrayNext(client->printer->jobs)) { char when[256], /* When job queued/started/finished */ hhmmss[64]; /* Time HH:MM:SS */ switch (job->state) { case IPP_JSTATE_PENDING : case IPP_JSTATE_HELD : snprintf(when, sizeof(when), "Queued at %s", time_string(job->created, hhmmss, sizeof(hhmmss))); break; case IPP_JSTATE_PROCESSING : case IPP_JSTATE_STOPPED : snprintf(when, sizeof(when), "Started at %s", time_string(job->processing, hhmmss, sizeof(hhmmss))); break; case IPP_JSTATE_ABORTED : snprintf(when, sizeof(when), "Aborted at %s", time_string(job->completed, hhmmss, sizeof(hhmmss))); break; case IPP_JSTATE_CANCELED : snprintf(when, sizeof(when), "Canceled at %s", time_string(job->completed, hhmmss, sizeof(hhmmss))); break; case IPP_JSTATE_COMPLETED : snprintf(when, sizeof(when), "Completed at %s", time_string(job->completed, hhmmss, sizeof(hhmmss))); break; } html_printf(client, "\n", job->id, job->name, job->username, when); } html_printf(client, "
Job #NameOwnerWhen
%d%s%s%s
\n"); _cupsRWUnlock(&(client->printer->rwlock)); } html_footer(client); return (1); } else if (!strcmp(client->uri, "/media")) { /* * Show web media page... */ int i, /* Looping var */ num_options; /* Number of form options */ cups_option_t *options; /* Form options */ static const char * const sizes[] = { /* Size strings */ "ISO A4", "ISO A5", "ISO A6", "DL Envelope", "US Legal", "US Letter", "#10 Envelope", "3x5 Photo", "3.5x5 Photo", "4x6 Photo", "5x7 Photo" }; static const char * const types[] = /* Type strings */ { "Auto", "Cardstock", "Envelope", "Labels", "Other", "Glossy Photo", "High-Gloss Photo", "Matte Photo", "Satin Photo", "Semi-Gloss Photo", "Plain", "Letterhead", "Transparency" }; static const int sheets[] = /* Number of sheets */ { 250, 100, 25, 5, 0 }; if (!respond_http(client, HTTP_STATUS_OK, encoding, "text/html", 0)) return (0); html_header(client, client->printer->name); if ((num_options = parse_options(client, &options)) > 0) { /* * WARNING: A real printer/server implementation MUST NOT implement * media updates via a GET request - GET requests are supposed to be * idempotent (without side-effects) and we obviously are not * authenticating access here. This form is provided solely to * enable testing and development! */ const char *val; /* Form value */ if ((val = cupsGetOption("main_size", num_options, options)) != NULL) client->printer->main_size = atoi(val); if ((val = cupsGetOption("main_type", num_options, options)) != NULL) client->printer->main_type = atoi(val); if ((val = cupsGetOption("main_level", num_options, options)) != NULL) client->printer->main_level = atoi(val); if ((val = cupsGetOption("envelope_size", num_options, options)) != NULL) client->printer->envelope_size = atoi(val); if ((val = cupsGetOption("envelope_level", num_options, options)) != NULL) client->printer->envelope_level = atoi(val); if ((val = cupsGetOption("photo_size", num_options, options)) != NULL) client->printer->photo_size = atoi(val); if ((val = cupsGetOption("photo_type", num_options, options)) != NULL) client->printer->photo_type = atoi(val); if ((val = cupsGetOption("photo_level", num_options, options)) != NULL) client->printer->photo_level = atoi(val); if ((client->printer->main_level < 100 && client->printer->main_level > 0) || (client->printer->envelope_level < 25 && client->printer->envelope_level > 0) || (client->printer->photo_level < 25 && client->printer->photo_level > 0)) client->printer->state_reasons |= _IPP_PREASON_MEDIA_LOW; else client->printer->state_reasons &= (_ipp_preason_t)~_IPP_PREASON_MEDIA_LOW; if ((client->printer->main_level == 0 && client->printer->main_size > _IPP_MEDIA_SIZE_NONE) || (client->printer->envelope_level == 0 && client->printer->envelope_size > _IPP_MEDIA_SIZE_NONE) || (client->printer->photo_level == 0 && client->printer->photo_size > _IPP_MEDIA_SIZE_NONE)) { client->printer->state_reasons |= _IPP_PREASON_MEDIA_EMPTY; if (client->printer->active_job) client->printer->state_reasons |= _IPP_PREASON_MEDIA_NEEDED; } else client->printer->state_reasons &= (_ipp_preason_t)~(_IPP_PREASON_MEDIA_EMPTY | _IPP_PREASON_MEDIA_NEEDED); html_printf(client, "
Media updated.
\n"); } html_printf(client, "
\n"); html_printf(client, "\n"); html_printf(client, "\n"); html_printf(client, "\n"); html_printf(client, "\n"); html_printf(client, "
Main Tray:
Envelope Feeder:
Photo Tray:
\n"); html_footer(client); return (1); } else if (!strcmp(client->uri, "/supplies")) { /* * Show web supplies page... */ int i, j, /* Looping vars */ num_options; /* Number of form options */ cups_option_t *options; /* Form options */ static const int levels[] = { 0, 5, 10, 25, 50, 75, 90, 95, 100 }; if (!respond_http(client, HTTP_STATUS_OK, encoding, "text/html", 0)) return (0); html_header(client, client->printer->name); if ((num_options = parse_options(client, &options)) > 0) { /* * WARNING: A real printer/server implementation MUST NOT implement * supply updates via a GET request - GET requests are supposed to be * idempotent (without side-effects) and we obviously are not * authenticating access here. This form is provided solely to * enable testing and development! */ char name[64]; /* Form field */ const char *val; /* Form value */ client->printer->state_reasons &= (_ipp_preason_t)~(_IPP_PREASON_MARKER_SUPPLY_EMPTY | _IPP_PREASON_MARKER_SUPPLY_LOW | _IPP_PREASON_MARKER_WASTE_ALMOST_FULL | _IPP_PREASON_MARKER_WASTE_FULL | _IPP_PREASON_TONER_EMPTY | _IPP_PREASON_TONER_LOW); for (i = 0; i < (int)(sizeof(printer_supplies) / sizeof(printer_supplies[0])); i ++) { snprintf(name, sizeof(name), "supply_%d", i); if ((val = cupsGetOption(name, num_options, options)) != NULL) { int level = client->printer->supplies[i] = atoi(val); /* New level */ if (i < 4) { if (level == 0) client->printer->state_reasons |= _IPP_PREASON_TONER_EMPTY; else if (level < 10) client->printer->state_reasons |= _IPP_PREASON_TONER_LOW; } else { if (level == 100) client->printer->state_reasons |= _IPP_PREASON_MARKER_WASTE_FULL; else if (level > 90) client->printer->state_reasons |= _IPP_PREASON_MARKER_WASTE_ALMOST_FULL; } } } html_printf(client, "
Supplies updated.
\n"); } html_printf(client, "
\n"); html_printf(client, "\n"); for (i = 0; i < (int)(sizeof(printer_supplies) / sizeof(printer_supplies[0])); i ++) { html_printf(client, "\n"); } html_printf(client, "\n
%s:
\n
\n"); html_footer(client); return (1); } else return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0)); break; case HTTP_STATE_POST : if (strcmp(httpGetField(client->http, HTTP_FIELD_CONTENT_TYPE), "application/ipp")) { /* * Not an IPP request... */ return (respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0)); } /* * Read the IPP request... */ client->request = ippNew(); while ((ipp_state = ippRead(client->http, client->request)) != IPP_STATE_DATA) { if (ipp_state == IPP_STATE_ERROR) { fprintf(stderr, "%s IPP read error (%s).\n", client->hostname, cupsLastErrorString()); respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); return (0); } } /* * Now that we have the IPP request, process the request... */ return (process_ipp(client)); default : break; /* Anti-compiler-warning-code */ } return (1); } /* * 'process_ipp()' - Process an IPP request. */ static int /* O - 1 on success, 0 on error */ process_ipp(_ipp_client_t *client) /* I - Client */ { ipp_tag_t group; /* Current group tag */ ipp_attribute_t *attr; /* Current attribute */ ipp_attribute_t *charset; /* Character set attribute */ ipp_attribute_t *language; /* Language attribute */ ipp_attribute_t *uri; /* Printer URI attribute */ int major, minor; /* Version number */ const char *name; /* Name of attribute */ debug_attributes("Request", client->request, 1); /* * First build an empty response message for this request... */ client->operation_id = ippGetOperation(client->request); client->response = ippNewResponse(client->request); /* * Then validate the request header and required attributes... */ major = ippGetVersion(client->request, &minor); if (major < 1 || major > 2) { /* * Return an error, since we only support IPP 1.x and 2.x. */ respond_ipp(client, IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, "Bad request version number %d.%d.", major, minor); } else if (ippGetRequestId(client->request) <= 0) respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad request-id %d.", ippGetRequestId(client->request)); else if (!ippFirstAttribute(client->request)) respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "No attributes in request."); else { /* * Make sure that the attributes are provided in the correct order and * don't repeat groups... */ for (attr = ippFirstAttribute(client->request), group = ippGetGroupTag(attr); attr; attr = ippNextAttribute(client->request)) { if (ippGetGroupTag(attr) < group && ippGetGroupTag(attr) != IPP_TAG_ZERO) { /* * Out of order; return an error... */ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Attribute groups are out of order (%x < %x).", ippGetGroupTag(attr), group); break; } else group = ippGetGroupTag(attr); } if (!attr) { /* * Then make sure that the first three attributes are: * * attributes-charset * attributes-natural-language * printer-uri/job-uri */ attr = ippFirstAttribute(client->request); name = ippGetName(attr); if (attr && name && !strcmp(name, "attributes-charset") && ippGetValueTag(attr) == IPP_TAG_CHARSET) charset = attr; else charset = NULL; attr = ippNextAttribute(client->request); name = ippGetName(attr); if (attr && name && !strcmp(name, "attributes-natural-language") && ippGetValueTag(attr) == IPP_TAG_LANGUAGE) language = attr; else language = NULL; if ((attr = ippFindAttribute(client->request, "printer-uri", IPP_TAG_URI)) != NULL) uri = attr; else if ((attr = ippFindAttribute(client->request, "job-uri", IPP_TAG_URI)) != NULL) uri = attr; else uri = NULL; if (charset && strcasecmp(ippGetString(charset, 0, NULL), "us-ascii") && strcasecmp(ippGetString(charset, 0, NULL), "utf-8")) { /* * Bad character set... */ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Unsupported character set \"%s\".", ippGetString(charset, 0, NULL)); } else if (!charset || !language || !uri) { /* * Return an error, since attributes-charset, * attributes-natural-language, and printer-uri/job-uri are required * for all operations. */ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing required attributes."); } else { char scheme[32], /* URI scheme */ userpass[32], /* Username/password in URI */ host[256], /* Host name in URI */ resource[256]; /* Resource path in URI */ int port; /* Port number in URI */ name = ippGetName(uri); if (httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL), scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) respond_ipp(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, "Bad %s value '%s'.", name, ippGetString(uri, 0, NULL)); else if ((!strcmp(name, "job-uri") && strncmp(resource, "/ipp/print/", 11)) || (!strcmp(name, "printer-uri") && strcmp(resource, "/ipp/print"))) respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "%s %s not found.", name, ippGetString(uri, 0, NULL)); else { /* * Try processing the operation... */ switch (ippGetOperation(client->request)) { case IPP_OP_PRINT_JOB : ipp_print_job(client); break; case IPP_OP_PRINT_URI : ipp_print_uri(client); break; case IPP_OP_VALIDATE_JOB : ipp_validate_job(client); break; case IPP_OP_CREATE_JOB : ipp_create_job(client); break; case IPP_OP_SEND_DOCUMENT : ipp_send_document(client); break; case IPP_OP_SEND_URI : ipp_send_uri(client); break; case IPP_OP_CANCEL_JOB : ipp_cancel_job(client); break; case IPP_OP_GET_JOB_ATTRIBUTES : ipp_get_job_attributes(client); break; case IPP_OP_GET_JOBS : ipp_get_jobs(client); break; case IPP_OP_GET_PRINTER_ATTRIBUTES : ipp_get_printer_attributes(client); break; case IPP_OP_CLOSE_JOB : ipp_close_job(client); break; case IPP_OP_IDENTIFY_PRINTER : ipp_identify_printer(client); break; default : respond_ipp(client, IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED, "Operation not supported."); break; } } } } } /* * Send the HTTP header and return... */ if (httpGetState(client->http) != HTTP_STATE_POST_SEND) httpFlush(client->http); /* Flush trailing (junk) data */ return (respond_http(client, HTTP_STATUS_OK, NULL, "application/ipp", ippLength(client->response))); } /* * 'process_job()' - Process a print job. */ static void * /* O - Thread exit status */ process_job(_ipp_job_t *job) /* I - Job */ { job->state = IPP_JSTATE_PROCESSING; job->printer->state = IPP_PSTATE_PROCESSING; job->processing = time(NULL); while (job->printer->state_reasons & _IPP_PREASON_MEDIA_EMPTY) { job->printer->state_reasons |= _IPP_PREASON_MEDIA_NEEDED; sleep(1); } job->printer->state_reasons &= (_ipp_preason_t)~_IPP_PREASON_MEDIA_NEEDED; if (job->printer->command) { /* * Execute a command with the job spool file and wait for it to complete... */ int pid, /* Process ID */ status; /* Exit status */ time_t start, /* Start time */ end; /* End time */ char *myargv[3], /* Command-line arguments */ *myenvp[200]; /* Environment variables */ int myenvc; /* Number of environment variables */ ipp_attribute_t *attr; /* Job attribute */ char val[1280], /* IPP_NAME=value */ *valptr; /* Pointer into string */ #ifndef WIN32 int mypipe[2]; /* Pipe for stderr */ char line[2048], /* Line from stderr */ *ptr, /* Pointer into line */ *endptr; /* End of line */ ssize_t bytes; /* Bytes read */ #endif /* !WIN32 */ fprintf(stderr, "Running command \"%s %s\".\n", job->printer->command, job->filename); time(&start); /* * Setup the command-line arguments... */ myargv[0] = job->printer->command; myargv[1] = job->filename; myargv[2] = NULL; /* * Copy the current environment, then add ENV variables for every Job * attribute... */ for (myenvc = 0; environ[myenvc] && myenvc < (int)(sizeof(myenvp) / sizeof(myenvp[0]) - 1); myenvc ++) myenvp[myenvc] = strdup(environ[myenvc]); for (attr = ippFirstAttribute(job->attrs); attr && myenvc < (int)(sizeof(myenvp) / sizeof(myenvp[0]) - 1); attr = ippNextAttribute(job->attrs)) { /* * Convert "attribute-name" to "IPP_ATTRIBUTE_NAME=" and then add the * value(s) from the attribute. */ const char *name = ippGetName(attr); if (!name) continue; valptr = val; *valptr++ = 'I'; *valptr++ = 'P'; *valptr++ = 'P'; *valptr++ = '_'; while (*name && valptr < (val + sizeof(val) - 2)) { if (*name == '-') *valptr++ = '_'; else *valptr++ = (char)toupper(*name & 255); name ++; } *valptr++ = '='; ippAttributeString(attr, valptr, sizeof(val) - (size_t)(valptr - val)); myenvp[myenvc++] = strdup(val); } myenvp[myenvc] = NULL; /* * Now run the program... */ #ifdef WIN32 status = _spawnvpe(_P_WAIT, job->printer->command, myargv, myenvp); #else if (pipe(mypipe)) { perror("Unable to create pipe for stderr"); mypipe[0] = mypipe[1] = -1; } if ((pid = fork()) == 0) { /* * Child comes here... */ close(2); dup2(mypipe[1], 2); close(mypipe[0]); close(mypipe[1]); execve(job->printer->command, myargv, myenvp); exit(errno); } else if (pid < 0) { /* * Unable to fork process... */ perror("Unable to start job processing command"); status = -1; close(mypipe[0]); close(mypipe[1]); /* * Free memory used for environment... */ while (myenvc > 0) free(myenvp[-- myenvc]); } else { /* * Free memory used for environment... */ while (myenvc > 0) free(myenvp[-- myenvc]); /* * If the pipe exists, read from it until EOF... */ if (mypipe[0] >= 0) { close(mypipe[1]); endptr = line; while ((bytes = read(mypipe[0], endptr, sizeof(line) - (size_t)(endptr - line) - 1)) > 0) { endptr += bytes; *endptr = '\0'; while ((ptr = strchr(line, '\n')) != NULL) { *ptr++ = '\0'; if (!strncmp(line, "STATE:", 6)) { /* * Process printer-state-reasons keywords. */ process_state_message(job, line); } else if (!strncmp(line, "ATTR:", 5)) { /* * Process printer attribute update. */ process_attr_message(job, line); } else if (Verbosity > 1) fprintf(stderr, "%s: %s\n", job->printer->command, line); bytes = ptr - line; if (ptr < endptr) memmove(line, ptr, (size_t)(endptr - ptr)); endptr -= bytes; *endptr = '\0'; } } close(mypipe[0]); } /* * Wait for child to complete... */ # ifdef HAVE_WAITPID while (waitpid(pid, &status, 0) < 0); # else while (wait(&status) < 0); # endif /* HAVE_WAITPID */ } #endif /* WIN32 */ if (status) { #ifndef WIN32 if (WIFEXITED(status)) #endif /* !WIN32 */ fprintf(stderr, "Command \"%s\" exited with status %d.\n", job->printer->command, WEXITSTATUS(status)); #ifndef WIN32 else fprintf(stderr, "Command \"%s\" terminated with signal %d.\n", job->printer->command, WTERMSIG(status)); #endif /* !WIN32 */ job->state = IPP_JSTATE_ABORTED; } else if (status < 0) job->state = IPP_JSTATE_ABORTED; else fprintf(stderr, "Command \"%s\" completed successfully.\n", job->printer->command); /* * Make sure processing takes at least 5 seconds... */ time(&end); if ((end - start) < 5) sleep(5); } else { /* * Sleep for a random amount of time to simulate job processing. */ sleep((unsigned)(5 + (rand() % 11))); } if (job->cancel) job->state = IPP_JSTATE_CANCELED; else if (job->state == IPP_JSTATE_PROCESSING) job->state = IPP_JSTATE_COMPLETED; job->completed = time(NULL); job->printer->state = IPP_PSTATE_IDLE; job->printer->active_job = NULL; return (NULL); } /* * 'process_state_message()' - Process a STATE: message from a command. */ static void process_state_message( _ipp_job_t *job, /* I - Job */ char *message) /* I - Message */ { int i; /* Looping var */ _ipp_preason_t state_reasons, /* printer-state-reasons values */ bit; /* Current reason bit */ char *ptr, /* Pointer into message */ *next; /* Next keyword in message */ int remove; /* Non-zero if we are removing keywords */ /* * Skip leading "STATE:" and any whitespace... */ for (message += 6; *message; message ++) if (*message != ' ' && *message != '\t') break; /* * Support the following forms of message: * * "keyword[,keyword,...]" to set the printer-state-reasons value(s). * * "-keyword[,keyword,...]" to remove keywords. * * "+keyword[,keyword,...]" to add keywords. * * Keywords may or may not have a suffix (-report, -warning, -error) per * RFC 2911. */ if (*message == '-') { remove = 1; state_reasons = job->printer->state_reasons; message ++; } else if (*message == '+') { remove = 0; state_reasons = job->printer->state_reasons; message ++; } else { remove = 0; state_reasons = _IPP_PREASON_NONE; } while (*message) { if ((next = strchr(message, ',')) != NULL) *next++ = '\0'; if ((ptr = strstr(message, "-error")) != NULL) *ptr = '\0'; else if ((ptr = strstr(message, "-report")) != NULL) *ptr = '\0'; else if ((ptr = strstr(message, "-warning")) != NULL) *ptr = '\0'; for (i = 0, bit = 1; i < (int)(sizeof(_ipp_preason_strings) / sizeof(_ipp_preason_strings[0])); i ++, bit *= 2) { if (!strcmp(message, _ipp_preason_strings[i])) { if (remove) state_reasons &= ~bit; else state_reasons |= bit; } } if (next) message = next; else break; } job->printer->state_reasons = state_reasons; } /* * 'register_printer()' - Register a printer object via Bonjour. */ static int /* O - 1 on success, 0 on error */ register_printer( _ipp_printer_t *printer, /* I - Printer */ const char *location, /* I - Location */ const char *make, /* I - Manufacturer */ const char *model, /* I - Model name */ const char *formats, /* I - Supported formats */ const char *adminurl, /* I - Web interface URL */ const char *uuid, /* I - Printer UUID */ int color, /* I - 1 = color, 0 = monochrome */ int duplex, /* I - 1 = duplex, 0 = simplex */ const char *subtype) /* I - Service subtype */ { #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) _ipp_txt_t ipp_txt; /* Bonjour IPP TXT record */ #endif /* HAVE_DNSSD || HAVE_AVAHI */ #ifdef HAVE_DNSSD DNSServiceErrorType error; /* Error from Bonjour */ char make_model[256],/* Make and model together */ product[256], /* Product string */ regtype[256]; /* Bonjour service type */ /* * Build the TXT record for IPP... */ snprintf(make_model, sizeof(make_model), "%s %s", make, model); snprintf(product, sizeof(product), "(%s)", model); TXTRecordCreate(&ipp_txt, 1024, NULL); TXTRecordSetValue(&ipp_txt, "rp", 9, "ipp/print"); TXTRecordSetValue(&ipp_txt, "ty", (uint8_t)strlen(make_model), make_model); TXTRecordSetValue(&ipp_txt, "adminurl", (uint8_t)strlen(adminurl), adminurl); if (*location) TXTRecordSetValue(&ipp_txt, "note", (uint8_t)strlen(location), location); TXTRecordSetValue(&ipp_txt, "product", (uint8_t)strlen(product), product); TXTRecordSetValue(&ipp_txt, "pdl", (uint8_t)strlen(formats), formats); TXTRecordSetValue(&ipp_txt, "Color", 1, color ? "T" : "F"); TXTRecordSetValue(&ipp_txt, "Duplex", 1, duplex ? "T" : "F"); TXTRecordSetValue(&ipp_txt, "usb_MFG", (uint8_t)strlen(make), make); TXTRecordSetValue(&ipp_txt, "usb_MDL", (uint8_t)strlen(model), model); TXTRecordSetValue(&ipp_txt, "UUID", (uint8_t)strlen(uuid), uuid); # ifdef HAVE_SSL TXTRecordSetValue(&ipp_txt, "TLS", 3, "1.2"); # endif /* HAVE_SSL */ if (strstr(formats, "image/urf")) TXTRecordSetValue(&ipp_txt, "URF", 66, "CP1,IS1-5-7,MT1-2-3-4-5-6-8-9-10-11-12-13,RS300,SRGB24,V1.4,W8,DM1"); TXTRecordSetValue(&ipp_txt, "txtvers", 1, "1"); TXTRecordSetValue(&ipp_txt, "qtotal", 1, "1"); /* * Register the _printer._tcp (LPD) service type with a port number of 0 to * defend our service name but not actually support LPD... */ printer->printer_ref = DNSSDMaster; if ((error = DNSServiceRegister(&(printer->printer_ref), kDNSServiceFlagsShareConnection, 0 /* interfaceIndex */, printer->dnssd_name, "_printer._tcp", NULL /* domain */, NULL /* host */, 0 /* port */, 0 /* txtLen */, NULL /* txtRecord */, (DNSServiceRegisterReply)dnssd_callback, printer)) != kDNSServiceErr_NoError) { fprintf(stderr, "Unable to register \"%s._printer._tcp\": %d\n", printer->dnssd_name, error); return (0); } /* * Then register the _ipp._tcp (IPP) service type with the real port number to * advertise our IPP printer... */ printer->ipp_ref = DNSSDMaster; if (subtype && *subtype) snprintf(regtype, sizeof(regtype), "_ipp._tcp,%s", subtype); else strlcpy(regtype, "_ipp._tcp", sizeof(regtype)); if ((error = DNSServiceRegister(&(printer->ipp_ref), kDNSServiceFlagsShareConnection, 0 /* interfaceIndex */, printer->dnssd_name, regtype, NULL /* domain */, NULL /* host */, htons(printer->port), TXTRecordGetLength(&ipp_txt), TXTRecordGetBytesPtr(&ipp_txt), (DNSServiceRegisterReply)dnssd_callback, printer)) != kDNSServiceErr_NoError) { fprintf(stderr, "Unable to register \"%s.%s\": %d\n", printer->dnssd_name, regtype, error); return (0); } # ifdef HAVE_SSL /* * Then register the _ipps._tcp (IPP) service type with the real port number to * advertise our IPPS printer... */ printer->ipps_ref = DNSSDMaster; if (subtype && *subtype) snprintf(regtype, sizeof(regtype), "_ipps._tcp,%s", subtype); else strlcpy(regtype, "_ipps._tcp", sizeof(regtype)); if ((error = DNSServiceRegister(&(printer->ipps_ref), kDNSServiceFlagsShareConnection, 0 /* interfaceIndex */, printer->dnssd_name, regtype, NULL /* domain */, NULL /* host */, htons(printer->port), TXTRecordGetLength(&ipp_txt), TXTRecordGetBytesPtr(&ipp_txt), (DNSServiceRegisterReply)dnssd_callback, printer)) != kDNSServiceErr_NoError) { fprintf(stderr, "Unable to register \"%s.%s\": %d\n", printer->dnssd_name, regtype, error); return (0); } # endif /* HAVE_SSL */ /* * Similarly, register the _http._tcp,_printer (HTTP) service type with the * real port number to advertise our IPP printer... */ printer->http_ref = DNSSDMaster; if ((error = DNSServiceRegister(&(printer->http_ref), kDNSServiceFlagsShareConnection, 0 /* interfaceIndex */, printer->dnssd_name, "_http._tcp,_printer", NULL /* domain */, NULL /* host */, htons(printer->port), 0 /* txtLen */, NULL, /* txtRecord */ (DNSServiceRegisterReply)dnssd_callback, printer)) != kDNSServiceErr_NoError) { fprintf(stderr, "Unable to register \"%s.%s\": %d\n", printer->dnssd_name, regtype, error); return (0); } TXTRecordDeallocate(&ipp_txt); #elif defined(HAVE_AVAHI) char temp[256]; /* Subtype service string */ /* * Create the TXT record... */ ipp_txt = NULL; ipp_txt = avahi_string_list_add_printf(ipp_txt, "rp=ipp/print"); ipp_txt = avahi_string_list_add_printf(ipp_txt, "ty=%s %s", make, model); ipp_txt = avahi_string_list_add_printf(ipp_txt, "adminurl=%s", adminurl); if (*location) ipp_txt = avahi_string_list_add_printf(ipp_txt, "note=%s", location); ipp_txt = avahi_string_list_add_printf(ipp_txt, "product=(%s)", model); ipp_txt = avahi_string_list_add_printf(ipp_txt, "pdl=%s", formats); ipp_txt = avahi_string_list_add_printf(ipp_txt, "Color=%s", color ? "T" : "F"); ipp_txt = avahi_string_list_add_printf(ipp_txt, "Duplex=%s", duplex ? "T" : "F"); ipp_txt = avahi_string_list_add_printf(ipp_txt, "usb_MFG=%s", make); ipp_txt = avahi_string_list_add_printf(ipp_txt, "usb_MDL=%s", model); ipp_txt = avahi_string_list_add_printf(ipp_txt, "UUID=%s", uuid); # ifdef HAVE_SSL ipp_txt = avahi_string_list_add_printf(ipp_txt, "TLS=1.2"); # endif /* HAVE_SSL */ /* * Register _printer._tcp (LPD) with port 0 to reserve the service name... */ avahi_threaded_poll_lock(DNSSDMaster); printer->ipp_ref = avahi_entry_group_new(DNSSDClient, dnssd_callback, NULL); avahi_entry_group_add_service_strlst(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_printer._tcp", NULL, NULL, 0, NULL); /* * Then register the _ipp._tcp (IPP)... */ avahi_entry_group_add_service_strlst(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_ipp._tcp", NULL, NULL, printer->port, ipp_txt); if (subtype && *subtype) { snprintf(temp, sizeof(temp), "%s._sub._ipp._tcp", subtype); avahi_entry_group_add_service_subtype(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_ipp._tcp", NULL, temp); } #ifdef HAVE_SSL /* * _ipps._tcp (IPPS) for secure printing... */ avahi_entry_group_add_service_strlst(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_ipps._tcp", NULL, NULL, printer->port, ipp_txt); if (subtype && *subtype) { snprintf(temp, sizeof(temp), "%s._sub._ipps._tcp", subtype); avahi_entry_group_add_service_subtype(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_ipps._tcp", NULL, temp); } #endif /* HAVE_SSL */ /* * Finally _http.tcp (HTTP) for the web interface... */ avahi_entry_group_add_service_strlst(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_http._tcp", NULL, NULL, printer->port, NULL); avahi_entry_group_add_service_subtype(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_http._tcp", NULL, "_printer._sub._http._tcp"); /* * Commit it... */ avahi_entry_group_commit(printer->ipp_ref); avahi_threaded_poll_unlock(DNSSDMaster); avahi_string_list_free(ipp_txt); #endif /* HAVE_DNSSD */ return (1); } /* * 'respond_http()' - Send a HTTP response. */ int /* O - 1 on success, 0 on failure */ respond_http( _ipp_client_t *client, /* I - Client */ http_status_t code, /* I - HTTP status of response */ const char *content_encoding, /* I - Content-Encoding of response */ const char *type, /* I - MIME media type of response */ size_t length) /* I - Length of response */ { char message[1024]; /* Text message */ fprintf(stderr, "%s %s\n", client->hostname, httpStatus(code)); if (code == HTTP_STATUS_CONTINUE) { /* * 100-continue doesn't send any headers... */ return (httpWriteResponse(client->http, HTTP_STATUS_CONTINUE) == 0); } /* * Format an error message... */ if (!type && !length && code != HTTP_STATUS_OK && code != HTTP_STATUS_SWITCHING_PROTOCOLS) { snprintf(message, sizeof(message), "%d - %s\n", code, httpStatus(code)); type = "text/plain"; length = strlen(message); } else message[0] = '\0'; /* * Send the HTTP response header... */ httpClearFields(client->http); if (code == HTTP_STATUS_METHOD_NOT_ALLOWED || client->operation == HTTP_STATE_OPTIONS) httpSetField(client->http, HTTP_FIELD_ALLOW, "GET, HEAD, OPTIONS, POST"); if (type) { if (!strcmp(type, "text/html")) httpSetField(client->http, HTTP_FIELD_CONTENT_TYPE, "text/html; charset=utf-8"); else httpSetField(client->http, HTTP_FIELD_CONTENT_TYPE, type); if (content_encoding) httpSetField(client->http, HTTP_FIELD_CONTENT_ENCODING, content_encoding); } httpSetLength(client->http, length); if (httpWriteResponse(client->http, code) < 0) return (0); /* * Send the response data... */ if (message[0]) { /* * Send a plain text message. */ if (httpPrintf(client->http, "%s", message) < 0) return (0); if (httpWrite2(client->http, "", 0) < 0) return (0); } else if (client->response) { /* * Send an IPP response... */ debug_attributes("Response", client->response, 2); ippSetState(client->response, IPP_STATE_IDLE); if (ippWrite(client->http, client->response) != IPP_STATE_DATA) return (0); } return (1); } /* * 'respond_ipp()' - Send an IPP response. */ static void respond_ipp(_ipp_client_t *client, /* I - Client */ ipp_status_t status, /* I - status-code */ const char *message, /* I - printf-style status-message */ ...) /* I - Additional args as needed */ { const char *formatted = NULL; /* Formatted message */ ippSetStatusCode(client->response, status); if (message) { va_list ap; /* Pointer to additional args */ ipp_attribute_t *attr; /* New status-message attribute */ va_start(ap, message); if ((attr = ippFindAttribute(client->response, "status-message", IPP_TAG_TEXT)) != NULL) ippSetStringfv(client->response, &attr, 0, message, ap); else attr = ippAddStringfv(client->response, IPP_TAG_OPERATION, IPP_TAG_TEXT, "status-message", NULL, message, ap); va_end(ap); formatted = ippGetString(attr, 0, NULL); } if (formatted) fprintf(stderr, "%s %s %s (%s)\n", client->hostname, ippOpString(client->operation_id), ippErrorString(status), formatted); else fprintf(stderr, "%s %s %s\n", client->hostname, ippOpString(client->operation_id), ippErrorString(status)); } /* * 'respond_unsupported()' - Respond with an unsupported attribute. */ static void respond_unsupported( _ipp_client_t *client, /* I - Client */ ipp_attribute_t *attr) /* I - Atribute */ { ipp_attribute_t *temp; /* Copy of attribute */ respond_ipp(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, "Unsupported %s %s%s value.", ippGetName(attr), ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr))); temp = ippCopyAttribute(client->response, attr, 0); ippSetGroupTag(client->response, &temp, IPP_TAG_UNSUPPORTED_GROUP); } /* * 'run_printer()' - Run the printer service. */ static void run_printer(_ipp_printer_t *printer) /* I - Printer */ { int num_fds; /* Number of file descriptors */ struct pollfd polldata[3]; /* poll() data */ int timeout; /* Timeout for poll() */ _ipp_client_t *client; /* New client */ /* * Setup poll() data for the Bonjour service socket and IPv4/6 listeners... */ polldata[0].fd = printer->ipv4; polldata[0].events = POLLIN; polldata[1].fd = printer->ipv6; polldata[1].events = POLLIN; num_fds = 2; #ifdef HAVE_DNSSD polldata[num_fds ].fd = DNSServiceRefSockFD(DNSSDMaster); polldata[num_fds ++].events = POLLIN; #endif /* HAVE_DNSSD */ /* * Loop until we are killed or have a hard error... */ for (;;) { if (cupsArrayCount(printer->jobs)) timeout = 10; else timeout = -1; if (poll(polldata, (nfds_t)num_fds, timeout) < 0 && errno != EINTR) { perror("poll() failed"); break; } if (polldata[0].revents & POLLIN) { if ((client = create_client(printer, printer->ipv4)) != NULL) { _cups_thread_t t = _cupsThreadCreate((_cups_thread_func_t)process_client, client); if (t) { _cupsThreadDetach(t); } else { perror("Unable to create client thread"); delete_client(client); } } } if (polldata[1].revents & POLLIN) { if ((client = create_client(printer, printer->ipv6)) != NULL) { _cups_thread_t t = _cupsThreadCreate((_cups_thread_func_t)process_client, client); if (t) { _cupsThreadDetach(t); } else { perror("Unable to create client thread"); delete_client(client); } } } #ifdef HAVE_DNSSD if (polldata[2].revents & POLLIN) DNSServiceProcessResult(DNSSDMaster); #endif /* HAVE_DNSSD */ /* * Clean out old jobs... */ clean_jobs(printer); } } /* * 'time_string()' - Return the local time in hours, minutes, and seconds. */ static char * time_string(time_t tv, /* I - Time value */ char *buffer, /* I - Buffer */ size_t bufsize) /* I - Size of buffer */ { struct tm *curtime = localtime(&tv); /* Local time */ strftime(buffer, bufsize, "%X", curtime); return (buffer); } /* * 'usage()' - Show program usage. */ static void usage(int status) /* O - Exit status */ { if (!status) { puts(CUPS_SVERSION " - Copyright 2010-2015 by Apple Inc. All rights " "reserved."); puts(""); } puts("Usage: ippserver [options] \"name\""); puts(""); puts("Options:"); puts("-2 Supports 2-sided printing (default=1-sided)"); puts("-M manufacturer Manufacturer name (default=Test)"); puts("-P PIN printing mode"); puts("-a attributes-file Load printer attributes from file"); puts("-c command Run command for every print job"); printf("-d spool-directory Spool directory " "(default=/tmp/ippserver.%d)\n", (int)getpid()); puts("-f type/subtype[,...] List of supported types " "(default=application/pdf,image/jpeg)"); puts("-h Show program help"); puts("-i iconfile.png PNG icon file (default=printer.png)"); puts("-k Keep job spool files"); puts("-l location Location of printer (default=empty string)"); puts("-m model Model name (default=Printer)"); puts("-n hostname Hostname for printer"); puts("-p port Port number (default=auto)"); puts("-r subtype Bonjour service subtype (default=_print)"); puts("-s speed[,color-speed] Speed in pages per minute (default=10,0)"); puts("-v[vvv] Be (very) verbose"); exit(status); } /* * 'valid_doc_attributes()' - Determine whether the document attributes are * valid. * * When one or more document attributes are invalid, this function adds a * suitable response and attributes to the unsupported group. */ static int /* O - 1 if valid, 0 if not */ valid_doc_attributes( _ipp_client_t *client) /* I - Client */ { int valid = 1; /* Valid attributes? */ ipp_op_t op = ippGetOperation(client->request); /* IPP operation */ const char *op_name = ippOpString(op); /* IPP operation name */ ipp_attribute_t *attr, /* Current attribute */ *supported; /* xxx-supported attribute */ const char *compression = NULL, /* compression value */ *format = NULL; /* document-format value */ /* * Check operation attributes... */ if ((attr = ippFindAttribute(client->request, "compression", IPP_TAG_ZERO)) != NULL) { /* * If compression is specified, only accept a supported value in a Print-Job * or Send-Document request... */ compression = ippGetString(attr, 0, NULL); supported = ippFindAttribute(client->printer->attrs, "compression-supported", IPP_TAG_KEYWORD); if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_KEYWORD || ippGetGroupTag(attr) != IPP_TAG_OPERATION || (op != IPP_OP_PRINT_JOB && op != IPP_OP_SEND_DOCUMENT && op != IPP_OP_VALIDATE_JOB) || !ippContainsString(supported, compression)) { respond_unsupported(client, attr); valid = 0; } else { fprintf(stderr, "%s %s compression=\"%s\"\n", client->hostname, op_name, compression); ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "compression-supplied", NULL, compression); if (strcmp(compression, "none")) { if (Verbosity) fprintf(stderr, "Receiving job file with \"%s\" compression.\n", compression); httpSetField(client->http, HTTP_FIELD_CONTENT_ENCODING, compression); } } } /* * Is it a format we support? */ if ((attr = ippFindAttribute(client->request, "document-format", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_MIMETYPE || ippGetGroupTag(attr) != IPP_TAG_OPERATION) { respond_unsupported(client, attr); valid = 0; } else { format = ippGetString(attr, 0, NULL); fprintf(stderr, "%s %s document-format=\"%s\"\n", client->hostname, op_name, format); ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-supplied", NULL, format); } } else { format = ippGetString(ippFindAttribute(client->printer->attrs, "document-format-default", IPP_TAG_MIMETYPE), 0, NULL); if (!format) format = "application/octet-stream"; /* Should never happen */ attr = ippAddString(client->request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, format); } if (format && !strcmp(format, "application/octet-stream") && (ippGetOperation(client->request) == IPP_OP_PRINT_JOB || ippGetOperation(client->request) == IPP_OP_SEND_DOCUMENT)) { /* * Auto-type the file using the first 8 bytes of the file... */ unsigned char header[8]; /* First 8 bytes of file */ memset(header, 0, sizeof(header)); httpPeek(client->http, (char *)header, sizeof(header)); if (!memcmp(header, "%PDF", 4)) format = "application/pdf"; else if (!memcmp(header, "%!", 2)) format = "application/postscript"; else if (!memcmp(header, "\377\330\377", 3) && header[3] >= 0xe0 && header[3] <= 0xef) format = "image/jpeg"; else if (!memcmp(header, "\211PNG", 4)) format = "image/png"; else if (!memcmp(header, "RAS2", 4)) format = "image/pwg-raster"; else if (!memcmp(header, "UNIRAST", 8)) format = "image/urf"; else format = NULL; if (format) { fprintf(stderr, "%s %s Auto-typed document-format=\"%s\"\n", client->hostname, op_name, format); ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-detected", NULL, format); } } if (op != IPP_OP_CREATE_JOB && (supported = ippFindAttribute(client->printer->attrs, "document-format-supported", IPP_TAG_MIMETYPE)) != NULL && !ippContainsString(supported, format)) { respond_unsupported(client, attr); valid = 0; } /* * document-name */ if ((attr = ippFindAttribute(client->request, "document-name", IPP_TAG_NAME)) != NULL) ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_NAME, "document-name-supplied", NULL, ippGetString(attr, 0, NULL)); return (valid); } /* * 'valid_job_attributes()' - Determine whether the job attributes are valid. * * When one or more job attributes are invalid, this function adds a suitable * response and attributes to the unsupported group. */ static int /* O - 1 if valid, 0 if not */ valid_job_attributes( _ipp_client_t *client) /* I - Client */ { int i, /* Looping var */ count, /* Number of values */ valid = 1; /* Valid attributes? */ ipp_attribute_t *attr, /* Current attribute */ *supported; /* xxx-supported attribute */ /* * Check operation attributes... */ valid = valid_doc_attributes(client); /* * Check the various job template attributes... */ if ((attr = ippFindAttribute(client->request, "copies", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetInteger(attr, 0) < 1 || ippGetInteger(attr, 0) > 999) { respond_unsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "ipp-attribute-fidelity", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_BOOLEAN) { respond_unsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "job-hold-until", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || (ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG && ippGetValueTag(attr) != IPP_TAG_KEYWORD) || strcmp(ippGetString(attr, 0, NULL), "no-hold")) { respond_unsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "job-impressions", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetInteger(attr, 0) < 0) { respond_unsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "job-name", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || (ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG)) { respond_unsupported(client, attr); valid = 0; } ippSetGroupTag(client->request, &attr, IPP_TAG_JOB); } else ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled"); if ((attr = ippFindAttribute(client->request, "job-priority", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetInteger(attr, 0) < 1 || ippGetInteger(attr, 0) > 100) { respond_unsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "job-sheets", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || (ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG && ippGetValueTag(attr) != IPP_TAG_KEYWORD) || strcmp(ippGetString(attr, 0, NULL), "none")) { respond_unsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "media", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || (ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG && ippGetValueTag(attr) != IPP_TAG_KEYWORD)) { respond_unsupported(client, attr); valid = 0; } else { supported = ippFindAttribute(client->printer->attrs, "media-supported", IPP_TAG_KEYWORD); if (!ippContainsString(supported, ippGetString(attr, 0, NULL))) { respond_unsupported(client, attr); valid = 0; } } } if ((attr = ippFindAttribute(client->request, "media-col", IPP_TAG_ZERO)) != NULL) { ipp_t *col, /* media-col collection */ *size; /* media-size collection */ ipp_attribute_t *member, /* Member attribute */ *x_dim, /* x-dimension */ *y_dim; /* y-dimension */ int x_value, /* y-dimension value */ y_value; /* x-dimension value */ if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_BEGIN_COLLECTION) { respond_unsupported(client, attr); valid = 0; } col = ippGetCollection(attr, 0); if ((member = ippFindAttribute(col, "media-size-name", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(member) != 1 || (ippGetValueTag(member) != IPP_TAG_NAME && ippGetValueTag(member) != IPP_TAG_NAMELANG && ippGetValueTag(member) != IPP_TAG_KEYWORD)) { respond_unsupported(client, attr); valid = 0; } else { supported = ippFindAttribute(client->printer->attrs, "media-supported", IPP_TAG_KEYWORD); if (!ippContainsString(supported, ippGetString(member, 0, NULL))) { respond_unsupported(client, attr); valid = 0; } } } else if ((member = ippFindAttribute(col, "media-size", IPP_TAG_BEGIN_COLLECTION)) != NULL) { if (ippGetCount(member) != 1) { respond_unsupported(client, attr); valid = 0; } else { size = ippGetCollection(member, 0); if ((x_dim = ippFindAttribute(size, "x-dimension", IPP_TAG_INTEGER)) == NULL || ippGetCount(x_dim) != 1 || (y_dim = ippFindAttribute(size, "y-dimension", IPP_TAG_INTEGER)) == NULL || ippGetCount(y_dim) != 1) { respond_unsupported(client, attr); valid = 0; } else { x_value = ippGetInteger(x_dim, 0); y_value = ippGetInteger(y_dim, 0); supported = ippFindAttribute(client->printer->attrs, "media-size-supported", IPP_TAG_BEGIN_COLLECTION); count = ippGetCount(supported); for (i = 0; i < count ; i ++) { size = ippGetCollection(supported, i); x_dim = ippFindAttribute(size, "x-dimension", IPP_TAG_ZERO); y_dim = ippFindAttribute(size, "y-dimension", IPP_TAG_ZERO); if (ippContainsInteger(x_dim, x_value) && ippContainsInteger(y_dim, y_value)) break; } if (i >= count) { respond_unsupported(client, attr); valid = 0; } } } } } if ((attr = ippFindAttribute(client->request, "multiple-document-handling", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_KEYWORD || (strcmp(ippGetString(attr, 0, NULL), "separate-documents-uncollated-copies") && strcmp(ippGetString(attr, 0, NULL), "separate-documents-collated-copies"))) { respond_unsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "orientation-requested", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_ENUM || ippGetInteger(attr, 0) < IPP_ORIENT_PORTRAIT || ippGetInteger(attr, 0) > IPP_ORIENT_REVERSE_PORTRAIT) { respond_unsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "page-ranges", IPP_TAG_ZERO)) != NULL) { if (ippGetValueTag(attr) != IPP_TAG_RANGE) { respond_unsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "print-quality", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_ENUM || ippGetInteger(attr, 0) < IPP_QUALITY_DRAFT || ippGetInteger(attr, 0) > IPP_QUALITY_HIGH) { respond_unsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "printer-resolution", IPP_TAG_ZERO)) != NULL) { supported = ippFindAttribute(client->printer->attrs, "printer-resolution-supported", IPP_TAG_RESOLUTION); if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_RESOLUTION || !supported) { respond_unsupported(client, attr); valid = 0; } else { int xdpi, /* Horizontal resolution for job template attribute */ ydpi, /* Vertical resolution for job template attribute */ sydpi; /* Vertical resolution for supported value */ ipp_res_t units, /* Units for job template attribute */ sunits; /* Units for supported value */ xdpi = ippGetResolution(attr, 0, &ydpi, &units); count = ippGetCount(supported); for (i = 0; i < count; i ++) { if (xdpi == ippGetResolution(supported, i, &sydpi, &sunits) && ydpi == sydpi && units == sunits) break; } if (i >= count) { respond_unsupported(client, attr); valid = 0; } } } if ((attr = ippFindAttribute(client->request, "sides", IPP_TAG_ZERO)) != NULL) { const char *sides = ippGetString(attr, 0, NULL); /* "sides" value... */ if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_KEYWORD) { respond_unsupported(client, attr); valid = 0; } else if ((supported = ippFindAttribute(client->printer->attrs, "sides-supported", IPP_TAG_KEYWORD)) != NULL) { if (!ippContainsString(supported, sides)) { respond_unsupported(client, attr); valid = 0; } } else if (strcmp(sides, "one-sided")) { respond_unsupported(client, attr); valid = 0; } } return (valid); } ippsample/tools/ipptransform.c0000644000175000017500000021710413240604116015574 0ustar tilltill/* * ipptransform utility for converting PDF and JPEG files to raster data or HP PCL. * * Copyright 2016-2018 by the IEEE-ISTO Printer Working Group. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ #include #include #include #include #include #ifdef __APPLE__ # include extern void CGContextSetCTM(CGContextRef c, CGAffineTransform m); #elif defined(HAVE_MUPDF) # include static inline fz_matrix fz_make_matrix(float a, float b, float c, float d, float e, float f) { fz_matrix ret = { a, b, c, d, e, f }; return (ret); } #endif /* __APPLE__ */ #include "dither.h" /* * Constants... */ #define XFORM_MAX_RASTER 16777216 #define XFORM_RED_MASK 0x000000ff #define XFORM_GREEN_MASK 0x0000ff00 #define XFORM_BLUE_MASK 0x00ff0000 #define XFORM_RGB_MASK (XFORM_RED_MASK | XFORM_GREEN_MASK | XFORM_BLUE_MASK) #define XFORM_BG_MASK (XFORM_BLUE_MASK | XFORM_GREEN_MASK) #define XFORM_RG_MASK (XFORM_RED_MASK | XFORM_GREEN_MASK) /* * Local types... */ typedef ssize_t (*xform_write_cb_t)(void *, const unsigned char *, size_t); typedef struct xform_raster_s xform_raster_t; struct xform_raster_s { const char *format; /* Output format */ int num_options; /* Number of job options */ cups_option_t *options; /* Job options */ unsigned copies; /* Number of copies */ cups_page_header2_t header; /* Page header */ cups_page_header2_t back_header; /* Page header for back side */ int borderless; /* Borderless media? */ unsigned char *band_buffer; /* Band buffer */ unsigned band_height; /* Band height */ unsigned band_bpp; /* Bytes per pixel in band */ /* Set by start_job callback */ cups_raster_t *ras; /* Raster stream */ /* Set by start_page callback */ unsigned left, top, right, bottom; /* Image (print) box with origin at top left */ unsigned out_blanks; /* Blank lines */ size_t out_length; /* Output buffer size */ unsigned char *out_buffer; /* Output (bit) buffer */ unsigned char *comp_buffer; /* Compression buffer */ /* Callbacks */ void (*end_job)(xform_raster_t *, xform_write_cb_t, void *); void (*end_page)(xform_raster_t *, unsigned, xform_write_cb_t, void *); void (*start_job)(xform_raster_t *, xform_write_cb_t, void *); void (*start_page)(xform_raster_t *, unsigned, xform_write_cb_t, void *); void (*write_line)(xform_raster_t *, unsigned, const unsigned char *, xform_write_cb_t, void *); }; /* * Local globals... */ static int Verbosity = 0; /* Log level */ /* * Local functions... */ static int load_env_options(cups_option_t **options); static void *monitor_ipp(const char *device_uri); #ifdef HAVE_MUPDF static void pack_graya(unsigned char *row, size_t num_pixels); #endif /* HAVE_MUPDF */ static void pack_rgba(unsigned char *row, size_t num_pixels); static void pcl_end_job(xform_raster_t *ras, xform_write_cb_t cb, void *ctx); static void pcl_end_page(xform_raster_t *ras, unsigned page, xform_write_cb_t cb, void *ctx); static void pcl_init(xform_raster_t *ras); static void pcl_printf(xform_write_cb_t cb, void *ctx, const char *format, ...) __attribute__ ((__format__ (__printf__, 3, 4))); static void pcl_start_job(xform_raster_t *ras, xform_write_cb_t cb, void *ctx); static void pcl_start_page(xform_raster_t *ras, unsigned page, xform_write_cb_t cb, void *ctx); static void pcl_write_line(xform_raster_t *ras, unsigned y, const unsigned char *line, xform_write_cb_t cb, void *ctx); static void raster_end_job(xform_raster_t *ras, xform_write_cb_t cb, void *ctx); static void raster_end_page(xform_raster_t *ras, unsigned page, xform_write_cb_t cb, void *ctx); static void raster_init(xform_raster_t *ras); static void raster_start_job(xform_raster_t *ras, xform_write_cb_t cb, void *ctx); static void raster_start_page(xform_raster_t *ras, unsigned page, xform_write_cb_t cb, void *ctx); static void raster_write_line(xform_raster_t *ras, unsigned y, const unsigned char *line, xform_write_cb_t cb, void *ctx); static void usage(int status) __attribute__((noreturn)); static ssize_t write_fd(int *fd, const unsigned char *buffer, size_t bytes); static int xform_document(const char *filename, const char *informat, const char *outformat, const char *resolutions, const char *sheet_back, const char *types, int num_options, cups_option_t *options, xform_write_cb_t cb, void *ctx); static int xform_setup(xform_raster_t *ras, const char *outformat, const char *resolutions, const char *types, const char *sheet_back, int color, unsigned pages, int num_options, cups_option_t *options); /* * 'main()' - Main entry for transform utility. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ const char *filename = NULL, /* File to transform */ *content_type, /* Source content type */ *device_uri, /* Destination URI */ *output_type, /* Destination content type */ *resolutions, /* pwg-raster-document-resolution-supported */ *sheet_back, /* pwg-raster-document-sheet-back */ *types, /* pwg-raster-document-type-supported */ *opt; /* Option character */ int num_options; /* Number of options */ cups_option_t *options; /* Options */ int fd = 1; /* Output file/socket */ http_t *http = NULL; /* Output HTTP connection */ void *write_ptr = &fd; /* Pointer to file/socket/HTTP connection */ char resource[1024]; /* URI resource path */ xform_write_cb_t write_cb = (xform_write_cb_t)write_fd; /* Write callback */ int status = 0; /* Exit status */ _cups_thread_t monitor = 0; /* Monitoring thread ID */ /* * Process the command-line... */ num_options = load_env_options(&options); content_type = getenv("CONTENT_TYPE"); device_uri = getenv("DEVICE_URI"); output_type = getenv("OUTPUT_TYPE"); resolutions = getenv("PWG_RASTER_DOCUMENT_RESOLUTION_SUPPORTED"); sheet_back = getenv("PWG_RASTER_DOCUMENT_SHEET_BACK"); types = getenv("PWG_RASTER_DOCUMENT_TYPE_SUPPORTED"); if ((opt = getenv("SERVER_LOGLEVEL")) != NULL) { if (!strcmp(opt, "debug")) Verbosity = 2; else if (!strcmp(opt, "info")) Verbosity = 1; } for (i = 1; i < argc; i ++) { if (argv[i][0] == '-' && argv[i][1] != '-') { for (opt = argv[i] + 1; *opt; opt ++) { switch (*opt) { case 'd' : i ++; if (i >= argc) usage(1); device_uri = argv[i]; break; case 'i' : i ++; if (i >= argc) usage(1); content_type = argv[i]; break; case 'm' : i ++; if (i >= argc) usage(1); output_type = argv[i]; break; case 'o' : i ++; if (i >= argc) usage(1); num_options = cupsParseOptions(argv[i], num_options, &options); break; case 'r' : /* pwg-raster-document-resolution-supported values */ i ++; if (i >= argc) usage(1); resolutions = argv[i]; break; case 's' : /* pwg-raster-document-sheet-back value */ i ++; if (i >= argc) usage(1); sheet_back = argv[i]; break; case 't' : /* pwg-raster-document-type-supported values */ i ++; if (i >= argc) usage(1); types = argv[i]; break; case 'v' : /* Be verbose... */ Verbosity ++; break; default : fprintf(stderr, "ERROR: Unknown option '-%c'.\n", *opt); usage(1); break; } } } else if (!strcmp(argv[i], "--help")) usage(0); else if (!strncmp(argv[i], "--", 2)) { fprintf(stderr, "ERROR: Unknown option '%s'.\n", argv[i]); usage(1); } else if (!filename) filename = argv[i]; else usage(1); } /* * Check that we have everything we need... */ if (!filename) usage(1); if (!content_type) { if ((opt = strrchr(filename, '.')) != NULL) { if (!strcmp(opt, ".pdf")) content_type = "application/pdf"; else if (!strcmp(opt, ".jpg") || !strcmp(opt, ".jpeg")) content_type = "image/jpeg"; } } if (!content_type) { fprintf(stderr, "ERROR: Unknown format for \"%s\", please specify with '-i' option.\n", filename); usage(1); } else if (strcmp(content_type, "application/pdf") && strcmp(content_type, "image/jpeg")) { fprintf(stderr, "ERROR: Unsupported format \"%s\" for \"%s\".\n", content_type, filename); usage(1); } if (!output_type) { fputs("ERROR: Unknown output format, please specify with '-m' option.\n", stderr); usage(1); } else if (strcmp(output_type, "application/vnd.hp-pcl") && strcmp(output_type, "image/pwg-raster") && strcmp(output_type, "image/urf")) { fprintf(stderr, "ERROR: Unsupported output format \"%s\".\n", output_type); usage(1); } if (!resolutions) resolutions = "300dpi"; if (!sheet_back) sheet_back = "normal"; if (!types) types = "sgray_8"; /* * If the device URI is specified, open the connection... */ if (device_uri) { char scheme[32], /* URI scheme */ userpass[256], /* URI user:pass */ host[256], /* URI host */ service[32]; /* Service port */ int port; /* URI port number */ http_addrlist_t *list; /* Address list for socket */ if (httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) { fprintf(stderr, "ERROR: Invalid device URI \"%s\".\n", device_uri); usage(1); } if (strcmp(scheme, "socket") && strcmp(scheme, "ipp") && strcmp(scheme, "ipps")) { fprintf(stderr, "ERROR: Unsupported device URI scheme \"%s\".\n", scheme); usage(1); } snprintf(service, sizeof(service), "%d", port); if ((list = httpAddrGetList(host, AF_UNSPEC, service)) == NULL) { fprintf(stderr, "ERROR: Unable to lookup device URI host \"%s\": %s\n", host, cupsLastErrorString()); return (1); } if (!strcmp(scheme, "socket")) { /* * AppSocket connection... */ if (!httpAddrConnect2(list, &fd, 30000, NULL)) { fprintf(stderr, "ERROR: Unable to connect to \"%s\" on port %d: %s\n", host, port, cupsLastErrorString()); return (1); } } else { http_encryption_t encryption; /* Encryption mode */ ipp_t *request, /* IPP request */ *response; /* IPP response */ ipp_attribute_t *attr; /* operations-supported */ int create_job = 0; /* Support for Create-Job/Send-Document? */ const char *job_name; /* Title of job */ const char *media; /* Value of "media" option */ const char *sides; /* Value of "sides" option */ /* * Connect to the IPP/IPPS printer... */ if (port == 443 || !strcmp(scheme, "ipps")) encryption = HTTP_ENCRYPTION_ALWAYS; else encryption = HTTP_ENCRYPTION_IF_REQUESTED; if ((http = httpConnect2(host, port, list, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL) { fprintf(stderr, "ERROR: Unable to connect to \"%s\" on port %d: %s\n", host, port, cupsLastErrorString()); return (1); } /* * See if it supports Create-Job + Send-Document... */ request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, device_uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", NULL, "operations-supported"); response = cupsDoRequest(http, request, resource); if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) { fprintf(stderr, "ERROR: Unable to get printer capabilities: %s\n", cupsLastErrorString()); return (1); } if ((attr = ippFindAttribute(response, "operations-supported", IPP_TAG_ENUM)) == NULL) { fputs("ERROR: Unable to get list of supported operations from printer.\n", stderr); return (1); } create_job = ippContainsInteger(attr, IPP_OP_CREATE_JOB) && ippContainsInteger(attr, IPP_OP_SEND_DOCUMENT); ippDelete(response); /* * Create the job and start printing... */ if ((job_name = getenv("IPP_JOB_NAME")) == NULL) { if ((job_name = strrchr(filename, '/')) != NULL) job_name ++; else job_name = filename; } if (create_job) { int job_id = 0; /* Job ID */ request = ippNewRequest(IPP_OP_CREATE_JOB); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, device_uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, job_name); response = cupsDoRequest(http, request, resource); if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL) job_id = ippGetInteger(attr, 0); ippDelete(response); if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) { fprintf(stderr, "ERROR: Unable to create print job: %s\n", cupsLastErrorString()); return (1); } else if (job_id <= 0) { fputs("ERROR: No job-id for created print job.\n", stderr); return (1); } request = ippNewRequest(IPP_OP_SEND_DOCUMENT); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, device_uri); ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, output_type); ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1); } else { request = ippNewRequest(IPP_OP_PRINT_JOB); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, device_uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, output_type); } if ((media = cupsGetOption("media", num_options, options)) != NULL) ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "media", NULL, media); if ((sides = cupsGetOption("sides", num_options, options)) != NULL) ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, sides); if (cupsSendRequest(http, request, resource, 0) != HTTP_STATUS_CONTINUE) { fprintf(stderr, "ERROR: Unable to send print data: %s\n", cupsLastErrorString()); return (1); } ippDelete(request); write_cb = (xform_write_cb_t)httpWrite2; write_ptr = http; monitor = _cupsThreadCreate((_cups_thread_func_t)monitor_ipp, (void *)device_uri); } httpAddrFreeList(list); } /* * Do transform... */ status = xform_document(filename, content_type, output_type, resolutions, sheet_back, types, num_options, options, write_cb, write_ptr); if (http) { ippDelete(cupsGetResponse(http, resource)); if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) { fprintf(stderr, "ERROR: Unable to send print data: %s\n", cupsLastErrorString()); status = 1; } httpClose(http); } else if (fd != 1) close(fd); if (monitor) _cupsThreadCancel(monitor); return (status); } /* * 'load_env_options()' - Load options from the environment. */ extern char **environ; static int /* O - Number of options */ load_env_options( cups_option_t **options) /* I - Options */ { int i; /* Looping var */ char name[256], /* Option name */ *nameptr, /* Pointer into name */ *envptr; /* Pointer into environment variable */ int num_options = 0; /* Number of options */ *options = NULL; /* * Load all of the IPP_xxx environment variables as options... */ for (i = 0; environ[i]; i ++) { envptr = environ[i]; if (strncmp(envptr, "IPP_", 4)) continue; for (nameptr = name, envptr += 4; *envptr && *envptr != '='; envptr ++) { if (nameptr > (name + sizeof(name) - 1)) continue; if (*envptr == '_') *nameptr++ = '-'; else *nameptr++ = (char)_cups_tolower(*envptr); } *nameptr = '\0'; if (*envptr == '=') envptr ++; num_options = cupsAddOption(name, envptr, num_options, options); } return (num_options); } /* * 'monitor_ipp()' - Monitor IPP printer status. */ static void * /* O - Thread exit status */ monitor_ipp(const char *device_uri) /* I - Device URI */ { int i; /* Looping var */ http_t *http; /* HTTP connection */ ipp_t *request, /* IPP request */ *response; /* IPP response */ ipp_attribute_t *attr; /* IPP response attribute */ char scheme[32], /* URI scheme */ userpass[256], /* URI user:pass */ host[256], /* URI host */ resource[1024]; /* URI resource */ int port; /* URI port number */ http_encryption_t encryption; /* Encryption to use */ int delay = 1, /* Current delay */ next_delay, /* Next delay */ prev_delay = 0; /* Previous delay */ char pvalues[10][1024]; /* Current printer attribute values */ static const char * const pattrs[10] =/* Printer attributes we need */ { "marker-colors", "marker-levels", "marker-low-levels", "marker-high-levels", "marker-names", "marker-types", "printer-state-reasons", "printer-alert", "printer-supply", "printer-supply-description" }; httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)); if (port == 443 || !strcmp(scheme, "ipps")) encryption = HTTP_ENCRYPTION_ALWAYS; else encryption = HTTP_ENCRYPTION_IF_REQUESTED; while ((http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL) { fprintf(stderr, "ERROR: Unable to connect to \"%s\" on port %d: %s\n", host, port, cupsLastErrorString()); sleep(30); } /* * Report printer state changes until we are canceled... */ for (;;) { /* * Poll for the current state... */ request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, device_uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs); response = cupsDoRequest(http, request, resource); /* * Report any differences... */ for (attr = ippFirstAttribute(response); attr; attr = ippNextAttribute(response)) { const char *name = ippGetName(attr); char value[1024]; /* Name and value */ if (!name) continue; for (i = 0; i < (int)(sizeof(pattrs) / sizeof(pattrs[0])); i ++) if (!strcmp(name, pattrs[i])) break; if (i >= (int)(sizeof(pattrs) / sizeof(pattrs[0]))) continue; ippAttributeString(attr, value, sizeof(value)); if (strcmp(value, pvalues[i])) { if (!strcmp(name, "printer-state-reasons")) fprintf(stderr, "STATE: %s\n", value); else fprintf(stderr, "ATTR: %s=%s\n", name, value); strlcpy(pvalues[i], value, sizeof(pvalues[i])); } } ippDelete(response); /* * Sleep until the next update... */ sleep((unsigned)delay); next_delay = (delay + prev_delay) % 12; prev_delay = next_delay < delay ? 0 : delay; delay = next_delay; } return (NULL); } #ifdef HAVE_MUPDF /* * 'pack_graya()' - Pack GRAYX scanlines into GRAY scanlines. * * This routine is suitable only for 8 bit GRAYX data packed into GRAY bytes. */ static void pack_graya(unsigned char *row, /* I - Row of pixels to pack */ size_t num_pixels) /* I - Number of pixels in row */ { unsigned char *src_byte; /* Remaining source bytes */ unsigned char *dest_byte; /* Remaining destination bytes */ for (src_byte = row + 2, dest_byte = row + 1, num_pixels --; num_pixels > 0; num_pixels --, src_byte += 2) *dest_byte++ = *src_byte; } #endif /* HAVE_MUPDF */ /* * 'pack_rgba()' - Pack RGBX scanlines into RGB scanlines. * * This routine is suitable only for 8 bit RGBX data packed into RGB bytes. */ static void pack_rgba(unsigned char *row, /* I - Row of pixels to pack */ size_t num_pixels) /* I - Number of pixels in row */ { size_t num_quads = num_pixels / 4; /* Number of 4 byte samples to pack */ size_t leftover_pixels = num_pixels & 3; /* Number of pixels remaining */ unsigned *quad_row = (unsigned *)row; /* 32-bit pixel pointer */ unsigned *dest = quad_row; /* Destination pointer */ unsigned char *src_byte; /* Remaining source bytes */ unsigned char *dest_byte; /* Remaining destination bytes */ /* * Copy all of the groups of 4 pixels we can... */ while (num_quads > 0) { *dest++ = (quad_row[0] & XFORM_RGB_MASK) | (quad_row[1] << 24); *dest++ = ((quad_row[1] & XFORM_BG_MASK) >> 8) | ((quad_row[2] & XFORM_RG_MASK) << 16); *dest++ = ((quad_row[2] & XFORM_BLUE_MASK) >> 16) | (quad_row[3] << 8); quad_row += 4; num_quads --; } /* * Then handle the leftover pixels... */ src_byte = (unsigned char *)quad_row; dest_byte = (unsigned char *)dest; while (leftover_pixels > 0) { *dest_byte++ = *src_byte++; *dest_byte++ = *src_byte++; *dest_byte++ = *src_byte++; src_byte ++; leftover_pixels --; } } /* * 'pcl_end_job()' - End a PCL "job". */ static void pcl_end_job(xform_raster_t *ras, /* I - Raster information */ xform_write_cb_t cb, /* I - Write callback */ void *ctx) /* I - Write context */ { (void)ras; /* * Send a PCL reset sequence. */ (*cb)(ctx, (const unsigned char *)"\033E", 2); } /* * 'pcl_end_page()' - End of PCL page. */ static void pcl_end_page(xform_raster_t *ras, /* I - Raster information */ unsigned page, /* I - Current page */ xform_write_cb_t cb, /* I - Write callback */ void *ctx) /* I - Write context */ { /* * End graphics... */ (*cb)(ctx, (const unsigned char *)"\033*r0B", 5); /* * Formfeed as needed... */ if (!(ras->header.Duplex && (page & 1))) (*cb)(ctx, (const unsigned char *)"\014", 1); /* * Free the output buffer... */ free(ras->out_buffer); ras->out_buffer = NULL; } /* * 'pcl_init()' - Initialize callbacks for PCL output. */ static void pcl_init(xform_raster_t *ras) /* I - Raster information */ { ras->end_job = pcl_end_job; ras->end_page = pcl_end_page; ras->start_job = pcl_start_job; ras->start_page = pcl_start_page; ras->write_line = pcl_write_line; } /* * 'pcl_printf()' - Write a formatted string. */ static void pcl_printf(xform_write_cb_t cb, /* I - Write callback */ void *ctx, /* I - Write context */ const char *format, /* I - Printf-style format string */ ...) /* I - Additional arguments as needed */ { va_list ap; /* Argument pointer */ char buffer[8192]; /* Buffer */ va_start(ap, format); vsnprintf(buffer, sizeof(buffer), format, ap); va_end(ap); (*cb)(ctx, (const unsigned char *)buffer, strlen(buffer)); } /* * 'pcl_start_job()' - Start a PCL "job". */ static void pcl_start_job(xform_raster_t *ras, /* I - Raster information */ xform_write_cb_t cb, /* I - Write callback */ void *ctx) /* I - Write context */ { (void)ras; /* * Send a PCL reset sequence. */ (*cb)(ctx, (const unsigned char *)"\033E", 2); } /* * 'pcl_start_page()' - Start a PCL page. */ static void pcl_start_page(xform_raster_t *ras, /* I - Raster information */ unsigned page, /* I - Current page */ xform_write_cb_t cb, /* I - Write callback */ void *ctx) /* I - Write context */ { /* * Setup margins to be 1/6" top and bottom and 1/4" or .135" on the * left and right. */ ras->top = ras->header.HWResolution[1] / 6; ras->bottom = ras->header.cupsHeight - ras->header.HWResolution[1] / 6 - 1; if (ras->header.PageSize[1] == 842) { /* A4 gets special side margins to expose an 8" print area */ ras->left = (ras->header.cupsWidth - 8 * ras->header.HWResolution[0]) / 2; ras->right = ras->left + 8 * ras->header.HWResolution[0] - 1; } else { /* All other sizes get 1/4" margins */ ras->left = ras->header.HWResolution[0] / 4; ras->right = ras->header.cupsWidth - ras->header.HWResolution[0] / 4 - 1; } if (!ras->header.Duplex || (page & 1)) { /* * Set the media size... */ pcl_printf(cb, ctx, "\033&l12D\033&k12H"); /* Set 12 LPI, 10 CPI */ pcl_printf(cb, ctx, "\033&l0O"); /* Set portrait orientation */ switch (ras->header.PageSize[1]) { case 540 : /* Monarch Envelope */ pcl_printf(cb, ctx, "\033&l80A"); break; case 595 : /* A5 */ pcl_printf(cb, ctx, "\033&l25A"); break; case 624 : /* DL Envelope */ pcl_printf(cb, ctx, "\033&l90A"); break; case 649 : /* C5 Envelope */ pcl_printf(cb, ctx, "\033&l91A"); break; case 684 : /* COM-10 Envelope */ pcl_printf(cb, ctx, "\033&l81A"); break; case 709 : /* B5 Envelope */ pcl_printf(cb, ctx, "\033&l100A"); break; case 756 : /* Executive */ pcl_printf(cb, ctx, "\033&l1A"); break; case 792 : /* Letter */ pcl_printf(cb, ctx, "\033&l2A"); break; case 842 : /* A4 */ pcl_printf(cb, ctx, "\033&l26A"); break; case 1008 : /* Legal */ pcl_printf(cb, ctx, "\033&l3A"); break; case 1191 : /* A3 */ pcl_printf(cb, ctx, "\033&l27A"); break; case 1224 : /* Tabloid */ pcl_printf(cb, ctx, "\033&l6A"); break; } /* * Set top margin and turn off perforation skip... */ pcl_printf(cb, ctx, "\033&l%uE\033&l0L", 12 * ras->top / ras->header.HWResolution[1]); if (ras->header.Duplex) { int mode = ras->header.Duplex ? 1 + ras->header.Tumble != 0 : 0; pcl_printf(cb, ctx, "\033&l%dS", mode); /* Set duplex mode */ } } else if (ras->header.Duplex) pcl_printf(cb, ctx, "\033&a2G"); /* Print on back side */ /* * Set graphics mode... */ pcl_printf(cb, ctx, "\033*t%uR", ras->header.HWResolution[0]); /* Set resolution */ pcl_printf(cb, ctx, "\033*r%uS", ras->right - ras->left + 1); /* Set width */ pcl_printf(cb, ctx, "\033*r%uT", ras->bottom - ras->top + 1); /* Set height */ pcl_printf(cb, ctx, "\033&a0H\033&a%uV", 720 * ras->top / ras->header.HWResolution[1]); /* Set position */ pcl_printf(cb, ctx, "\033*b2M"); /* Use PackBits compression */ pcl_printf(cb, ctx, "\033*r1A"); /* Start graphics */ /* * Allocate the output buffer... */ ras->out_blanks = 0; ras->out_length = (ras->right - ras->left + 8) / 8; ras->out_buffer = malloc(ras->out_length); ras->comp_buffer = malloc(2 * ras->out_length + 2); } /* * 'pcl_write_line()' - Write a line of raster data. */ static void pcl_write_line( xform_raster_t *ras, /* I - Raster information */ unsigned y, /* I - Line number */ const unsigned char *line, /* I - Pixels on line */ xform_write_cb_t cb, /* I - Write callback */ void *ctx) /* I - Write context */ { unsigned x; /* Column number */ unsigned char bit, /* Current bit */ byte, /* Current byte */ *outptr, /* Pointer into output buffer */ *outend, /* End of output buffer */ *start, /* Start of sequence */ *compptr; /* Pointer into compression buffer */ unsigned count; /* Count of bytes for output */ if (line[0] == 255 && !memcmp(line, line + 1, ras->right - ras->left)) { /* * Skip blank line... */ ras->out_blanks ++; return; } /* * Dither the line into the output buffer... */ y &= 63; for (x = ras->left, bit = 128, byte = 0, outptr = ras->out_buffer; x <= ras->right; x ++, line ++) { if (*line <= threshold[x & 63][y]) byte |= bit; if (bit == 1) { *outptr++ = byte; byte = 0; bit = 128; } else bit >>= 1; } if (bit != 128) *outptr++ = byte; /* * Apply compression... */ compptr = ras->comp_buffer; outend = outptr; outptr = ras->out_buffer; while (outptr < outend) { if ((outptr + 1) >= outend) { /* * Single byte on the end... */ *compptr++ = 0x00; *compptr++ = *outptr++; } else if (outptr[0] == outptr[1]) { /* * Repeated sequence... */ outptr ++; count = 2; while (outptr < (outend - 1) && outptr[0] == outptr[1] && count < 127) { outptr ++; count ++; } *compptr++ = (unsigned char)(257 - count); *compptr++ = *outptr++; } else { /* * Non-repeated sequence... */ start = outptr; outptr ++; count = 1; while (outptr < (outend - 1) && outptr[0] != outptr[1] && count < 127) { outptr ++; count ++; } *compptr++ = (unsigned char)(count - 1); memcpy(compptr, start, count); compptr += count; } } /* * Output the line... */ if (ras->out_blanks > 0) { /* * Skip blank lines first... */ pcl_printf(cb, ctx, "\033*b%dY", ras->out_blanks); ras->out_blanks = 0; } pcl_printf(cb, ctx, "\033*b%dW", (int)(compptr - ras->comp_buffer)); (*cb)(ctx, ras->comp_buffer, (size_t)(compptr - ras->comp_buffer)); } /* * 'raster_end_job()' - End a raster "job". */ static void raster_end_job(xform_raster_t *ras, /* I - Raster information */ xform_write_cb_t cb, /* I - Write callback */ void *ctx) /* I - Write context */ { (void)cb; (void)ctx; cupsRasterClose(ras->ras); } /* * 'raster_end_page()' - End of raster page. */ static void raster_end_page(xform_raster_t *ras, /* I - Raster information */ unsigned page, /* I - Current page */ xform_write_cb_t cb, /* I - Write callback */ void *ctx) /* I - Write context */ { (void)page; (void)cb; (void)ctx; if (ras->header.cupsBitsPerPixel == 1) { free(ras->out_buffer); ras->out_buffer = NULL; } } /* * 'raster_init()' - Initialize callbacks for raster output. */ static void raster_init(xform_raster_t *ras) /* I - Raster information */ { ras->end_job = raster_end_job; ras->end_page = raster_end_page; ras->start_job = raster_start_job; ras->start_page = raster_start_page; ras->write_line = raster_write_line; } /* * 'raster_start_job()' - Start a raster "job". */ static void raster_start_job(xform_raster_t *ras, /* I - Raster information */ xform_write_cb_t cb, /* I - Write callback */ void *ctx) /* I - Write context */ { ras->ras = cupsRasterOpenIO((cups_raster_iocb_t)cb, ctx, !strcmp(ras->format, "image/pwg-raster") ? CUPS_RASTER_WRITE_PWG : CUPS_RASTER_WRITE_APPLE); } /* * 'raster_start_page()' - Start a raster page. */ static void raster_start_page(xform_raster_t *ras,/* I - Raster information */ unsigned page,/* I - Current page */ xform_write_cb_t cb, /* I - Write callback */ void *ctx)/* I - Write context */ { (void)cb; (void)ctx; ras->left = 0; ras->top = 0; ras->right = ras->header.cupsWidth - 1; ras->bottom = ras->header.cupsHeight - 1; if (ras->header.Duplex && !(page & 1)) cupsRasterWriteHeader2(ras->ras, &ras->back_header); else cupsRasterWriteHeader2(ras->ras, &ras->header); if (ras->header.cupsBitsPerPixel == 1) { ras->out_length = ras->header.cupsBytesPerLine; ras->out_buffer = malloc(ras->header.cupsBytesPerLine); } } /* * 'raster_write_line()' - Write a line of raster data. */ static void raster_write_line( xform_raster_t *ras, /* I - Raster information */ unsigned y, /* I - Line number */ const unsigned char *line, /* I - Pixels on line */ xform_write_cb_t cb, /* I - Write callback */ void *ctx) /* I - Write context */ { (void)cb; (void)ctx; if (ras->header.cupsBitsPerPixel == 1) { /* * Dither the line into the output buffer... */ unsigned x; /* Column number */ unsigned char bit, /* Current bit */ byte, /* Current byte */ *outptr; /* Pointer into output buffer */ y &= 63; if (ras->header.cupsColorSpace == CUPS_CSPACE_SW) { for (x = ras->left, bit = 128, byte = 0, outptr = ras->out_buffer; x <= ras->right; x ++, line ++) { if (*line > threshold[x % 25][y]) byte |= bit; if (bit == 1) { *outptr++ = byte; byte = 0; bit = 128; } else bit >>= 1; } } else { for (x = ras->left, bit = 128, byte = 0, outptr = ras->out_buffer; x <= ras->right; x ++, line ++) { if (*line <= threshold[x & 63][y]) byte |= bit; if (bit == 1) { *outptr++ = byte; byte = 0; bit = 128; } else bit >>= 1; } } if (bit != 128) *outptr++ = byte; cupsRasterWritePixels(ras->ras, ras->out_buffer, ras->header.cupsBytesPerLine); } else cupsRasterWritePixels(ras->ras, (unsigned char *)line, ras->header.cupsBytesPerLine); } /* * 'usage()' - Show program usage. */ static void usage(int status) /* I - Exit status */ { puts("Usage: ipptransform [options] filename\n"); puts("Options:"); puts(" --help"); puts(" -d device-uri"); puts(" -i input/format"); puts(" -m output/format"); puts(" -o \"name=value [... name=value]\""); puts(" -r resolution[,...,resolution]"); puts(" -s {flipped|manual-tumble|normal|rotated}"); puts(" -t type[,...,type]"); puts(" -v\n"); puts("Device URIs: socket://address[:port], ipp://address[:port]/resource, ipps://address[:port]/resource"); puts("Input Formats: application/pdf, image/jpeg"); puts("Output Formats: application/vnd.hp-pcl, image/pwg-raster, image/urf"); puts("Options: copies, media, media-col, page-ranges, print-color-mode, print-quality, print-scaling, printer-resolution, sides"); puts("Resolutions: NNNdpi or NNNxNNNdpi"); puts("Types: black_1, sgray_1, sgray_8, srgb_8"); exit(status); } /* * 'write_fd()' - Write to a file/socket. */ static ssize_t /* O - Number of bytes written or -1 on error */ write_fd(int *fd, /* I - File descriptor */ const unsigned char *buffer, /* I - Buffer */ size_t bytes) /* I - Number of bytes to write */ { ssize_t temp, /* Temporary byte count */ total = 0; /* Total bytes written */ while (bytes > 0) { if ((temp = write(*fd, buffer, bytes)) < 0) { if (errno == EINTR || errno == EAGAIN) continue; else return (-1); } total += temp; bytes -= (size_t)temp; buffer += temp; } return (total); } #ifdef __APPLE__ /* * 'xform_document()' - Transform a file for printing. */ static int /* O - 0 on success, 1 on error */ xform_document( const char *filename, /* I - File to transform */ const char *informat, /* I - Input document (MIME media type */ const char *outformat, /* I - Output format (MIME media type) */ const char *resolutions, /* I - Supported resolutions */ const char *sheet_back, /* I - Back side transform */ const char *types, /* I - Supported types */ int num_options, /* I - Number of options */ cups_option_t *options, /* I - Options */ xform_write_cb_t cb, /* I - Write callback */ void *ctx) /* I - Write context */ { CFURLRef url; /* CFURL object for PDF filename */ CGPDFDocumentRef document= NULL; /* Input document */ CGPDFPageRef pdf_page; /* Page in PDF file */ CGImageSourceRef src; /* Image reader */ CGImageRef image = NULL; /* Image */ xform_raster_t ras; /* Raster info */ size_t max_raster; /* Maximum raster memory to use */ const char *max_raster_env;/* IPPTRANSFORM_MAX_RASTER env var */ CGColorSpaceRef cs; /* Quartz color space */ CGContextRef context; /* Quartz bitmap context */ CGBitmapInfo info; /* Bitmap flags */ size_t band_size; /* Size of band line */ double xscale, yscale; /* Scaling factor */ CGAffineTransform transform, /* Transform for page */ back_transform; /* Transform for back side */ CGRect dest; /* Destination rectangle */ unsigned pages = 1; /* Number of pages */ int color = 1; /* Does the PDF have color? */ const char *page_ranges; /* "page-ranges" option */ unsigned first = 1, /* First page of range */ last = 1; /* Last page of range */ const char *print_scaling; /* print-scaling option */ size_t image_width, /* Image width */ image_height; /* Image height */ int image_rotation; /* Image rotation */ double image_xscale, /* Image scaling */ image_yscale; unsigned copy; /* Current copy */ unsigned page; /* Current page */ unsigned media_sheets = 0, impressions = 0;/* Page/sheet counters */ /* * Open the file... */ if ((url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)filename, (CFIndex)strlen(filename), false)) == NULL) { fputs("ERROR: Unable to create CFURL for file.\n", stderr); return (1); } if (!strcmp(informat, "application/pdf")) { /* * Open the PDF... */ document = CGPDFDocumentCreateWithURL(url); CFRelease(url); if (!document) { fputs("ERROR: Unable to create CFPDFDocument for file.\n", stderr); return (1); } if (CGPDFDocumentIsEncrypted(document)) { /* * Only support encrypted PDFs with a blank password... */ if (!CGPDFDocumentUnlockWithPassword(document, "")) { fputs("ERROR: Document is encrypted and cannot be unlocked.\n", stderr); CGPDFDocumentRelease(document); return (1); } } if (!CGPDFDocumentAllowsPrinting(document)) { fputs("ERROR: Document does not allow printing.\n", stderr); CGPDFDocumentRelease(document); return (1); } /* * Check page ranges... */ if ((page_ranges = cupsGetOption("page-ranges", num_options, options)) != NULL) { if (sscanf(page_ranges, "%u-%u", &first, &last) != 2 || first > last) { fprintf(stderr, "ERROR: Bad \"page-ranges\" value '%s'.\n", page_ranges); CGPDFDocumentRelease(document); return (1); } pages = (unsigned)CGPDFDocumentGetNumberOfPages(document); if (first > pages) { fputs("ERROR: \"page-ranges\" value does not include any pages to print in the document.\n", stderr); CGPDFDocumentRelease(document); return (1); } if (last > pages) last = pages; } else { first = 1; last = (unsigned)CGPDFDocumentGetNumberOfPages(document); } pages = last - first + 1; } else { /* * Open the image... */ if ((src = CGImageSourceCreateWithURL(url, NULL)) == NULL) { CFRelease(url); fputs("ERROR: Unable to create CFImageSourceRef for file.\n", stderr); return (1); } if ((image = CGImageSourceCreateImageAtIndex(src, 0, NULL)) == NULL) { CFRelease(src); CFRelease(url); fputs("ERROR: Unable to create CFImageRef for file.\n", stderr); return (1); } CFRelease(src); CFRelease(url); pages = 1; } /* * Setup the raster context... */ if (xform_setup(&ras, outformat, resolutions, sheet_back, types, color, pages, num_options, options)) { CGPDFDocumentRelease(document); return (1); } if (ras.header.cupsBitsPerPixel != 24) { /* * Grayscale output... */ ras.band_bpp = 1; info = kCGImageAlphaNone; cs = CGColorSpaceCreateWithName(kCGColorSpaceGenericGrayGamma2_2); } else { /* * Color (sRGB) output... */ ras.band_bpp = 4; info = kCGImageAlphaNoneSkipLast; cs = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); } max_raster = XFORM_MAX_RASTER; max_raster_env = getenv("IPPTRANSFORM_MAX_RASTER"); if (max_raster_env && strtol(max_raster_env, NULL, 10) > 0) max_raster = (size_t)strtol(max_raster_env, NULL, 10); band_size = ras.header.cupsWidth * ras.band_bpp; if ((ras.band_height = (unsigned)(max_raster / band_size)) < 1) ras.band_height = 1; else if (ras.band_height > ras.header.cupsHeight) ras.band_height = ras.header.cupsHeight; ras.band_buffer = malloc(ras.band_height * band_size); context = CGBitmapContextCreate(ras.band_buffer, ras.header.cupsWidth, ras.band_height, 8, band_size, cs, info); CGColorSpaceRelease(cs); /* Don't anti-alias or interpolate when creating raster data */ CGContextSetAllowsAntialiasing(context, 0); CGContextSetInterpolationQuality(context, kCGInterpolationNone); xscale = ras.header.HWResolution[0] / 72.0; yscale = ras.header.HWResolution[1] / 72.0; if (Verbosity > 1) fprintf(stderr, "DEBUG: xscale=%g, yscale=%g\n", xscale, yscale); CGContextScaleCTM(context, xscale, yscale); if (Verbosity > 1) fprintf(stderr, "DEBUG: Band height=%u, page height=%u, page translate 0.0,%g\n", ras.band_height, ras.header.cupsHeight, -1.0 * (ras.header.cupsHeight - ras.band_height) / yscale); CGContextTranslateCTM(context, 0.0, -1.0 * (ras.header.cupsHeight - ras.band_height) / yscale); dest.origin.x = dest.origin.y = 0.0; dest.size.width = ras.header.cupsWidth * 72.0 / ras.header.HWResolution[0]; dest.size.height = ras.header.cupsHeight * 72.0 / ras.header.HWResolution[1]; /* * Get print-scaling value... */ if ((print_scaling = cupsGetOption("print-scaling", num_options, options)) == NULL) if ((print_scaling = getenv("PRINTER_PRINT_SCALING_DEFAULT")) == NULL) print_scaling = "auto"; /* * Start the conversion... */ if (Verbosity > 1) fprintf(stderr, "DEBUG: cupsPageSize=[%g %g]\n", ras.header.cupsPageSize[0], ras.header.cupsPageSize[1]); (*(ras.start_job))(&ras, cb, ctx); if (document) { /* * Render pages in the PDF... */ if (pages > 1 && sheet_back && ras.header.Duplex) { /* * Setup the back page transform... */ if (!strcmp(sheet_back, "flipped")) { if (ras.header.Tumble) back_transform = CGAffineTransformMake(-1, 0, 0, 1, ras.header.cupsPageSize[0], 0); else back_transform = CGAffineTransformMake(1, 0, 0, -1, 0, ras.header.cupsPageSize[1]); } else if (!strcmp(sheet_back, "manual-tumble") && ras.header.Tumble) back_transform = CGAffineTransformMake(-1, 0, 0, -1, ras.header.cupsPageSize[0], ras.header.cupsPageSize[1]); else if (!strcmp(sheet_back, "rotated") && !ras.header.Tumble) back_transform = CGAffineTransformMake(-1, 0, 0, -1, ras.header.cupsPageSize[0], ras.header.cupsPageSize[1]); else back_transform = CGAffineTransformMake(1, 0, 0, 1, 0, 0); } else back_transform = CGAffineTransformMake(1, 0, 0, 1, 0, 0); if (Verbosity > 1) fprintf(stderr, "DEBUG: back_transform=[%g %g %g %g %g %g]\n", back_transform.a, back_transform.b, back_transform.c, back_transform.d, back_transform.tx, back_transform.ty); /* * Draw all of the pages... */ for (copy = 0; copy < ras.copies; copy ++) { for (page = 1; page <= pages; page ++) { unsigned y, /* Current line */ band_starty = 0,/* Start line of band */ band_endy = 0; /* End line of band */ unsigned char *lineptr; /* Pointer to line */ pdf_page = CGPDFDocumentGetPage(document, page + first - 1); transform = CGPDFPageGetDrawingTransform(pdf_page, kCGPDFCropBox,dest, 0, true); if (Verbosity > 1) fprintf(stderr, "DEBUG: Printing copy %d/%d, page %d/%d, transform=[%g %g %g %g %g %g]\n", copy + 1, ras.copies, page, pages, transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); (*(ras.start_page))(&ras, page, cb, ctx); for (y = ras.top; y <= ras.bottom; y ++) { if (y > band_endy) { /* * Draw the next band of raster data... */ band_starty = y; band_endy = y + ras.band_height - 1; if (band_endy > ras.bottom) band_endy = ras.bottom; if (Verbosity > 1) fprintf(stderr, "DEBUG: Drawing band from %u to %u.\n", band_starty, band_endy); CGContextSaveGState(context); if (ras.header.cupsNumColors == 1) CGContextSetGrayFillColor(context, 1., 1.); else CGContextSetRGBFillColor(context, 1., 1., 1., 1.); CGContextSetCTM(context, CGAffineTransformIdentity); CGContextFillRect(context, CGRectMake(0., 0., ras.header.cupsWidth, ras.band_height)); CGContextRestoreGState(context); CGContextSaveGState(context); if (Verbosity > 1) fprintf(stderr, "DEBUG: Band translate 0.0,%g\n", y / yscale); CGContextTranslateCTM(context, 0.0, y / yscale); if (!(page & 1) && ras.header.Duplex) CGContextConcatCTM(context, back_transform); CGContextConcatCTM(context, transform); CGContextClipToRect(context, CGPDFPageGetBoxRect(pdf_page, kCGPDFCropBox)); CGContextDrawPDFPage(context, pdf_page); CGContextRestoreGState(context); } /* * Prepare and write a line... */ lineptr = ras.band_buffer + (y - band_starty) * band_size + ras.left * ras.band_bpp; if (ras.band_bpp == 4) pack_rgba(lineptr, ras.right - ras.left + 1); (*(ras.write_line))(&ras, y, lineptr, cb, ctx); } (*(ras.end_page))(&ras, page, cb, ctx); impressions ++; fprintf(stderr, "ATTR: job-impressions-completed=%u\n", impressions); if (!ras.header.Duplex || !(page & 1)) { media_sheets ++; fprintf(stderr, "ATTR: job-media-sheets-completed=%u\n", media_sheets); } } if (ras.copies > 1 && (pages & 1) && ras.header.Duplex) { /* * Duplex printing, add a blank back side image... */ unsigned y; /* Current line */ if (Verbosity > 1) fprintf(stderr, "DEBUG: Printing blank page %u for duplex.\n", pages + 1); memset(ras.band_buffer, 255, ras.header.cupsBytesPerLine); (*(ras.start_page))(&ras, page, cb, ctx); for (y = ras.top; y < ras.bottom; y ++) (*(ras.write_line))(&ras, y, ras.band_buffer, cb, ctx); (*(ras.end_page))(&ras, page, cb, ctx); impressions ++; fprintf(stderr, "ATTR: job-impressions-completed=%u\n", impressions); if (!ras.header.Duplex || !(page & 1)) { media_sheets ++; fprintf(stderr, "ATTR: job-media-sheets-completed=%u\n", media_sheets); } } } CGPDFDocumentRelease(document); } else { /* * Render copies of the image... */ image_width = CGImageGetWidth(image); image_height = CGImageGetHeight(image); if ((image_height < image_width && ras.header.cupsWidth < ras.header.cupsHeight) || (image_width < image_height && ras.header.cupsHeight < ras.header.cupsWidth)) { /* * Rotate image 90 degrees... */ image_rotation = 90; } else { /* * Leave image as-is... */ image_rotation = 0; } if (Verbosity > 1) fprintf(stderr, "DEBUG: image_width=%u, image_height=%u, image_rotation=%d\n", (unsigned)image_width, (unsigned)image_height, image_rotation); if ((!strcmp(print_scaling, "auto") && ras.borderless) || !strcmp(print_scaling, "fill")) { /* * Scale to fill... */ if (image_rotation) { image_xscale = ras.header.cupsPageSize[0] / (double)image_height; image_yscale = ras.header.cupsPageSize[1] / (double)image_width; } else { image_xscale = ras.header.cupsPageSize[0] / (double)image_width; image_yscale = ras.header.cupsPageSize[1] / (double)image_height; } if (image_xscale < image_yscale) image_xscale = image_yscale; else image_yscale = image_xscale; } else { /* * Scale to fit with 1/4" margins... */ if (image_rotation) { image_xscale = (ras.header.cupsPageSize[0] - 36.0) / (double)image_height; image_yscale = (ras.header.cupsPageSize[1] - 36.0) / (double)image_width; } else { image_xscale = (ras.header.cupsPageSize[0] - 36.0) / (double)image_width; image_yscale = (ras.header.cupsPageSize[1] - 36.0) / (double)image_height; } if (image_xscale > image_yscale) image_xscale = image_yscale; else image_yscale = image_xscale; } if (image_rotation) { transform = CGAffineTransformMake(image_xscale, 0, 0, image_yscale, 0.5 * (ras.header.cupsPageSize[0] - image_xscale * image_height), 0.5 * (ras.header.cupsPageSize[1] - image_yscale * image_width)); } else { transform = CGAffineTransformMake(image_xscale, 0, 0, image_yscale, 0.5 * (ras.header.cupsPageSize[0] - image_xscale * image_width), 0.5 * (ras.header.cupsPageSize[1] - image_yscale * image_height)); } /* * Draw all of the copies... */ for (copy = 0; copy < ras.copies; copy ++) { unsigned y, /* Current line */ band_starty = 0,/* Start line of band */ band_endy = 0; /* End line of band */ unsigned char *lineptr; /* Pointer to line */ if (Verbosity > 1) fprintf(stderr, "DEBUG: Printing copy %d/%d, transform=[%g %g %g %g %g %g]\n", copy + 1, ras.copies, transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); (*(ras.start_page))(&ras, 1, cb, ctx); for (y = ras.top; y <= ras.bottom; y ++) { if (y > band_endy) { /* * Draw the next band of raster data... */ band_starty = y; band_endy = y + ras.band_height - 1; if (band_endy > ras.bottom) band_endy = ras.bottom; if (Verbosity > 1) fprintf(stderr, "DEBUG: Drawing band from %u to %u.\n", band_starty, band_endy); CGContextSaveGState(context); if (ras.header.cupsNumColors == 1) CGContextSetGrayFillColor(context, 1., 1.); else CGContextSetRGBFillColor(context, 1., 1., 1., 1.); CGContextSetCTM(context, CGAffineTransformIdentity); CGContextFillRect(context, CGRectMake(0., 0., ras.header.cupsWidth, ras.band_height)); CGContextRestoreGState(context); CGContextSaveGState(context); if (Verbosity > 1) fprintf(stderr, "DEBUG: Band translate 0.0,%g\n", y / yscale); CGContextTranslateCTM(context, 0.0, y / yscale); CGContextConcatCTM(context, transform); if (image_rotation) CGContextConcatCTM(context, CGAffineTransformMake(0, -1, 1, 0, 0, image_width)); CGContextDrawImage(context, CGRectMake(0, 0, image_width, image_height), image); CGContextRestoreGState(context); } /* * Prepare and write a line... */ lineptr = ras.band_buffer + (y - band_starty) * band_size + ras.left * ras.band_bpp; if (ras.band_bpp == 4) pack_rgba(lineptr, ras.right - ras.left + 1); (*(ras.write_line))(&ras, y, lineptr, cb, ctx); } (*(ras.end_page))(&ras, 1, cb, ctx); impressions ++; fprintf(stderr, "ATTR: job-impressions-completed=%u\n", impressions); media_sheets ++; fprintf(stderr, "ATTR: job-media-sheets-completed=%u\n", media_sheets); } CFRelease(image); } (*(ras.end_job))(&ras, cb, ctx); /* * Clean up... */ CGContextRelease(context); return (0); } #else /* * 'xform_document()' - Transform a file for printing. */ static int /* O - 0 on success, 1 on error */ xform_document( const char *filename, /* I - File to transform */ const char *informat, /* I - Input format (MIME media type) */ const char *outformat, /* I - Output format (MIME media type) */ const char *resolutions, /* I - Supported resolutions */ const char *sheet_back, /* I - Back side transform */ const char *types, /* I - Supported types */ int num_options, /* I - Number of options */ cups_option_t *options, /* I - Options */ xform_write_cb_t cb, /* I - Write callback */ void *ctx) /* I - Write context */ { fz_context *context; /* MuPDF context */ fz_document *document; /* Document to print */ fz_page *pdf_page; /* Page in PDF file */ fz_pixmap *pixmap; /* Pixmap for band */ fz_device *device; /* Device for rendering */ fz_colorspace *cs; /* Quartz color space */ xform_raster_t ras; /* Raster info */ size_t max_raster; /* Maximum raster memory to use */ const char *max_raster_env;/* IPPTRANSFORM_MAX_RASTER env var */ unsigned pages = 1; /* Number of pages */ int color = 1; /* Color PDF? */ const char *page_ranges; /* "page-ranges" option */ unsigned first, last; /* First and last page of range */ const char *print_scaling; /* print-scaling option */ unsigned copy; /* Current copy */ unsigned page; /* Current page */ unsigned media_sheets = 0, impressions = 0;/* Page/sheet counters */ size_t band_size; /* Size of band line */ double xscale, yscale; /* Scaling factor */ fz_rect image_box; /* Bounding box of content */ fz_matrix base_transform, /* Base transform */ image_transform,/* Transform for content ("page image") */ transform, /* Transform for page */ back_transform; /* Transform for back side */ /* * Open the PDF file... */ if ((context = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED)) == NULL) { fputs("ERROR: Unable to create context.\n", stderr); return (1); } fz_register_document_handlers(context); fz_try(context) document = fz_open_document(context, filename); fz_catch(context) { fprintf(stderr, "ERROR: Unable to open '%s': %s\n", filename, fz_caught_message(context)); fz_drop_context(context); return (1); } if (fz_needs_password(context, document)) { fputs("ERROR: Document is encrypted and cannot be unlocked.\n", stderr); fz_drop_document(context, document); fz_drop_context(context); return (1); } /* * Check page ranges... */ if ((page_ranges = cupsGetOption("page-ranges", num_options, options)) != NULL) { if (sscanf(page_ranges, "%u-%u", &first, &last) != 2 || first > last) { fprintf(stderr, "ERROR: Bad \"page-ranges\" value '%s'.\n", page_ranges); fz_drop_document(context, document); fz_drop_context(context); return (1); } pages = (unsigned)fz_count_pages(context, document); if (first > pages) { fputs("ERROR: \"page-ranges\" value does not include any pages to print in the document.\n", stderr); fz_drop_document(context, document); fz_drop_context(context); return (1); } if (last > pages) last = pages; } else { first = 1; last = (unsigned)fz_count_pages(context, document); } pages = last - first + 1; /* * Setup the raster context... */ if (xform_setup(&ras, outformat, resolutions, sheet_back, types, color, 1, num_options, options)) { fz_drop_document(context, document); fz_drop_context(context); return (1); } if (ras.header.cupsBitsPerPixel != 24) { /* * Grayscale output... */ ras.band_bpp = 2; /* TODO: Update when alpha is disabled */ cs = fz_device_gray(context); } else { /* * Color (sRGB) output... */ ras.band_bpp = 4; /* TODO: Update when alpha is disabled */ cs = fz_device_rgb(context); } max_raster = XFORM_MAX_RASTER; max_raster_env = getenv("IPPTRANSFORM_MAX_RASTER"); if (max_raster_env && strtol(max_raster_env, NULL, 10) > 0) max_raster = (size_t)strtol(max_raster_env, NULL, 10); band_size = ras.header.cupsWidth * ras.band_bpp; if ((ras.band_height = (unsigned)(max_raster / band_size)) < 1) ras.band_height = 1; else if (ras.band_height > ras.header.cupsHeight) ras.band_height = ras.header.cupsHeight; /* TODO: Update code to not use RGBA/GrayA pixmap now that MuPDF supports it */ pixmap = fz_new_pixmap(context, cs, (int)ras.header.cupsWidth, (int)ras.band_height, NULL, 1); pixmap->flags = 0; pixmap->xres = (int)ras.header.HWResolution[0]; pixmap->yres = (int)ras.header.HWResolution[1]; xscale = ras.header.HWResolution[0] / 72.0; yscale = ras.header.HWResolution[1] / 72.0; if (Verbosity > 1) fprintf(stderr, "DEBUG: xscale=%g, yscale=%g\n", xscale, yscale); fz_scale(&base_transform, xscale, yscale); if (Verbosity > 1) fprintf(stderr, "DEBUG: Band height=%u, page height=%u\n", ras.band_height, ras.header.cupsHeight); device = fz_new_draw_device(context, &base_transform, pixmap); /* Don't anti-alias or interpolate when creating raster data */ fz_set_aa_level(context, 0); fz_enable_device_hints(context, device, FZ_DONT_INTERPOLATE_IMAGES); /* * Setup the back page transform, if any... */ if (sheet_back && ras.header.Duplex) { if (!strcmp(sheet_back, "flipped")) { if (ras.header.Tumble) back_transform = fz_make_matrix(-1, 0, 0, 1, ras.header.cupsPageSize[0], 0); else back_transform = fz_make_matrix(1, 0, 0, -1, 0, ras.header.cupsPageSize[1]); } else if (!strcmp(sheet_back, "manual-tumble") && ras.header.Tumble) back_transform = fz_make_matrix(-1, 0, 0, -1, ras.header.cupsPageSize[0], ras.header.cupsPageSize[1]); else if (!strcmp(sheet_back, "rotated") && !ras.header.Tumble) back_transform = fz_make_matrix(-1, 0, 0, -1, ras.header.cupsPageSize[0], ras.header.cupsPageSize[1]); else back_transform = fz_make_matrix(1, 0, 0, 1, 0, 0); } else back_transform = fz_make_matrix(1, 0, 0, 1, 0, 0); if (Verbosity > 1) fprintf(stderr, "DEBUG: cupsPageSize=[%g %g]\n", ras.header.cupsPageSize[0], ras.header.cupsPageSize[1]); if (Verbosity > 1) fprintf(stderr, "DEBUG: back_transform=[%g %g %g %g %g %g]\n", back_transform.a, back_transform.b, back_transform.c, back_transform.d, back_transform.e, back_transform.f); /* * Get print-scaling value... */ if ((print_scaling = cupsGetOption("print-scaling", num_options, options)) == NULL) if ((print_scaling = getenv("PRINTER_PRINT_SCALING_DEFAULT")) == NULL) print_scaling = "auto"; /* * Draw all of the pages... */ (*(ras.start_job))(&ras, cb, ctx); for (copy = 0; copy < ras.copies; copy ++) { for (page = 1; page <= pages; page ++) { unsigned y, /* Current line */ band_starty = 0,/* Start line of band */ band_endy = 0; /* End line of band */ unsigned char *lineptr; /* Pointer to line */ pdf_page = fz_load_page(context, document, (int)(page + first - 2)); fz_bound_page(context, pdf_page, &image_box); fprintf(stderr, "DEBUG: image_box=[%g %g %g %g]\n", image_box.x0, image_box.y0, image_box.x1, image_box.y1); float image_width = image_box.x1 - image_box.x0; float image_height = image_box.y1 - image_box.y0; int image_rotation = 0; int is_image = strcmp(informat, "application/pdf") != 0; float image_xscale, image_yscale; if ((image_height < image_width && ras.header.cupsWidth < ras.header.cupsHeight) || (image_width < image_height && ras.header.cupsHeight < ras.header.cupsWidth)) { /* * Rotate image/page 90 degrees... */ image_rotation = 90; } if ((!strcmp(print_scaling, "auto") && ras.borderless && is_image) || !strcmp(print_scaling, "fill")) { /* * Scale to fill... */ if (image_rotation) { image_xscale = ras.header.cupsPageSize[0] / (double)image_height; image_yscale = ras.header.cupsPageSize[1] / (double)image_width; } else { image_xscale = ras.header.cupsPageSize[0] / (double)image_width; image_yscale = ras.header.cupsPageSize[1] / (double)image_height; } if (image_xscale < image_yscale) image_xscale = image_yscale; else image_yscale = image_xscale; } else if ((!strcmp(print_scaling, "auto") && (is_image || (image_rotation == 0 && (image_width > ras.header.cupsPageSize[0] || image_height > ras.header.cupsPageSize[1])) || (image_rotation == 90 && (image_height > ras.header.cupsPageSize[1] || image_width > ras.header.cupsPageSize[1])))) || !strcmp(print_scaling, "fit")) { /* * Scale to fit... */ if (image_rotation) { image_xscale = ras.header.cupsPageSize[0] / (double)image_height; image_yscale = ras.header.cupsPageSize[1] / (double)image_width; } else { image_xscale = ras.header.cupsPageSize[0] / (double)image_width; image_yscale = ras.header.cupsPageSize[1] / (double)image_height; } if (image_xscale > image_yscale) image_xscale = image_yscale; else image_yscale = image_xscale; } else { /* * Do not scale... */ image_xscale = image_yscale = 1.0; } if (image_rotation) { image_transform = fz_make_matrix(image_xscale, 0, 0, image_yscale, 0.5 * (ras.header.cupsPageSize[0] - image_xscale * image_height), 0.5 * (ras.header.cupsPageSize[1] - image_yscale * image_width)); } else { image_transform = fz_make_matrix(image_xscale, 0, 0, image_yscale, 0.5 * (ras.header.cupsPageSize[0] - image_xscale * image_width), 0.5 * (ras.header.cupsPageSize[1] - image_yscale * image_height)); } if (Verbosity > 1) fprintf(stderr, "DEBUG: Printing copy %d/%d, page %d/%d, image_transform=[%g %g %g %g %g %g]\n", copy + 1, ras.copies, page, pages, image_transform.a, image_transform.b, image_transform.c, image_transform.d, image_transform.e, image_transform.f); (*(ras.start_page))(&ras, page, cb, ctx); for (y = ras.top; y <= ras.bottom; y ++) { if (y > band_endy) { /* * Draw the next band of raster data... */ band_starty = y; band_endy = y + ras.band_height - 1; if (band_endy > ras.bottom) band_endy = ras.bottom; if (Verbosity > 1) fprintf(stderr, "DEBUG: Drawing band from %u to %u.\n", band_starty, band_endy); fz_clear_pixmap_with_value(context, pixmap, 0xff); transform = fz_identity; fz_pre_translate(&transform, 0.0, -1.0 * y / yscale); if (!(page & 1) && ras.header.Duplex) fz_concat(&transform, &transform, &back_transform); fz_concat(&transform, &transform, &image_transform); fprintf(stderr, "DEBUG: page transform=[%g %g %g %g %g %g]\n", transform.a, transform.b, transform.c, transform.d, transform.e, transform.f); fz_run_page(context, pdf_page, device, &transform, NULL); } /* * Prepare and write a line... */ lineptr = pixmap->samples + (y - band_starty) * band_size + ras.left * ras.band_bpp; if (ras.band_bpp == 4) pack_rgba(lineptr, ras.right - ras.left + 1); else pack_graya(lineptr, ras.right - ras.left + 1); (*(ras.write_line))(&ras, y, lineptr, cb, ctx); } (*(ras.end_page))(&ras, page, cb, ctx); impressions ++; fprintf(stderr, "ATTR: job-impressions-completed=%u\n", impressions); if (!ras.header.Duplex || !(page & 1)) { media_sheets ++; fprintf(stderr, "ATTR: job-media-sheets-completed=%u\n", media_sheets); } } if (ras.copies > 1 && (pages & 1) && ras.header.Duplex) { /* * Duplex printing, add a blank back side image... */ unsigned y; /* Current line */ if (Verbosity > 1) fprintf(stderr, "DEBUG: Printing blank page %u for duplex.\n", pages + 1); memset(pixmap->samples, 255, ras.header.cupsBytesPerLine); (*(ras.start_page))(&ras, page, cb, ctx); for (y = ras.top; y < ras.bottom; y ++) (*(ras.write_line))(&ras, y, pixmap->samples, cb, ctx); (*(ras.end_page))(&ras, page, cb, ctx); impressions ++; fprintf(stderr, "ATTR: job-impressions-completed=%u\n", impressions); if (!ras.header.Duplex || !(page & 1)) { media_sheets ++; fprintf(stderr, "ATTR: job-media-sheets-completed=%u\n", media_sheets); } } } (*(ras.end_job))(&ras, cb, ctx); /* * Clean up... */ fz_drop_device(context, device); fz_drop_pixmap(context, pixmap); fz_drop_document(context, document); fz_drop_context(context); return (1); } #endif /* __APPLE__ */ /* * 'xform_setup()' - Setup a raster context for printing. */ static int /* O - 0 on success, -1 on failure */ xform_setup(xform_raster_t *ras, /* I - Raster information */ const char *format, /* I - Output format (MIME media type) */ const char *resolutions,/* I - Supported resolutions */ const char *sheet_back, /* I - Back side transform */ const char *types, /* I - Supported types */ int color, /* I - Document contains color? */ unsigned pages, /* I - Number of pages */ int num_options, /* I - Number of options */ cups_option_t *options) /* I - Options */ { const char *copies, /* "copies" option */ *media, /* "media" option */ *media_col; /* "media-col" option */ pwg_media_t *pwg_media = NULL; /* PWG media value */ const char *print_quality, /* "print-quality" option */ *printer_resolution, /* "printer-resolution" option */ *sides, /* "sides" option */ *type; /* Raster type to use */ int draft = 0, /* Draft quality? */ xdpi, ydpi; /* Resolution to use */ cups_array_t *res_array, /* Resolutions in array */ *type_array; /* Types in array */ /* * Initialize raster information... */ memset(ras, 0, sizeof(xform_raster_t)); ras->format = format; ras->num_options = num_options; ras->options = options; if (!strcmp(format, "application/vnd.hp-pcl")) pcl_init(ras); else raster_init(ras); /* * Get the number of copies... */ if ((copies = cupsGetOption("copies", num_options, options)) != NULL) { int temp = atoi(copies); /* Copies value */ if (temp < 1 || temp > 9999) { fprintf(stderr, "ERROR: Invalid \"copies\" value '%s'.\n", copies); return (-1); } ras->copies = (unsigned)temp; } else ras->copies = 1; /* * Figure out the media size... */ if ((media = cupsGetOption("media", num_options, options)) != NULL) { if ((pwg_media = pwgMediaForPWG(media)) == NULL) pwg_media = pwgMediaForLegacy(media); if (!pwg_media) { fprintf(stderr, "ERROR: Unknown \"media\" value '%s'.\n", media); return (-1); } } else if ((media_col = cupsGetOption("media-col", num_options, options)) != NULL) { int num_cols; /* Number of collection values */ cups_option_t *cols; /* Collection values */ const char *media_size_name, *media_size, /* Collection attributes */ *media_bottom_margin, *media_left_margin, *media_right_margin, *media_top_margin; num_cols = cupsParseOptions(media_col, 0, &cols); if ((media_size_name = cupsGetOption("media-size-name", num_cols, cols)) != NULL) { if ((pwg_media = pwgMediaForPWG(media_size_name)) == NULL) { fprintf(stderr, "ERROR: Unknown \"media-size-name\" value '%s'.\n", media_size_name); cupsFreeOptions(num_cols, cols); return (-1); } } else if ((media_size = cupsGetOption("media-size", num_cols, cols)) != NULL) { int num_sizes; /* Number of collection values */ cups_option_t *sizes; /* Collection values */ const char *x_dim, /* Collection attributes */ *y_dim; num_sizes = cupsParseOptions(media_size, 0, &sizes); if ((x_dim = cupsGetOption("x-dimension", num_sizes, sizes)) != NULL && (y_dim = cupsGetOption("y-dimension", num_sizes, sizes)) != NULL) { pwg_media = pwgMediaForSize(atoi(x_dim), atoi(y_dim)); } else { fprintf(stderr, "ERROR: Bad \"media-size\" value '%s'.\n", media_size); cupsFreeOptions(num_sizes, sizes); cupsFreeOptions(num_cols, cols); return (-1); } cupsFreeOptions(num_sizes, sizes); } /* * Check whether the media-col is for a borderless size... */ if ((media_bottom_margin = cupsGetOption("media-bottom-margin", num_cols, cols)) != NULL && !strcmp(media_bottom_margin, "0") && (media_left_margin = cupsGetOption("media-left-margin", num_cols, cols)) != NULL && !strcmp(media_left_margin, "0") && (media_right_margin = cupsGetOption("media-right-margin", num_cols, cols)) != NULL && !strcmp(media_right_margin, "0") && (media_top_margin = cupsGetOption("media-top-margin", num_cols, cols)) != NULL && !strcmp(media_top_margin, "0")) ras->borderless = 1; cupsFreeOptions(num_cols, cols); } if (!pwg_media) { /* * Use default size... */ const char *media_default = getenv("PRINTER_MEDIA_DEFAULT"); /* "media-default" value */ if (!media_default) media_default = "na_letter_8.5x11in"; if ((pwg_media = pwgMediaForPWG(media_default)) == NULL) { fprintf(stderr, "ERROR: Unknown \"media-default\" value '%s'.\n", media_default); return (-1); } } /* * Map certain photo sizes (4x6, 5x7, 8x10) to borderless... */ if ((pwg_media->width == 10160 && pwg_media->length == 15240) ||(pwg_media->width == 12700 && pwg_media->length == 17780) ||(pwg_media->width == 20320 && pwg_media->length == 25400)) ras->borderless = 1; /* * Figure out the proper resolution, etc. */ res_array = _cupsArrayNewStrings(resolutions, ','); if ((printer_resolution = cupsGetOption("printer-resolution", num_options, options)) != NULL && !cupsArrayFind(res_array, (void *)printer_resolution)) { if (Verbosity) fprintf(stderr, "INFO: Unsupported \"printer-resolution\" value '%s'.\n", printer_resolution); printer_resolution = NULL; } if (!printer_resolution) { if ((print_quality = cupsGetOption("print-quality", num_options, options)) != NULL) { switch (atoi(print_quality)) { case IPP_QUALITY_DRAFT : draft = 1; printer_resolution = cupsArrayIndex(res_array, 0); break; case IPP_QUALITY_NORMAL : printer_resolution = cupsArrayIndex(res_array, cupsArrayCount(res_array) / 2); break; case IPP_QUALITY_HIGH : printer_resolution = cupsArrayIndex(res_array, cupsArrayCount(res_array) - 1); break; default : if (Verbosity) fprintf(stderr, "INFO: Unsupported \"print-quality\" value '%s'.\n", print_quality); break; } } } if (!printer_resolution) printer_resolution = cupsArrayIndex(res_array, cupsArrayCount(res_array) / 2); if (!printer_resolution) { fputs("ERROR: No \"printer-resolution\" or \"pwg-raster-document-resolution-supported\" value.\n", stderr); return (-1); } /* * Parse the "printer-resolution" value... */ if (sscanf(printer_resolution, "%ux%udpi", &xdpi, &ydpi) != 2) { if (sscanf(printer_resolution, "%udpi", &xdpi) == 1) { ydpi = xdpi; } else { fprintf(stderr, "ERROR: Bad resolution value '%s'.\n", printer_resolution); return (-1); } } cupsArrayDelete(res_array); /* * Now figure out the color space to use... */ type_array = _cupsArrayNewStrings(types, ','); if (color && cupsArrayFind(type_array, "srgb_8")) type = "srgb_8"; else if (draft && cupsArrayFind(type_array, "black_1")) type = "black_1"; else if (draft && cupsArrayFind(type_array, "sgray_1")) type = "sgray_1"; else type = "sgray_8"; /* * Initialize the raster header... */ if (pages == 1) sides = "one-sided"; else if ((sides = cupsGetOption("sides", num_options, options)) == NULL) { if ((sides = getenv("PRINTER_SIDES_DEFAULT")) == NULL) sides = "one-sided"; } if (ras->copies > 1 && (pages & 1) && strcmp(sides, "one-sided")) pages ++; if (!cupsRasterInitPWGHeader(&(ras->header), pwg_media, type, xdpi, ydpi, sides, NULL)) { fprintf(stderr, "ERROR: Unable to initialize raster context: %s\n", cupsRasterErrorString()); return (-1); } if (pages > 1) { if (!cupsRasterInitPWGHeader(&(ras->back_header), pwg_media, type, xdpi, ydpi, sides, sheet_back)) { fprintf(stderr, "ERROR: Unable to initialize back side raster context: %s\n", cupsRasterErrorString()); return (-1); } } ras->header.cupsInteger[CUPS_RASTER_PWG_TotalPageCount] = ras->copies * pages; ras->back_header.cupsInteger[CUPS_RASTER_PWG_TotalPageCount] = ras->copies * pages; return (0); } ippsample/DOCKER.md0000644000175000017500000000303713240604116013033 0ustar tilltill# Docker Support for IPP Sample Code This repository includes a sample Docker configuration file ("ippsample.docker") for running ippserver in a Docker container. To run IPP sample code on Docker: 1. From a shell prompt in the directory (on Windows 10|2016, OS/X, or Linux) containing this docker file run: docker build -t --security-opt seccomp=unconfined ubuntu[-ippserver | -ippclient] . docker run -it -v d:\DockerShare:/data --security-opt seccomp=unconfined ubuntu-[ippclient | ippserver] bash 2. From the bash prompt on the newly created container as root, start the services needed for Bonjour service dbus start service avahi-daemon start To start the IPP server: 1. In the ippserver container run: ippserver -M byMyself -l rightHere -m coolPrinter -n myHost -p 631 -s 72 -vvvv myPrintService 2. OR to run the server in debug mode using gdb: gdb ippserver run -M byMyself -l rightHere -m coolPrinter -n myHost -p 631 -s 72 -vvvv myPrintService Run the IPP Client: 1. From the bash command prompt on the IPP client container and in the /root/ippsample/examples directory with the IPP Server running, run: ippfind (Note the URL returned, e.g., ipp://f8a365cfc7ec.local:631/ipp/print) ipptool [URL returned] identify-printer-display.test (Note the "IDENTIFY from 172.17.0.4: Hello, World!" message in stdout on the ippserver container) 2. To run the IPP everywhere tests on the IPP Client using setup from step #1, run: ipptool -V 2.0 -tf document-letter.pdf [URL returned] ipp-everywhere.test ippsample/.gitignore0000644000175000017500000000066313240604116013534 0ustar tilltillMakedefs autom4te.cache config.h config.log config.status cups/libcups.a cups/org.pwg.ippsample.* cups/test.raster cups/testarray cups/testclient cups/testdest cups/testfile cups/testhttp cups/testi18n cups/testipp cups/testoptions cups/testraster doc/mantohtml parts prime server/ippserver stage tools/ippfind tools/ippproxy tools/ipptool tools/ipptransform tools/ipptransform3d xcuserdata *.dSYM *.log *.o *.ras *.snap *.xcworkspace ippsample/.gitattributes0000644000175000017500000000010513240604116014426 0ustar tilltill.git* export-ignore .mailmap export-ignore .travis.yml export-ignore ippsample/LICENSE0000644000175000017500000002613613240604116012554 0ustar tilltill Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ippsample/Makefile0000644000175000017500000000270013240604116013176 0ustar tilltill# # Top-level Makefile for IPP sample implementations. # # Copyright © 2014-2018 by the IEEE-ISTO Printer Working Group. # Copyright © 2007-2018 by Apple Inc. # Copyright © 1997-2007 by Easy Software Products, all rights reserved. # # Licensed under Apache License v2.0. See the file "LICENSE" for more # information. # include Makedefs # Source directories... DIRS = \ cups \ server \ tools # # Make all targets... # all: for dir in $(DIRS); do \ echo Making all in $$dir...; \ (cd $$dir; $(MAKE) $(MFLAGS) all) || exit 1; \ done # # Remove object and target files... # clean: for dir in $(DIRS); do \ echo Cleaning all in $$dir...; \ (cd $$dir; $(MAKE) $(MFLAGS) clean) || exit 1; \ done # # Remove all non-distribution files... # distclean: clean $(RM) Makedefs config.h config.log config.status -$(RM) -r autom4te*.cache # # Make dependencies # depend: for dir in $(DIRS); do \ echo Updating dependencies in $$dir...; \ (cd $$dir; $(MAKE) $(MFLAGS) depend) || exit 1; \ done # # Install everything... # install: for dir in $(DIRS) doc; do \ echo Installing in $$dir...; \ (cd $$dir; $(MAKE) $(MFLAGS) install) || exit 1; \ done # # Test everything... # .PHONY: test test: for dir in $(DIRS); do \ echo Testing in $$dir...; \ (cd $$dir; $(MAKE) $(MFLAGS) test) || exit 1; \ done echo Running integration tests... test/run-tests.sh # # Don't run top-level build targets in parallel... # .NOTPARALLEL: ippsample/vcnet/0000755000175000017500000000000013240604116012656 5ustar tilltillippsample/vcnet/ippfind.vcxproj0000644000175000017500000002401313240604116015724 0ustar tilltill Debug Win32 Debug x64 Release Win32 Release x64 {B484DA0C-62C8-4C32-83B6-CCEB58968B85} ippfind Win32Proj Application v120 Unicode true Application v120 Unicode Application v120 Unicode true Application v120 Unicode <_ProjectFileVersion>12.0.30501.0 $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ true $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ true $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ false $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ false Disabled ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level1 EditAndContinue dnssd.lib;ws2_32.lib;%(AdditionalDependencies) true Console false MachineX86 X64 Disabled ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level1 ProgramDatabase dnssd.lib;ws2_32.lib;%(AdditionalDependencies) true Console false MachineX64 ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) MultiThreadedDLL Level1 ProgramDatabase dnssd.lib;ws2_32.lib;%(AdditionalDependencies) true Console true true false MachineX86 Sign code with IEEE-ISTO cert. signtool sign /n "IEEE INDUSTRY STANDARDS AND TECHNOLOGY ORGANIZATION" $(TargetPath) X64 ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) MultiThreadedDLL Level1 ProgramDatabase dnssd.lib;ws2_32.lib;%(AdditionalDependencies) true Console true true false MachineX64 signtool sign /n "IEEE INDUSTRY STANDARDS AND TECHNOLOGY ORGANIZATION" $(TargetPath) Sign code with IEEE-ISTO cert. {cb4aa6f2-3e84-45be-b505-95cd375e8be3} false {18950a1b-d37a-40c7-b2df-c12986c0526e} false ippsample/vcnet/signmsi.bat0000644000175000017500000000022413240604116015015 0ustar tilltill"C:\Program Files\Windows Kits\8.1\bin\x86\signtool" sign /n "IEEE Industry Standards and Technology Organization" sw-ippeveselfcert10-windows.msi ippsample/vcnet/setdebug.bat0000644000175000017500000000030013240604116015141 0ustar tilltill@rem Script to enable debug logging for IPPTOOL set CUPS_DEBUG_LOG=ipptool.log set CUPS_DEBUG_LEVEL=6 set "CUPS_DEBUG_FILTER=^(http|_http|ipp|_ipp|cupsDo|cupsGetResponse|cupsSend|cupsWrite)" ippsample/vcnet/regex.vcxproj0000644000175000017500000002344613240604116015416 0ustar tilltill Debug Win32 Debug x64 Release Win32 Release x64 {18950A1B-D37A-40C7-B2DF-C12986C0526E} regex Win32Proj DynamicLibrary v120 Unicode true DynamicLibrary v120 Unicode DynamicLibrary v120 Unicode true DynamicLibrary v120 Unicode <_ProjectFileVersion>12.0.30501.0 $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ true $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ false $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ true $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ false Disabled regex;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;REGEX_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue regex/regex.def true Windows MachineX86 MaxSpeed true regex;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;REGEX_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase regex/regex.def true Windows true true MachineX86 signtool sign /n "IEEE INDUSTRY STANDARDS AND TECHNOLOGY ORGANIZATION" $(TargetPath) Sign code with IEEE-ISTO cert. X64 Disabled regex;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;REGEX_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 ProgramDatabase regex/regex.def true Windows MachineX64 X64 MaxSpeed true regex;%(AdditionalIncludeDirectories) _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;REGEX_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase regex/regex.def true Windows true true MachineX64 signtool sign /n "IEEE INDUSTRY STANDARDS AND TECHNOLOGY ORGANIZATION" $(TargetPath) Sign code with IEEE-ISTO cert. ippsample/vcnet/ippsample.sln0000644000175000017500000001057113240604116015372 0ustar tilltillMicrosoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcups2", "libcups2.vcxproj", "{CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ipptool", "ipptool.vcxproj", "{B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regex", "regex.vcxproj", "{18950A1B-D37A-40C7-B2DF-C12986C0526E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ippfind", "ippfind.vcxproj", "{B484DA0C-62C8-4C32-83B6-CCEB58968B85}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ippserver", "ippserver.vcxproj", "{82A03BC7-0746-4B85-8908-3C7A3FAA58A9}" ProjectSection(ProjectDependencies) = postProject {18950A1B-D37A-40C7-B2DF-C12986C0526E} = {18950A1B-D37A-40C7-B2DF-C12986C0526E} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|Win32.ActiveCfg = Debug|Win32 {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|Win32.Build.0 = Debug|Win32 {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|x64.ActiveCfg = Debug|x64 {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|x64.Build.0 = Debug|x64 {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|Win32.ActiveCfg = Release|Win32 {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|Win32.Build.0 = Release|Win32 {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|x64.ActiveCfg = Release|x64 {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|x64.Build.0 = Release|x64 {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Debug|Win32.ActiveCfg = Debug|Win32 {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Debug|Win32.Build.0 = Debug|Win32 {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Debug|x64.ActiveCfg = Debug|x64 {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Debug|x64.Build.0 = Debug|x64 {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Release|Win32.ActiveCfg = Release|Win32 {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Release|Win32.Build.0 = Release|Win32 {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Release|x64.ActiveCfg = Release|x64 {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}.Release|x64.Build.0 = Release|x64 {18950A1B-D37A-40C7-B2DF-C12986C0526E}.Debug|Win32.ActiveCfg = Debug|Win32 {18950A1B-D37A-40C7-B2DF-C12986C0526E}.Debug|Win32.Build.0 = Debug|Win32 {18950A1B-D37A-40C7-B2DF-C12986C0526E}.Debug|x64.ActiveCfg = Debug|x64 {18950A1B-D37A-40C7-B2DF-C12986C0526E}.Debug|x64.Build.0 = Debug|x64 {18950A1B-D37A-40C7-B2DF-C12986C0526E}.Release|Win32.ActiveCfg = Release|Win32 {18950A1B-D37A-40C7-B2DF-C12986C0526E}.Release|Win32.Build.0 = Release|Win32 {18950A1B-D37A-40C7-B2DF-C12986C0526E}.Release|x64.ActiveCfg = Release|x64 {18950A1B-D37A-40C7-B2DF-C12986C0526E}.Release|x64.Build.0 = Release|x64 {B484DA0C-62C8-4C32-83B6-CCEB58968B85}.Debug|Win32.ActiveCfg = Debug|Win32 {B484DA0C-62C8-4C32-83B6-CCEB58968B85}.Debug|Win32.Build.0 = Debug|Win32 {B484DA0C-62C8-4C32-83B6-CCEB58968B85}.Debug|x64.ActiveCfg = Debug|x64 {B484DA0C-62C8-4C32-83B6-CCEB58968B85}.Debug|x64.Build.0 = Debug|x64 {B484DA0C-62C8-4C32-83B6-CCEB58968B85}.Release|Win32.ActiveCfg = Release|Win32 {B484DA0C-62C8-4C32-83B6-CCEB58968B85}.Release|Win32.Build.0 = Release|Win32 {B484DA0C-62C8-4C32-83B6-CCEB58968B85}.Release|x64.ActiveCfg = Release|x64 {B484DA0C-62C8-4C32-83B6-CCEB58968B85}.Release|x64.Build.0 = Release|x64 {82A03BC7-0746-4B85-8908-3C7A3FAA58A9}.Debug|Win32.ActiveCfg = Debug|Win32 {82A03BC7-0746-4B85-8908-3C7A3FAA58A9}.Debug|Win32.Build.0 = Debug|Win32 {82A03BC7-0746-4B85-8908-3C7A3FAA58A9}.Debug|x64.ActiveCfg = Debug|x64 {82A03BC7-0746-4B85-8908-3C7A3FAA58A9}.Debug|x64.Build.0 = Debug|x64 {82A03BC7-0746-4B85-8908-3C7A3FAA58A9}.Release|Win32.ActiveCfg = Release|Win32 {82A03BC7-0746-4B85-8908-3C7A3FAA58A9}.Release|Win32.Build.0 = Release|Win32 {82A03BC7-0746-4B85-8908-3C7A3FAA58A9}.Release|x64.ActiveCfg = Release|x64 {82A03BC7-0746-4B85-8908-3C7A3FAA58A9}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ippsample/vcnet/regex/0000755000175000017500000000000013240604116013770 5ustar tilltillippsample/vcnet/regex/regerror.c0000644000175000017500000000610613240604116015766 0ustar tilltill#include #include #include #include #include #include #include #include "utils.h" #include "regerror.ih" /* = #define REG_OKAY 0 = #define REG_NOMATCH 1 = #define REG_BADPAT 2 = #define REG_ECOLLATE 3 = #define REG_ECTYPE 4 = #define REG_EESCAPE 5 = #define REG_ESUBREG 6 = #define REG_EBRACK 7 = #define REG_EPAREN 8 = #define REG_EBRACE 9 = #define REG_BADBR 10 = #define REG_ERANGE 11 = #define REG_ESPACE 12 = #define REG_BADRPT 13 = #define REG_EMPTY 14 = #define REG_ASSERT 15 = #define REG_INVARG 16 = #define REG_ATOI 255 // convert name to number (!) = #define REG_ITOA 0400 // convert number to name (!) */ static struct rerr { int code; char *name; char *explain; } rerrs[] = { REG_OKAY, "REG_OKAY", "no errors detected", REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match", REG_BADPAT, "REG_BADPAT", "invalid regular expression", REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element", REG_ECTYPE, "REG_ECTYPE", "invalid character class", REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)", REG_ESUBREG, "REG_ESUBREG", "invalid backreference number", REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced", REG_EPAREN, "REG_EPAREN", "parentheses not balanced", REG_EBRACE, "REG_EBRACE", "braces not balanced", REG_BADBR, "REG_BADBR", "invalid repetition count(s)", REG_ERANGE, "REG_ERANGE", "invalid character range", REG_ESPACE, "REG_ESPACE", "out of memory", REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid", REG_EMPTY, "REG_EMPTY", "empty (sub)expression", REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug", REG_INVARG, "REG_INVARG", "invalid argument to regex routine", -1, "", "*** unknown regexp error code ***", }; /* - regerror - the interface to error numbers = extern size_t regerror(int, const regex_t *, char *, size_t); */ /* ARGSUSED */ size_t regerror( int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) { register struct rerr *r; register size_t len; register int target = errcode &~ REG_ITOA; register char *s; char convbuf[50]; if (errcode == REG_ATOI) s = regatoi(preg, convbuf); else { for (r = rerrs; r->code >= 0; r++) if (r->code == target) break; if (errcode®_ITOA) { if (r->code >= 0) (void) strcpy(convbuf, r->name); else sprintf(convbuf, "REG_0x%x", target); assert(strlen(convbuf) < sizeof(convbuf)); s = convbuf; } else s = r->explain; } len = strlen(s) + 1; if (errbuf_size > 0) { if (errbuf_size > len) (void) strcpy(errbuf, s); else { (void) strncpy(errbuf, s, errbuf_size-1); errbuf[errbuf_size-1] = '\0'; } } return(len); } /* - regatoi - internal routine to implement REG_ATOI == static char *regatoi(const regex_t *preg, char *localbuf); */ static char * regatoi(preg, localbuf) const regex_t *preg; char *localbuf; { register struct rerr *r; for (r = rerrs; r->code >= 0; r++) if (strcmp(r->name, preg->re_endp) == 0) break; if (r->code < 0) return("0"); sprintf(localbuf, "%d", r->code); return(localbuf); } ippsample/vcnet/regex/tests0000644000175000017500000003001613240604116015055 0ustar tilltill# regular expression test set # Lines are at least three fields, separated by one or more tabs. "" stands # for an empty field. First field is an RE. Second field is flags. If # C flag given, regcomp() is expected to fail, and the third field is the # error name (minus the leading REG_). # # Otherwise it is expected to succeed, and the third field is the string to # try matching it against. If there is no fourth field, the match is # expected to fail. If there is a fourth field, it is the substring that # the RE is expected to match. If there is a fifth field, it is a comma- # separated list of what the subexpressions should match, with - indicating # no match for that one. In both the fourth and fifth fields, a (sub)field # starting with @ indicates that the (sub)expression is expected to match # a null string followed by the stuff after the @; this provides a way to # test where null strings match. The character `N' in REs and strings # is newline, `S' is space, `T' is tab, `Z' is NUL. # # The full list of flags: # - placeholder, does nothing # b RE is a BRE, not an ERE # & try it as both an ERE and a BRE # C regcomp() error expected, third field is error name # i REG_ICASE # m ("mundane") REG_NOSPEC # s REG_NOSUB (not really testable) # n REG_NEWLINE # ^ REG_NOTBOL # $ REG_NOTEOL # # REG_STARTEND (see below) # p REG_PEND # # For REG_STARTEND, the start/end offsets are those of the substring # enclosed in (). # basics a & a a abc & abc abc abc|de - abc abc a|b|c - abc a # parentheses and perversions thereof a(b)c - abc abc a\(b\)c b abc abc a( C EPAREN a( b a( a( a\( - a( a( a\( bC EPAREN a\(b bC EPAREN a(b C EPAREN a(b b a(b a(b # gag me with a right parenthesis -- 1003.2 goofed here (my fault, partly) a) - a) a) ) - ) ) # end gagging (in a just world, those *should* give EPAREN) a) b a) a) a\) bC EPAREN \) bC EPAREN a()b - ab ab a\(\)b b ab ab # anchoring and REG_NEWLINE ^abc$ & abc abc a^b - a^b a^b b a^b a^b a$b - a$b a$b b a$b a$b ^ & abc @abc $ & abc @ ^$ & "" @ $^ - "" @ \($\)\(^\) b "" @ # stop retching, those are legitimate (although disgusting) ^^ - "" @ $$ - "" @ b$ & abNc b$ &n abNc b ^b$ & aNbNc ^b$ &n aNbNc b ^$ &n aNNb @Nb ^$ n abc ^$ n abcN @ $^ n aNNb @Nb \($\)\(^\) bn aNNb @Nb ^^ n^ aNNb @Nb $$ n aNNb @NN ^a ^ a a$ $ a ^a ^n aNb ^b ^n aNb b a$ $n bNa b$ $n bNa b a*(^b$)c* - b b a*\(^b$\)c* b b b # certain syntax errors and non-errors | C EMPTY | b | | * C BADRPT * b * * + C BADRPT ? C BADRPT "" &C EMPTY () - abc @abc \(\) b abc @abc a||b C EMPTY |ab C EMPTY ab| C EMPTY (|a)b C EMPTY (a|)b C EMPTY (*a) C BADRPT (+a) C BADRPT (?a) C BADRPT ({1}a) C BADRPT \(\{1\}a\) bC BADRPT (a|*b) C BADRPT (a|+b) C BADRPT (a|?b) C BADRPT (a|{1}b) C BADRPT ^* C BADRPT ^* b * * ^+ C BADRPT ^? C BADRPT ^{1} C BADRPT ^\{1\} bC BADRPT # metacharacters, backslashes a.c & abc abc a[bc]d & abd abd a\*c & a*c a*c a\\b & a\b a\b a\\\*b & a\*b a\*b a\bc & abc abc a\ &C EESCAPE a\\bc & a\bc a\bc \{ bC BADRPT a\[b & a[b a[b a[b &C EBRACK # trailing $ is a peculiar special case for the BRE code a$ & a a a$ & a$ a\$ & a a\$ & a$ a$ a\\$ & a a\\$ & a$ a\\$ & a\$ a\\$ & a\ a\ # back references, ugh a\(b\)\2c bC ESUBREG a\(b\1\)c bC ESUBREG a\(b*\)c\1d b abbcbbd abbcbbd bb a\(b*\)c\1d b abbcbd a\(b*\)c\1d b abbcbbbd ^\(.\)\1 b abc a\([bc]\)\1d b abcdabbd abbd b a\(\([bc]\)\2\)*d b abbccd abbccd a\(\([bc]\)\2\)*d b abbcbd # actually, this next one probably ought to fail, but the spec is unclear a\(\(b\)*\2\)*d b abbbd abbbd # here is a case that no NFA implementation does right \(ab*\)[ab]*\1 b ababaaa ababaaa a # check out normal matching in the presence of back refs \(a\)\1bcd b aabcd aabcd \(a\)\1bc*d b aabcd aabcd \(a\)\1bc*d b aabd aabd \(a\)\1bc*d b aabcccd aabcccd \(a\)\1bc*[ce]d b aabcccd aabcccd ^\(a\)\1b\(c\)*cd$ b aabcccd aabcccd # ordinary repetitions ab*c & abc abc ab+c - abc abc ab?c - abc abc a\(*\)b b a*b a*b a\(**\)b b ab ab a\(***\)b bC BADRPT *a b *a *a **a b a a ***a bC BADRPT # the dreaded bounded repetitions { & { { {abc & {abc {abc {1 C BADRPT {1} C BADRPT a{b & a{b a{b a{1}b - ab ab a\{1\}b b ab ab a{1,}b - ab ab a\{1,\}b b ab ab a{1,2}b - aab aab a\{1,2\}b b aab aab a{1 C EBRACE a\{1 bC EBRACE a{1a C EBRACE a\{1a bC EBRACE a{1a} C BADBR a\{1a\} bC BADBR a{,2} - a{,2} a{,2} a\{,2\} bC BADBR a{,} - a{,} a{,} a\{,\} bC BADBR a{1,x} C BADBR a\{1,x\} bC BADBR a{1,x C EBRACE a\{1,x bC EBRACE a{300} C BADBR a\{300\} bC BADBR a{1,0} C BADBR a\{1,0\} bC BADBR ab{0,0}c - abcac ac ab\{0,0\}c b abcac ac ab{0,1}c - abcac abc ab\{0,1\}c b abcac abc ab{0,3}c - abbcac abbc ab\{0,3\}c b abbcac abbc ab{1,1}c - acabc abc ab\{1,1\}c b acabc abc ab{1,3}c - acabc abc ab\{1,3\}c b acabc abc ab{2,2}c - abcabbc abbc ab\{2,2\}c b abcabbc abbc ab{2,4}c - abcabbc abbc ab\{2,4\}c b abcabbc abbc ((a{1,10}){1,10}){1,10} - a a a,a # multiple repetitions a** &C BADRPT a++ C BADRPT a?? C BADRPT a*+ C BADRPT a*? C BADRPT a+* C BADRPT a+? C BADRPT a?* C BADRPT a?+ C BADRPT a{1}{1} C BADRPT a*{1} C BADRPT a+{1} C BADRPT a?{1} C BADRPT a{1}* C BADRPT a{1}+ C BADRPT a{1}? C BADRPT a*{b} - a{b} a{b} a\{1\}\{1\} bC BADRPT a*\{1\} bC BADRPT a\{1\}* bC BADRPT # brackets, and numerous perversions thereof a[b]c & abc abc a[ab]c & abc abc a[^ab]c & adc adc a[]b]c & a]c a]c a[[b]c & a[c a[c a[-b]c & a-c a-c a[^]b]c & adc adc a[^-b]c & adc adc a[b-]c & a-c a-c a[b &C EBRACK a[] &C EBRACK a[1-3]c & a2c a2c a[3-1]c &C ERANGE a[1-3-5]c &C ERANGE a[[.-.]--]c & a-c a-c a[1- &C ERANGE a[[. &C EBRACK a[[.x &C EBRACK a[[.x. &C EBRACK a[[.x.] &C EBRACK a[[.x.]] & ax ax a[[.x,.]] &C ECOLLATE a[[.one.]]b & a1b a1b a[[.notdef.]]b &C ECOLLATE a[[.].]]b & a]b a]b a[[:alpha:]]c & abc abc a[[:notdef:]]c &C ECTYPE a[[: &C EBRACK a[[:alpha &C EBRACK a[[:alpha:] &C EBRACK a[[:alpha,:] &C ECTYPE a[[:]:]]b &C ECTYPE a[[:-:]]b &C ECTYPE a[[:alph:]] &C ECTYPE a[[:alphabet:]] &C ECTYPE [[:alnum:]]+ - -%@a0X- a0X [[:alpha:]]+ - -%@aX0- aX [[:blank:]]+ - aSSTb SST [[:cntrl:]]+ - aNTb NT [[:digit:]]+ - a019b 019 [[:graph:]]+ - Sa%bS a%b [[:lower:]]+ - AabC ab [[:print:]]+ - NaSbN aSb [[:punct:]]+ - S%-&T %-& [[:space:]]+ - aSNTb SNT [[:upper:]]+ - aBCd BC [[:xdigit:]]+ - p0f3Cq 0f3C a[[=b=]]c & abc abc a[[= &C EBRACK a[[=b &C EBRACK a[[=b= &C EBRACK a[[=b=] &C EBRACK a[[=b,=]] &C ECOLLATE a[[=one=]]b & a1b a1b # complexities a(((b)))c - abc abc a(b|(c))d - abd abd a(b*|c)d - abbd abbd # just gotta have one DFA-buster, of course a[ab]{20} - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab # and an inline expansion in case somebody gets tricky a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab] - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab # and in case somebody just slips in an NFA... a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab](wee|week)(knights|night) - aaaaabaaaabaaaabaaaabweeknights aaaaabaaaabaaaabaaaabweeknights # fish for anomalies as the number of states passes 32 12345678901234567890123456789 - a12345678901234567890123456789b 12345678901234567890123456789 123456789012345678901234567890 - a123456789012345678901234567890b 123456789012345678901234567890 1234567890123456789012345678901 - a1234567890123456789012345678901b 1234567890123456789012345678901 12345678901234567890123456789012 - a12345678901234567890123456789012b 12345678901234567890123456789012 123456789012345678901234567890123 - a123456789012345678901234567890123b 123456789012345678901234567890123 # and one really big one, beyond any plausible word width 1234567890123456789012345678901234567890123456789012345678901234567890 - a1234567890123456789012345678901234567890123456789012345678901234567890b 1234567890123456789012345678901234567890123456789012345678901234567890 # fish for problems as brackets go past 8 [ab][cd][ef][gh][ij][kl][mn] - xacegikmoq acegikm [ab][cd][ef][gh][ij][kl][mn][op] - xacegikmoq acegikmo [ab][cd][ef][gh][ij][kl][mn][op][qr] - xacegikmoqy acegikmoq [ab][cd][ef][gh][ij][kl][mn][op][q] - xacegikmoqy acegikmoq # subtleties of matching abc & xabcy abc a\(b\)?c\1d b acd aBc i Abc Abc a[Bc]*d i abBCcd abBCcd 0[[:upper:]]1 &i 0a1 0a1 0[[:lower:]]1 &i 0A1 0A1 a[^b]c &i abc a[^b]c &i aBc a[^b]c &i adc adc [a]b[c] - abc abc [a]b[a] - aba aba [abc]b[abc] - abc abc [abc]b[abd] - abd abd a(b?c)+d - accd accd (wee|week)(knights|night) - weeknights weeknights (we|wee|week|frob)(knights|night|day) - weeknights weeknights a[bc]d - xyzaaabcaababdacd abd a[ab]c - aaabc abc abc s abc abc a* & b @b # Let's have some fun -- try to match a C comment. # first the obvious, which looks okay at first glance... /\*.*\*/ - /*x*/ /*x*/ # but... /\*.*\*/ - /*x*/y/*z*/ /*x*/y/*z*/ # okay, we must not match */ inside; try to do that... /\*([^*]|\*[^/])*\*/ - /*x*/ /*x*/ /\*([^*]|\*[^/])*\*/ - /*x*/y/*z*/ /*x*/ # but... /\*([^*]|\*[^/])*\*/ - /*x**/y/*z*/ /*x**/y/*z*/ # and a still fancier version, which does it right (I think)... /\*([^*]|\*+[^*/])*\*+/ - /*x*/ /*x*/ /\*([^*]|\*+[^*/])*\*+/ - /*x*/y/*z*/ /*x*/ /\*([^*]|\*+[^*/])*\*+/ - /*x**/y/*z*/ /*x**/ /\*([^*]|\*+[^*/])*\*+/ - /*x****/y/*z*/ /*x****/ /\*([^*]|\*+[^*/])*\*+/ - /*x**x*/y/*z*/ /*x**x*/ /\*([^*]|\*+[^*/])*\*+/ - /*x***x/y/*z*/ /*x***x/y/*z*/ # subexpressions .* - abc abc - a(b)(c)d - abcd abcd b,c a(((b)))c - abc abc b,b,b a(b|(c))d - abd abd b,- a(b*|c|e)d - abbd abbd bb a(b*|c|e)d - acd acd c a(b*|c|e)d - ad ad @d a(b?)c - abc abc b a(b?)c - ac ac @c a(b+)c - abc abc b a(b+)c - abbbc abbbc bbb a(b*)c - ac ac @c (a|ab)(bc([de]+)f|cde) - abcdef abcdef a,bcdef,de # the regression tester only asks for 9 subexpressions a(b)(c)(d)(e)(f)(g)(h)(i)(j)k - abcdefghijk abcdefghijk b,c,d,e,f,g,h,i,j a(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)l - abcdefghijkl abcdefghijkl b,c,d,e,f,g,h,i,j,k a([bc]?)c - abc abc b a([bc]?)c - ac ac @c a([bc]+)c - abc abc b a([bc]+)c - abcc abcc bc a([bc]+)bc - abcbc abcbc bc a(bb+|b)b - abb abb b a(bbb+|bb+|b)b - abb abb b a(bbb+|bb+|b)b - abbb abbb bb a(bbb+|bb+|b)bb - abbb abbb b (.*).* - abcdef abcdef abcdef (a*)* - bc @b @b # do we get the right subexpression when it is used more than once? a(b|c)*d - ad ad - a(b|c)*d - abcd abcd c a(b|c)+d - abd abd b a(b|c)+d - abcd abcd c a(b|c?)+d - ad ad @d a(b|c?)+d - abcd abcd @d a(b|c){0,0}d - ad ad - a(b|c){0,1}d - ad ad - a(b|c){0,1}d - abd abd b a(b|c){0,2}d - ad ad - a(b|c){0,2}d - abcd abcd c a(b|c){0,}d - ad ad - a(b|c){0,}d - abcd abcd c a(b|c){1,1}d - abd abd b a(b|c){1,1}d - acd acd c a(b|c){1,2}d - abd abd b a(b|c){1,2}d - abcd abcd c a(b|c){1,}d - abd abd b a(b|c){1,}d - abcd abcd c a(b|c){2,2}d - acbd acbd b a(b|c){2,2}d - abcd abcd c a(b|c){2,4}d - abcd abcd c a(b|c){2,4}d - abcbd abcbd b a(b|c){2,4}d - abcbcd abcbcd c a(b|c){2,}d - abcd abcd c a(b|c){2,}d - abcbd abcbd b a(b+|((c)*))+d - abd abd @d,@d,- a(b+|((c)*))+d - abcd abcd @d,@d,- # check out the STARTEND option [abc] &# a(b)c b [abc] &# a(d)c [abc] &# a(bc)d b [abc] &# a(dc)d c . &# a()c b.*c &# b(bc)c bc b.* &# b(bc)c bc .*c &# b(bc)c bc # plain strings, with the NOSPEC flag abc m abc abc abc m xabcy abc abc m xyz a*b m aba*b a*b a*b m ab "" mC EMPTY # cases involving NULs aZb & a a aZb &p a aZb &p# (aZb) aZb aZ*b &p# (ab) ab a.b &# (aZb) aZb a.* &# (aZb)c aZb # word boundaries (ick) [[:<:]]a & a a [[:<:]]a & ba [[:<:]]a & -a a a[[:>:]] & a a a[[:>:]] & ab a[[:>:]] & a- a [[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc abc [[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc-q abc [[:<:]]a.c[[:>:]] & axc-dayc-dazce-abc axc [[:<:]]b.c[[:>:]] & a_bxc-byc_d-bzc-q bzc [[:<:]].x..[[:>:]] & y_xa_-_xb_y-_xc_-axdc _xc_ [[:<:]]a_b[[:>:]] & x_a_b # past problems, and suspected problems (A[1])|(A[2])|(A[3])|(A[4])|(A[5])|(A[6])|(A[7])|(A[8])|(A[9])|(A[A]) - A1 A1 abcdefghijklmnop i abcdefghijklmnop abcdefghijklmnop abcdefghijklmnopqrstuv i abcdefghijklmnopqrstuv abcdefghijklmnopqrstuv (ALAK)|(ALT[AB])|(CC[123]1)|(CM[123]1)|(GAMC)|(LC[23][EO ])|(SEM[1234])|(SL[ES][12])|(SLWW)|(SLF )|(SLDT)|(VWH[12])|(WH[34][EW])|(WP1[ESN]) - CC11 CC11 CC[13]1|a{21}[23][EO][123][Es][12]a{15}aa[34][EW]aaaaaaa[X]a - CC11 CC11 Char \([a-z0-9_]*\)\[.* b Char xyz[k Char xyz[k xyz a?b - ab ab -\{0,1\}[0-9]*$ b -5 -5 a*a*a*a*a*a*a* & aaaaaa aaaaaa ippsample/vcnet/regex/regerror.ih0000644000175000017500000000041313240604116016137 0ustar tilltill/* ========= begin header generated by ./mkh ========= */ #ifdef __cplusplus extern "C" { #endif /* === regerror.c === */ static char *regatoi(const regex_t *preg, char *localbuf); #ifdef __cplusplus } #endif /* ========= end header generated by ./mkh ========= */ ippsample/vcnet/regex/README0000644000175000017500000000234313240604116014652 0ustar tilltillalpha3.8 release. Tue Aug 10 15:51:48 EDT 1999 henry@spsystems.net (formerly henry@zoo.toronto.edu) See WHATSNEW for change listing. installation notes: -------- Read the comments at the beginning of Makefile before running. Utils.h contains some things that just might have to be modified on some systems, as well as a nested include (ugh) of . The "fake" directory contains quick-and-dirty fakes for some header files and routines that old systems may not have. Note also that -DUSEBCOPY will make utils.h substitute bcopy() for memmove(). After that, "make r" will build regcomp.o, regexec.o, regfree.o, and regerror.o (the actual routines), bundle them together into a test program, and run regression tests on them. No output is good output. "make lib" builds just the .o files for the actual routines (when you're happy with testing and have adjusted CFLAGS for production), and puts them together into libregex.a. You can pick up either the library or *.o ("make lib" makes sure there are no other .o files left around to confuse things). Main.c, debug.c, split.c are used for regression testing but are not part of the RE routines themselves. Regex.h goes in /usr/include. All other .h files are internal only. -------- ippsample/vcnet/regex/regex.def0000644000175000017500000000011213240604116015554 0ustar tilltillLIBRARY regex VERSION 1.0 EXPORTS regcomp regerror regexec regfree ippsample/vcnet/regex/regex2.h0000644000175000017500000001236513240604116015344 0ustar tilltill/* * First, the stuff that ends up in the outside-world include file = typedef off_t regoff_t; = typedef struct { = int re_magic; = size_t re_nsub; // number of parenthesized subexpressions = const char *re_endp; // end pointer for REG_PEND = struct re_guts *re_g; // none of your business :-) = } regex_t; = typedef struct { = regoff_t rm_so; // start of match = regoff_t rm_eo; // end of match = } regmatch_t; */ /* * internals of regex_t */ #define MAGIC1 ((('r'^0200)<<8) | 'e') /* * The internal representation is a *strip*, a sequence of * operators ending with an endmarker. (Some terminology etc. is a * historical relic of earlier versions which used multiple strips.) * Certain oddities in the representation are there to permit running * the machinery backwards; in particular, any deviation from sequential * flow must be marked at both its source and its destination. Some * fine points: * * - OPLUS_ and O_PLUS are *inside* the loop they create. * - OQUEST_ and O_QUEST are *outside* the bypass they create. * - OCH_ and O_CH are *outside* the multi-way branch they create, while * OOR1 and OOR2 are respectively the end and the beginning of one of * the branches. Note that there is an implicit OOR2 following OCH_ * and an implicit OOR1 preceding O_CH. * * In state representations, an operator's bit is on to signify a state * immediately *preceding* "execution" of that operator. */ typedef long sop; /* strip operator */ typedef long sopno; #define OPRMASK 0x7c000000 #define OPDMASK 0x03ffffff #define OPSHIFT (26) #define OP(n) ((n)&OPRMASK) #define OPND(n) ((n)&OPDMASK) #define SOP(op, opnd) ((op)|(opnd)) /* operators meaning operand */ /* (back, fwd are offsets) */ #define OEND (1< uch [csetsize] */ uch mask; /* bit within array */ uch hash; /* hash code */ size_t smultis; char *multis; /* -> char[smulti] ab\0cd\0ef\0\0 */ } cset; /* note that CHadd and CHsub are unsafe, and CHIN doesn't yield 0/1 */ #define CHadd(cs, c) ((cs)->ptr[(uch)(c)] |= (cs)->mask, (cs)->hash += (c)) #define CHsub(cs, c) ((cs)->ptr[(uch)(c)] &= ~(cs)->mask, (cs)->hash -= (c)) #define CHIN(cs, c) ((cs)->ptr[(uch)(c)] & (cs)->mask) #define MCadd(p, cs, cp) mcadd(p, cs, cp) /* regcomp() internal fns */ #define MCsub(p, cs, cp) mcsub(p, cs, cp) #define MCin(p, cs, cp) mcin(p, cs, cp) /* stuff for character categories */ typedef unsigned char cat_t; /* * main compiled-expression structure */ struct re_guts { int magic; # define MAGIC2 ((('R'^0200)<<8)|'E') sop *strip; /* malloced area for strip */ int csetsize; /* number of bits in a cset vector */ int ncsets; /* number of csets in use */ cset *sets; /* -> cset [ncsets] */ uch *setbits; /* -> uch[csetsize][ncsets/CHAR_BIT] */ int cflags; /* copy of regcomp() cflags argument */ sopno nstates; /* = number of sops */ sopno firststate; /* the initial OEND (normally 0) */ sopno laststate; /* the final OEND */ int iflags; /* internal flags */ # define USEBOL 01 /* used ^ */ # define USEEOL 02 /* used $ */ # define BAD 04 /* something wrong */ int nbol; /* number of ^ used */ int neol; /* number of $ used */ int ncategories; /* how many character categories */ cat_t *categories; /* ->catspace[-CHAR_MIN] */ char *must; /* match must contain this string */ int mlen; /* length of must */ size_t nsub; /* copy of re_nsub */ int backrefs; /* does it use back references? */ sopno nplus; /* how deep does it nest +s? */ /* catspace must be last */ cat_t catspace[1]; /* actually [NC] */ }; /* misc utilities */ #define OUT (CHAR_MAX+1) /* a non-character value */ #define ISWORD(c) (isalnum(c) || (c) == '_') ippsample/vcnet/regex/cclass.h0000644000175000017500000000162513240604116015415 0ustar tilltill/* character-class table */ static struct cclass { char *name; char *chars; char *multis; } cclasses[] = { "alnum", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ 0123456789", "", "alpha", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", "", "blank", " \t", "", "cntrl", "\007\b\t\n\v\f\r\1\2\3\4\5\6\16\17\20\21\22\23\24\ \25\26\27\30\31\32\33\34\35\36\37\177", "", "digit", "0123456789", "", "graph", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ 0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", "", "lower", "abcdefghijklmnopqrstuvwxyz", "", "print", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ 0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ", "", "punct", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", "", "space", "\t\n\v\f\r ", "", "upper", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "", "xdigit", "0123456789ABCDEFabcdef", "", NULL, 0, "" }; ippsample/vcnet/regex/regex.70000644000175000017500000002304413240604116015175 0ustar tilltill.TH REGEX 7 "25 Oct 1995" .BY "Henry Spencer" .SH NAME regex \- POSIX 1003.2 regular expressions .SH DESCRIPTION Regular expressions (``RE''s), as defined in POSIX 1003.2, come in two forms: modern REs (roughly those of .IR egrep ; 1003.2 calls these ``extended'' REs) and obsolete REs (roughly those of .IR ed ; 1003.2 ``basic'' REs). Obsolete REs mostly exist for backward compatibility in some old programs; they will be discussed at the end. 1003.2 leaves some aspects of RE syntax and semantics open; `\(dg' marks decisions on these aspects that may not be fully portable to other 1003.2 implementations. .PP A (modern) RE is one\(dg or more non-empty\(dg \fIbranches\fR, separated by `|'. It matches anything that matches one of the branches. .PP A branch is one\(dg or more \fIpieces\fR, concatenated. It matches a match for the first, followed by a match for the second, etc. .PP A piece is an \fIatom\fR possibly followed by a single\(dg `*', `+', `?', or \fIbound\fR. An atom followed by `*' matches a sequence of 0 or more matches of the atom. An atom followed by `+' matches a sequence of 1 or more matches of the atom. An atom followed by `?' matches a sequence of 0 or 1 matches of the atom. .PP A \fIbound\fR is `{' followed by an unsigned decimal integer, possibly followed by `,' possibly followed by another unsigned decimal integer, always followed by `}'. The integers must lie between 0 and RE_DUP_MAX (255\(dg) inclusive, and if there are two of them, the first may not exceed the second. An atom followed by a bound containing one integer \fIi\fR and no comma matches a sequence of exactly \fIi\fR matches of the atom. An atom followed by a bound containing one integer \fIi\fR and a comma matches a sequence of \fIi\fR or more matches of the atom. An atom followed by a bound containing two integers \fIi\fR and \fIj\fR matches a sequence of \fIi\fR through \fIj\fR (inclusive) matches of the atom. .PP An atom is a regular expression enclosed in `()' (matching a match for the regular expression), an empty set of `()' (matching the null string)\(dg, a \fIbracket expression\fR (see below), `.' (matching any single character), `^' (matching the null string at the beginning of a line), `$' (matching the null string at the end of a line), a `\e' followed by one of the characters `^.[$()|*+?{\e' (matching that character taken as an ordinary character), a `\e' followed by any other character\(dg (matching that character taken as an ordinary character, as if the `\e' had not been present\(dg), or a single character with no other significance (matching that character). A `{' followed by a character other than a digit is an ordinary character, not the beginning of a bound\(dg. It is illegal to end an RE with `\e'. .PP A \fIbracket expression\fR is a list of characters enclosed in `[]'. It normally matches any single character from the list (but see below). If the list begins with `^', it matches any single character (but see below) \fInot\fR from the rest of the list. If two characters in the list are separated by `\-', this is shorthand for the full \fIrange\fR of characters between those two (inclusive) in the collating sequence, e.g. `[0\-9]' in ASCII matches any decimal digit. It is illegal\(dg for two ranges to share an endpoint, e.g. `a\-c\-e'. Ranges are very collating-sequence-dependent, and portable programs should avoid relying on them. .PP To include a literal `]' in the list, make it the first character (following a possible `^'). To include a literal `\-', make it the first or last character, or the second endpoint of a range. To use a literal `\-' as the first endpoint of a range, enclose it in `[.' and `.]' to make it a collating element (see below). With the exception of these and some combinations using `[' (see next paragraphs), all other special characters, including `\e', lose their special significance within a bracket expression. .PP Within a bracket expression, a collating element (a character, a multi-character sequence that collates as if it were a single character, or a collating-sequence name for either) enclosed in `[.' and `.]' stands for the sequence of characters of that collating element. The sequence is a single element of the bracket expression's list. A bracket expression containing a multi-character collating element can thus match more than one character, e.g. if the collating sequence includes a `ch' collating element, then the RE `[[.ch.]]*c' matches the first five characters of `chchcc'. .PP Within a bracket expression, a collating element enclosed in `[=' and `=]' is an equivalence class, standing for the sequences of characters of all collating elements equivalent to that one, including itself. (If there are no other equivalent collating elements, the treatment is as if the enclosing delimiters were `[.' and `.]'.) For example, if o and \o'o^' are the members of an equivalence class, then `[[=o=]]', `[[=\o'o^'=]]', and `[o\o'o^']' are all synonymous. An equivalence class may not\(dg be an endpoint of a range. .PP Within a bracket expression, the name of a \fIcharacter class\fR enclosed in `[:' and `:]' stands for the list of all characters belonging to that class. Standard character class names are: .PP .RS .nf .ta 3c 6c 9c alnum digit punct alpha graph space blank lower upper cntrl print xdigit .fi .RE .PP These stand for the character classes defined in .IR ctype (3). A locale may provide others. A character class may not be used as an endpoint of a range. .PP There are two special cases\(dg of bracket expressions: the bracket expressions `[[:<:]]' and `[[:>:]]' match the null string at the beginning and end of a word respectively. A word is defined as a sequence of word characters which is neither preceded nor followed by word characters. A word character is an .I alnum character (as defined by .IR ctype (3)) or an underscore. This is an extension, compatible with but not specified by POSIX 1003.2, and should be used with caution in software intended to be portable to other systems. .PP In the event that an RE could match more than one substring of a given string, the RE matches the one starting earliest in the string. If the RE could match more than one substring starting at that point, it matches the longest. Subexpressions also match the longest possible substrings, subject to the constraint that the whole match be as long as possible, with subexpressions starting earlier in the RE taking priority over ones starting later. Note that higher-level subexpressions thus take priority over their lower-level component subexpressions. .PP Match lengths are measured in characters, not collating elements. A null string is considered longer than no match at all. For example, `bb*' matches the three middle characters of `abbbc', `(wee|week)(knights|nights)' matches all ten characters of `weeknights', when `(.*).*' is matched against `abc' the parenthesized subexpression matches all three characters, and when `(a*)*' is matched against `bc' both the whole RE and the parenthesized subexpression match the null string. .PP If case-independent matching is specified, the effect is much as if all case distinctions had vanished from the alphabet. When an alphabetic that exists in multiple cases appears as an ordinary character outside a bracket expression, it is effectively transformed into a bracket expression containing both cases, e.g. `x' becomes `[xX]'. When it appears inside a bracket expression, all case counterparts of it are added to the bracket expression, so that (e.g.) `[x]' becomes `[xX]' and `[^x]' becomes `[^xX]'. .PP No particular limit is imposed on the length of REs\(dg. Programs intended to be portable should not employ REs longer than 256 bytes, as an implementation can refuse to accept such REs and remain POSIX-compliant. .PP Obsolete (``basic'') regular expressions differ in several respects. `|', `+', and `?' are ordinary characters and there is no equivalent for their functionality. The delimiters for bounds are `\e{' and `\e}', with `{' and `}' by themselves ordinary characters. The parentheses for nested subexpressions are `\e(' and `\e)', with `(' and `)' by themselves ordinary characters. `^' is an ordinary character except at the beginning of the RE or\(dg the beginning of a parenthesized subexpression, `$' is an ordinary character except at the end of the RE or\(dg the end of a parenthesized subexpression, and `*' is an ordinary character if it appears at the beginning of the RE or the beginning of a parenthesized subexpression (after a possible leading `^'). Finally, there is one new type of atom, a \fIback reference\fR: `\e' followed by a non-zero decimal digit \fId\fR matches the same sequence of characters matched by the \fId\fRth parenthesized subexpression (numbering subexpressions by the positions of their opening parentheses, left to right), so that (e.g.) `\e([bc]\e)\e1' matches `bb' or `cc' but not `bc'. .SH SEE ALSO regex(3) .PP POSIX 1003.2, section 2.8 (Regular Expression Notation). .SH HISTORY Written by Henry Spencer, based on the 1003.2 spec. .SH BUGS Having two kinds of REs is a botch. .PP The current 1003.2 spec says that `)' is an ordinary character in the absence of an unmatched `('; this was an unintentional result of a wording error, and change is likely. Avoid relying on it. .PP Back references are a dreadful botch, posing major problems for efficient implementations. They are also somewhat vaguely defined (does `a\e(\e(b\e)*\e2\e)*d' match `abbbd'?). Avoid using them. .PP 1003.2's specification of case-independent matching is vague. The ``one case implies all cases'' definition given above is current consensus among implementors as to the right interpretation. .PP The syntax for word boundaries is incredibly ugly. ippsample/vcnet/regex/Makefile0000644000175000017500000000606713240604116015441 0ustar tilltill# You probably want to take -DREDEBUG out of CFLAGS, and put something like # -O in, *after* testing (-DREDEBUG strengthens testing by enabling a lot of # internal assertion checking and some debugging facilities). # Put -Dconst= in for a pre-ANSI compiler. # Do not take -DPOSIX_MISTAKE out. # REGCFLAGS isn't important to you (it's for my use in some special contexts). CFLAGS=-I. -DPOSIX_MISTAKE -DREDEBUG $(REGCFLAGS) # If you have a pre-ANSI compiler, put -o into MKHFLAGS. If you want # the Berkeley __P macro, put -b in. MKHFLAGS= # Flags for linking but not compiling, if any. LDFLAGS= # Extra libraries for linking, if any. LIBS= # Internal stuff, should not need changing. OBJPRODN=regcomp.o regexec.o regerror.o regfree.o OBJS=$(OBJPRODN) split.o debug.o main.o H=cclass.h cname.h regex2.h utils.h REGSRC=regcomp.c regerror.c regexec.c regfree.c ALLSRC=$(REGSRC) engine.c debug.c main.c split.c # Stuff that matters only if you're trying to lint the package. LINTFLAGS=-I. -Dstatic= -Dconst= -DREDEBUG LINTC=regcomp.c regexec.c regerror.c regfree.c debug.c main.c JUNKLINT=possible pointer alignment|null effect # arrangements to build forward-reference header files .SUFFIXES: .ih .h .c.ih: sh ./mkh $(MKHFLAGS) -p $< >$@ default: r lib: purge $(OBJPRODN) rm -f libregex.a ar crv libregex.a $(OBJPRODN) purge: rm -f *.o # stuff to build regex.h REGEXH=regex.h REGEXHSRC=regex2.h $(REGSRC) $(REGEXH): $(REGEXHSRC) mkh sh ./mkh $(MKHFLAGS) -i _REGEX_H_ $(REGEXHSRC) >regex.tmp cmp -s regex.tmp regex.h 2>/dev/null || cp regex.tmp regex.h rm -f regex.tmp # dependencies $(OBJPRODN) debug.o: utils.h regex.h regex2.h regcomp.o: cclass.h cname.h regcomp.ih regexec.o: engine.c engine.ih regerror.o: regerror.ih debug.o: debug.ih main.o: main.ih # tester re: $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ # regression test r: re tests ./re &1 | egrep -v '$(JUNKLINT)' | tee lint fullprint: ti README WHATSNEW notes todo | list ti *.h | list list *.c list regex.3 regex.7 print: ti README WHATSNEW notes todo | list ti *.h | list list reg*.c engine.c mf.tmp: Makefile sed '/^REGEXH=/s/=.*/=regex.h/' Makefile | sed '/#DEL$$/d' >$@ DTRH=cclass.h cname.h regex2.h utils.h PRE=COPYRIGHT README WHATSNEW POST=mkh regex.3 regex.7 tests $(DTRH) $(ALLSRC) fake/*.[ch] FILES=$(PRE) Makefile $(POST) DTR=$(PRE) Makefile=mf.tmp $(POST) dtr: $(FILES) mf.tmp makedtr $(DTR) >$@ rm mf.tmp cio: $(FILES) cio $(FILES) rdf: $(FILES) rcsdiff -c $(FILES) 2>&1 | p # various forms of cleanup tidy: rm -f junk* core core.* *.core dtr *.tmp lint clean: tidy rm -f *.o *.s *.ih re libregex.a # don't do this one unless you know what you're doing spotless: clean rm -f mkh regex.h ippsample/vcnet/regex/WHATSNEW0000644000175000017500000001365113240604116015161 0ustar tilltillNew in alpha3.8: Bug fix for signed/unsigned mixup, found and fixed by the FreeBSD folks. New in alpha3.7: A bit of cleanup aimed at maximizing portability, possibly at slight cost in efficiency. "ul" suffixes and "unsigned long" no longer appear, in particular. New in alpha3.6: A couple more portability glitches fixed. New in alpha3.5: Active development of this code has been stopped -- I'm working on a complete reimplementation -- but folks have found some minor portability glitches and the like, hence this release to fix them. One penalty: slightly reduced compatibility with old compilers, because the ANSI C `unsigned long' type and `ul' constant suffix are used in a few places (I could avoid this but it would be considerably more work). New in alpha3.4: The complex bug alluded to below has been fixed (in a slightly kludgey temporary way that may hurt efficiency a bit; this is another "get it out the door for 4.4" release). The tests at the end of the tests file have accordingly been uncommented. The primary sign of the bug was that something like a?b matching ab matched b rather than ab. (The bug was essentially specific to this exact situation, else it would have shown up earlier.) New in alpha3.3: The definition of word boundaries has been altered slightly, to more closely match the usual programming notion that "_" is an alphabetic. Stuff used for pre-ANSI systems is now in a subdir, and the makefile no longer alludes to it in mysterious ways. The makefile has generally been cleaned up some. Fixes have been made (again!) so that the regression test will run without -DREDEBUG, at the cost of weaker checking. A workaround for a bug in some folks' has been added. And some more things have been added to tests, including a couple right at the end which are commented out because the code currently flunks them (complex bug; fix coming). Plus the usual minor cleanup. New in alpha3.2: Assorted bits of cleanup and portability improvement (the development base is now a BSDI system using GCC instead of an ancient Sun system, and the newer compiler exposed some glitches). Fix for a serious bug that affected REs using many [] (including REG_ICASE REs because of the way they are implemented), *sometimes*, depending on memory-allocation patterns. The header-file prototypes no longer name the parameters, avoiding possible name conflicts. The possibility that some clot has defined CHAR_MIN as (say) `-128' instead of `(-128)' is now handled gracefully. "uchar" is no longer used as an internal type name (too many people have the same idea). Still the same old lousy performance, alas. New in alpha3.1: Basically nothing, this release is just a bookkeeping convenience. Stay tuned. New in alpha3.0: Performance is no better, alas, but some fixes have been made and some functionality has been added. (This is basically the "get it out the door in time for 4.4" release.) One bug fix: regfree() didn't free the main internal structure (how embarrassing). It is now possible to put NULs in either the RE or the target string, using (resp.) a new REG_PEND flag and the old REG_STARTEND flag. The REG_NOSPEC flag to regcomp() makes all characters ordinary, so you can match a literal string easily (this will become more useful when performance improves!). There are now primitives to match beginnings and ends of words, although the syntax is disgusting and so is the implementation. The REG_ATOI debugging interface has changed a bit. And there has been considerable internal cleanup of various kinds. New in alpha2.3: Split change list out of README, and moved flags notes into Makefile. Macro-ized the name of regex(7) in regex(3), since it has to change for 4.4BSD. Cleanup work in engine.c, and some new regression tests to catch tricky cases thereof. New in alpha2.2: Out-of-date manpages updated. Regerror() acquires two small extensions -- REG_ITOA and REG_ATOI -- which avoid debugging kludges in my own test program and might be useful to others for similar purposes. The regression test will now compile (and run) without REDEBUG. The BRE \$ bug is fixed. Most uses of "uchar" are gone; it's all chars now. Char/uchar parameters are now written int/unsigned, to avoid possible portability problems with unpromoted parameters. Some unsigned casts have been introduced to minimize portability problems with shifting into sign bits. New in alpha2.1: Lots of little stuff, cleanup and fixes. The one big thing is that regex.h is now generated, using mkh, rather than being supplied in the distribution; due to circularities in dependencies, you have to build regex.h explicitly by "make h". The two known bugs have been fixed (and the regression test now checks for them), as has a problem with assertions not being suppressed in the absence of REDEBUG. No performance work yet. New in alpha2: Backslash-anything is an ordinary character, not an error (except, of course, for the handful of backslashed metacharacters in BREs), which should reduce script breakage. The regression test checks *where* null strings are supposed to match, and has generally been tightened up somewhat. Small bug fixes in parameter passing (not harmful, but technically errors) and some other areas. Debugging invoked by defining REDEBUG rather than not defining NDEBUG. New in alpha+3: full prototyping for internal routines, using a little helper program, mkh, which extracts prototypes given in stylized comments. More minor cleanup. Buglet fix: it's CHAR_BIT, not CHAR_BITS. Simple pre-screening of input when a literal string is known to be part of the RE; this does wonders for performance. New in alpha+2: minor bits of cleanup. Notably, the number "32" for the word width isn't hardwired into regexec.c any more, the public header file prototypes the functions if __STDC__ is defined, and some small typos in the manpages have been fixed. New in alpha+1: improvements to the manual pages, and an important extension, the REG_STARTEND option to regexec(). ippsample/vcnet/regex/main.ih0000644000175000017500000000076413240604116015245 0ustar tilltill/* ========= begin header generated by ./mkh ========= */ #ifdef __cplusplus extern "C" { #endif /* === main.c === */ void regress(FILE *in); void try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts); int options(int type, char *s); int opt(int c, char *s); void fixstr(register char *p); char *check(char *str, regmatch_t sub, char *should); static char *eprint(int err); static int efind(char *name); #ifdef __cplusplus } #endif /* ========= end header generated by ./mkh ========= */ ippsample/vcnet/regex/regfree.c0000644000175000017500000000132113240604116015550 0ustar tilltill#include #include #include #include #include "utils.h" #include "regex2.h" /* - regfree - free everything = extern void regfree(regex_t *); */ void regfree(preg) regex_t *preg; { register struct re_guts *g; if (preg->re_magic != MAGIC1) /* oops */ return; /* nice to complain, but hard */ g = preg->re_g; if (g == NULL || g->magic != MAGIC2) /* oops again */ return; preg->re_magic = 0; /* mark it invalid */ g->magic = 0; /* mark it invalid */ if (g->strip != NULL) free((char *)g->strip); if (g->sets != NULL) free((char *)g->sets); if (g->setbits != NULL) free((char *)g->setbits); if (g->must != NULL) free(g->must); free((char *)g); } ippsample/vcnet/regex/regcomp.c0000644000175000017500000011066313240604116015577 0ustar tilltill#include #include #include #include #include #include #include #include "utils.h" #include "regex2.h" #include "cclass.h" #include "cname.h" /* * parse structure, passed up and down to avoid global variables and * other clumsinesses */ struct parse { char *next; /* next character in RE */ char *end; /* end of string (-> NUL normally) */ int error; /* has an error been seen? */ sop *strip; /* malloced strip */ sopno ssize; /* malloced strip size (allocated) */ sopno slen; /* malloced strip length (used) */ int ncsalloc; /* number of csets allocated */ struct re_guts *g; # define NPAREN 10 /* we need to remember () 1-9 for back refs */ sopno pbegin[NPAREN]; /* -> ( ([0] unused) */ sopno pend[NPAREN]; /* -> ) ([0] unused) */ }; #include "regcomp.ih" static char nuls[10]; /* place to point scanner in event of error */ /* * macros for use with parse structure * BEWARE: these know that the parse structure is named `p' !!! */ #define PEEK() (*p->next) #define PEEK2() (*(p->next+1)) #define MORE() (p->next < p->end) #define MORE2() (p->next+1 < p->end) #define SEE(c) (MORE() && PEEK() == (c)) #define SEETWO(a, b) (MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b)) #define EAT(c) ((SEE(c)) ? (NEXT(), 1) : 0) #define EATTWO(a, b) ((SEETWO(a, b)) ? (NEXT2(), 1) : 0) #define NEXT() (p->next++) #define NEXT2() (p->next += 2) #define NEXTn(n) (p->next += (n)) #define GETNEXT() (*p->next++) #define SETERROR(e) seterr(p, (e)) #define REQUIRE(co, e) ((co) || SETERROR(e)) #define MUSTSEE(c, e) (REQUIRE(MORE() && PEEK() == (c), e)) #define MUSTEAT(c, e) (REQUIRE(MORE() && GETNEXT() == (c), e)) #define MUSTNOTSEE(c, e) (REQUIRE(!MORE() || PEEK() != (c), e)) #define EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd)) #define INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos) #define AHEAD(pos) dofwd(p, pos, HERE()-(pos)) #define ASTERN(sop, pos) EMIT(sop, HERE()-pos) #define HERE() (p->slen) #define THERE() (p->slen - 1) #define THERETHERE() (p->slen - 2) #define DROP(n) (p->slen -= (n)) #ifndef NDEBUG static int never = 0; /* for use in asserts; shuts lint up */ #else #define never 0 /* some s have bugs too */ #endif /* - regcomp - interface for parser and compilation = extern int regcomp(regex_t *, const char *, int); = #define REG_BASIC 0000 = #define REG_EXTENDED 0001 = #define REG_ICASE 0002 = #define REG_NOSUB 0004 = #define REG_NEWLINE 0010 = #define REG_NOSPEC 0020 = #define REG_PEND 0040 = #define REG_DUMP 0200 */ int /* 0 success, otherwise REG_something */ regcomp(preg, pattern, cflags) regex_t *preg; const char *pattern; int cflags; { struct parse pa; register struct re_guts *g; register struct parse *p = &pa; register int i; register size_t len; #ifdef REDEBUG # define GOODFLAGS(f) (f) #else # define GOODFLAGS(f) ((f)&~REG_DUMP) #endif cflags = GOODFLAGS(cflags); if ((cflags®_EXTENDED) && (cflags®_NOSPEC)) return(REG_INVARG); if (cflags®_PEND) { if (preg->re_endp < pattern) return(REG_INVARG); len = preg->re_endp - pattern; } else len = strlen((char *)pattern); /* do the mallocs early so failure handling is easy */ g = (struct re_guts *)malloc(sizeof(struct re_guts) + (NC-1)*sizeof(cat_t)); if (g == NULL) return(REG_ESPACE); p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */ p->strip = (sop *)malloc(p->ssize * sizeof(sop)); p->slen = 0; if (p->strip == NULL) { free((char *)g); return(REG_ESPACE); } /* set things up */ p->g = g; p->next = (char *)pattern; /* convenience; we do not modify it */ p->end = p->next + len; p->error = 0; p->ncsalloc = 0; for (i = 0; i < NPAREN; i++) { p->pbegin[i] = 0; p->pend[i] = 0; } g->csetsize = NC; g->sets = NULL; g->setbits = NULL; g->ncsets = 0; g->cflags = cflags; g->iflags = 0; g->nbol = 0; g->neol = 0; g->must = NULL; g->mlen = 0; g->nsub = 0; g->ncategories = 1; /* category 0 is "everything else" */ g->categories = &g->catspace[-(CHAR_MIN)]; (void) memset((char *)g->catspace, 0, NC*sizeof(cat_t)); g->backrefs = 0; /* do it */ EMIT(OEND, 0); g->firststate = THERE(); if (cflags®_EXTENDED) p_ere(p, OUT); else if (cflags®_NOSPEC) p_str(p); else p_bre(p, OUT, OUT); EMIT(OEND, 0); g->laststate = THERE(); /* tidy up loose ends and fill things in */ categorize(p, g); stripsnug(p, g); findmust(p, g); g->nplus = pluscount(p, g); g->magic = MAGIC2; preg->re_nsub = g->nsub; preg->re_g = g; preg->re_magic = MAGIC1; #ifndef REDEBUG /* not debugging, so can't rely on the assert() in regexec() */ if (g->iflags&BAD) SETERROR(REG_ASSERT); #endif /* win or lose, we're done */ if (p->error != 0) /* lose */ regfree(preg); return(p->error); } /* - p_ere - ERE parser top level, concatenation and alternation == static void p_ere(register struct parse *p, int stop); */ static void p_ere(p, stop) register struct parse *p; int stop; /* character this ERE should end at */ { register char c; register sopno prevback; register sopno prevfwd; register sopno conc; register int first = 1; /* is this the first alternative? */ for (;;) { /* do a bunch of concatenated expressions */ conc = HERE(); while (MORE() && (c = PEEK()) != '|' && c != stop) p_ere_exp(p); REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */ if (!EAT('|')) break; /* NOTE BREAK OUT */ if (first) { INSERT(OCH_, conc); /* offset is wrong */ prevfwd = conc; prevback = conc; first = 0; } ASTERN(OOR1, prevback); prevback = THERE(); AHEAD(prevfwd); /* fix previous offset */ prevfwd = HERE(); EMIT(OOR2, 0); /* offset is very wrong */ } if (!first) { /* tail-end fixups */ AHEAD(prevfwd); ASTERN(O_CH, prevback); } assert(!MORE() || SEE(stop)); } /* - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op == static void p_ere_exp(register struct parse *p); */ static void p_ere_exp(p) register struct parse *p; { register char c; register sopno pos; register int count; register int count2; register sopno subno; int wascaret = 0; assert(MORE()); /* caller should have ensured this */ c = GETNEXT(); pos = HERE(); switch (c) { case '(': REQUIRE(MORE(), REG_EPAREN); p->g->nsub++; subno = p->g->nsub; if (subno < NPAREN) p->pbegin[subno] = HERE(); EMIT(OLPAREN, subno); if (!SEE(')')) p_ere(p, ')'); if (subno < NPAREN) { p->pend[subno] = HERE(); assert(p->pend[subno] != 0); } EMIT(ORPAREN, subno); MUSTEAT(')', REG_EPAREN); break; #ifndef POSIX_MISTAKE case ')': /* happens only if no current unmatched ( */ /* * You may ask, why the ifndef? Because I didn't notice * this until slightly too late for 1003.2, and none of the * other 1003.2 regular-expression reviewers noticed it at * all. So an unmatched ) is legal POSIX, at least until * we can get it fixed. */ SETERROR(REG_EPAREN); break; #endif case '^': EMIT(OBOL, 0); p->g->iflags |= USEBOL; p->g->nbol++; wascaret = 1; break; case '$': EMIT(OEOL, 0); p->g->iflags |= USEEOL; p->g->neol++; break; case '|': SETERROR(REG_EMPTY); break; case '*': case '+': case '?': SETERROR(REG_BADRPT); break; case '.': if (p->g->cflags®_NEWLINE) nonnewline(p); else EMIT(OANY, 0); break; case '[': p_bracket(p); break; case '\\': REQUIRE(MORE(), REG_EESCAPE); c = GETNEXT(); ordinary(p, c); break; case '{': /* okay as ordinary except if digit follows */ REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT); /* FALLTHROUGH */ default: ordinary(p, c); break; } if (!MORE()) return; c = PEEK(); /* we call { a repetition if followed by a digit */ if (!( c == '*' || c == '+' || c == '?' || (c == '{' && MORE2() && isdigit(PEEK2())) )) return; /* no repetition, we're done */ NEXT(); REQUIRE(!wascaret, REG_BADRPT); switch (c) { case '*': /* implemented as +? */ /* this case does not require the (y|) trick, noKLUDGE */ INSERT(OPLUS_, pos); ASTERN(O_PLUS, pos); INSERT(OQUEST_, pos); ASTERN(O_QUEST, pos); break; case '+': INSERT(OPLUS_, pos); ASTERN(O_PLUS, pos); break; case '?': /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ INSERT(OCH_, pos); /* offset slightly wrong */ ASTERN(OOR1, pos); /* this one's right */ AHEAD(pos); /* fix the OCH_ */ EMIT(OOR2, 0); /* offset very wrong... */ AHEAD(THERE()); /* ...so fix it */ ASTERN(O_CH, THERETHERE()); break; case '{': count = p_count(p); if (EAT(',')) { if (isdigit(PEEK())) { count2 = p_count(p); REQUIRE(count <= count2, REG_BADBR); } else /* single number with comma */ count2 = INFINITY; } else /* just a single number */ count2 = count; repeat(p, pos, count, count2); if (!EAT('}')) { /* error heuristics */ while (MORE() && PEEK() != '}') NEXT(); REQUIRE(MORE(), REG_EBRACE); SETERROR(REG_BADBR); } break; } if (!MORE()) return; c = PEEK(); if (!( c == '*' || c == '+' || c == '?' || (c == '{' && MORE2() && isdigit(PEEK2())) ) ) return; SETERROR(REG_BADRPT); } /* - p_str - string (no metacharacters) "parser" == static void p_str(register struct parse *p); */ static void p_str(p) register struct parse *p; { REQUIRE(MORE(), REG_EMPTY); while (MORE()) ordinary(p, GETNEXT()); } /* - p_bre - BRE parser top level, anchoring and concatenation == static void p_bre(register struct parse *p, register int end1, \ == register int end2); * Giving end1 as OUT essentially eliminates the end1/end2 check. * * This implementation is a bit of a kludge, in that a trailing $ is first * taken as an ordinary character and then revised to be an anchor. The * only undesirable side effect is that '$' gets included as a character * category in such cases. This is fairly harmless; not worth fixing. * The amount of lookahead needed to avoid this kludge is excessive. */ static void p_bre(p, end1, end2) register struct parse *p; register int end1; /* first terminating character */ register int end2; /* second terminating character */ { register sopno start = HERE(); register int first = 1; /* first subexpression? */ register int wasdollar = 0; if (EAT('^')) { EMIT(OBOL, 0); p->g->iflags |= USEBOL; p->g->nbol++; } while (MORE() && !SEETWO(end1, end2)) { wasdollar = p_simp_re(p, first); first = 0; } if (wasdollar) { /* oops, that was a trailing anchor */ DROP(1); EMIT(OEOL, 0); p->g->iflags |= USEEOL; p->g->neol++; } REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */ } /* - p_simp_re - parse a simple RE, an atom possibly followed by a repetition == static int p_simp_re(register struct parse *p, int starordinary); */ static int /* was the simple RE an unbackslashed $? */ p_simp_re(p, starordinary) register struct parse *p; int starordinary; /* is a leading * an ordinary character? */ { register int c; register int count; register int count2; register sopno pos; register int i; register sopno subno; # define BACKSL (1<g->cflags®_NEWLINE) nonnewline(p); else EMIT(OANY, 0); break; case '[': p_bracket(p); break; case BACKSL|'{': SETERROR(REG_BADRPT); break; case BACKSL|'(': p->g->nsub++; subno = p->g->nsub; if (subno < NPAREN) p->pbegin[subno] = HERE(); EMIT(OLPAREN, subno); /* the MORE here is an error heuristic */ if (MORE() && !SEETWO('\\', ')')) p_bre(p, '\\', ')'); if (subno < NPAREN) { p->pend[subno] = HERE(); assert(p->pend[subno] != 0); } EMIT(ORPAREN, subno); REQUIRE(EATTWO('\\', ')'), REG_EPAREN); break; case BACKSL|')': /* should not get here -- must be user */ case BACKSL|'}': SETERROR(REG_EPAREN); break; case BACKSL|'1': case BACKSL|'2': case BACKSL|'3': case BACKSL|'4': case BACKSL|'5': case BACKSL|'6': case BACKSL|'7': case BACKSL|'8': case BACKSL|'9': i = (c&~BACKSL) - '0'; assert(i < NPAREN); if (p->pend[i] != 0) { assert(i <= p->g->nsub); EMIT(OBACK_, i); assert(p->pbegin[i] != 0); assert(OP(p->strip[p->pbegin[i]]) == OLPAREN); assert(OP(p->strip[p->pend[i]]) == ORPAREN); (void) dupl(p, p->pbegin[i]+1, p->pend[i]); EMIT(O_BACK, i); } else SETERROR(REG_ESUBREG); p->g->backrefs = 1; break; case '*': REQUIRE(starordinary, REG_BADRPT); /* FALLTHROUGH */ default: ordinary(p, (char)c); /* takes off BACKSL, if any */ break; } if (EAT('*')) { /* implemented as +? */ /* this case does not require the (y|) trick, noKLUDGE */ INSERT(OPLUS_, pos); ASTERN(O_PLUS, pos); INSERT(OQUEST_, pos); ASTERN(O_QUEST, pos); } else if (EATTWO('\\', '{')) { count = p_count(p); if (EAT(',')) { if (MORE() && isdigit(PEEK())) { count2 = p_count(p); REQUIRE(count <= count2, REG_BADBR); } else /* single number with comma */ count2 = INFINITY; } else /* just a single number */ count2 = count; repeat(p, pos, count, count2); if (!EATTWO('\\', '}')) { /* error heuristics */ while (MORE() && !SEETWO('\\', '}')) NEXT(); REQUIRE(MORE(), REG_EBRACE); SETERROR(REG_BADBR); } } else if (c == (unsigned char)'$') /* $ (but not \$) ends it */ return(1); return(0); } /* - p_count - parse a repetition count == static int p_count(register struct parse *p); */ static int /* the value */ p_count(p) register struct parse *p; { register int count = 0; register int ndigits = 0; while (MORE() && isdigit(PEEK()) && count <= DUPMAX) { count = count*10 + (GETNEXT() - '0'); ndigits++; } REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR); return(count); } /* - p_bracket - parse a bracketed character list == static void p_bracket(register struct parse *p); * * Note a significant property of this code: if the allocset() did SETERROR, * no set operations are done. */ static void p_bracket(p) register struct parse *p; { register cset *cs = allocset(p); register int invert = 0; /* Dept of Truly Sickening Special-Case Kludges */ if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) { EMIT(OBOW, 0); NEXTn(6); return; } if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) { EMIT(OEOW, 0); NEXTn(6); return; } if (EAT('^')) invert++; /* make note to invert set at end */ if (EAT(']')) CHadd(cs, ']'); else if (EAT('-')) CHadd(cs, '-'); while (MORE() && PEEK() != ']' && !SEETWO('-', ']')) p_b_term(p, cs); if (EAT('-')) CHadd(cs, '-'); MUSTEAT(']', REG_EBRACK); if (p->error != 0) /* don't mess things up further */ return; if (p->g->cflags®_ICASE) { register int i; register int ci; for (i = p->g->csetsize - 1; i >= 0; i--) if (CHIN(cs, i) && isalpha(i)) { ci = othercase(i); if (ci != i) CHadd(cs, ci); } if (cs->multis != NULL) mccase(p, cs); } if (invert) { register int i; for (i = p->g->csetsize - 1; i >= 0; i--) if (CHIN(cs, i)) CHsub(cs, i); else CHadd(cs, i); if (p->g->cflags®_NEWLINE) CHsub(cs, '\n'); if (cs->multis != NULL) mcinvert(p, cs); } assert(cs->multis == NULL); /* xxx */ if (nch(p, cs) == 1) { /* optimize singleton sets */ ordinary(p, firstch(p, cs)); freeset(p, cs); } else EMIT(OANYOF, freezeset(p, cs)); } /* - p_b_term - parse one term of a bracketed character list == static void p_b_term(register struct parse *p, register cset *cs); */ static void p_b_term(p, cs) register struct parse *p; register cset *cs; { register char c; register char start, finish; register int i; /* classify what we've got */ switch ((MORE()) ? PEEK() : '\0') { case '[': c = (MORE2()) ? PEEK2() : '\0'; break; case '-': SETERROR(REG_ERANGE); return; /* NOTE RETURN */ break; default: c = '\0'; break; } switch (c) { case ':': /* character class */ NEXT2(); REQUIRE(MORE(), REG_EBRACK); c = PEEK(); REQUIRE(c != '-' && c != ']', REG_ECTYPE); p_b_cclass(p, cs); REQUIRE(MORE(), REG_EBRACK); REQUIRE(EATTWO(':', ']'), REG_ECTYPE); break; case '=': /* equivalence class */ NEXT2(); REQUIRE(MORE(), REG_EBRACK); c = PEEK(); REQUIRE(c != '-' && c != ']', REG_ECOLLATE); p_b_eclass(p, cs); REQUIRE(MORE(), REG_EBRACK); REQUIRE(EATTWO('=', ']'), REG_ECOLLATE); break; default: /* symbol, ordinary character, or range */ /* xxx revision needed for multichar stuff */ start = p_b_symbol(p); if (SEE('-') && MORE2() && PEEK2() != ']') { /* range */ NEXT(); if (EAT('-')) finish = '-'; else finish = p_b_symbol(p); } else finish = start; /* xxx what about signed chars here... */ REQUIRE(start <= finish, REG_ERANGE); for (i = start; i <= finish; i++) CHadd(cs, i); break; } } /* - p_b_cclass - parse a character-class name and deal with it == static void p_b_cclass(register struct parse *p, register cset *cs); */ static void p_b_cclass(p, cs) register struct parse *p; register cset *cs; { register char *sp = p->next; register struct cclass *cp; register size_t len; register char *u; register char c; while (MORE() && isalpha(PEEK())) NEXT(); len = p->next - sp; for (cp = cclasses; cp->name != NULL; cp++) if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0') break; if (cp->name == NULL) { /* oops, didn't find it */ SETERROR(REG_ECTYPE); return; } u = cp->chars; while ((c = *u++) != '\0') CHadd(cs, c); for (u = cp->multis; *u != '\0'; u += strlen(u) + 1) MCadd(p, cs, u); } /* - p_b_eclass - parse an equivalence-class name and deal with it == static void p_b_eclass(register struct parse *p, register cset *cs); * * This implementation is incomplete. xxx */ static void p_b_eclass(p, cs) register struct parse *p; register cset *cs; { register char c; c = p_b_coll_elem(p, '='); CHadd(cs, c); } /* - p_b_symbol - parse a character or [..]ed multicharacter collating symbol == static char p_b_symbol(register struct parse *p); */ static char /* value of symbol */ p_b_symbol(p) register struct parse *p; { register char value; REQUIRE(MORE(), REG_EBRACK); if (!EATTWO('[', '.')) return(GETNEXT()); /* collating symbol */ value = p_b_coll_elem(p, '.'); REQUIRE(EATTWO('.', ']'), REG_ECOLLATE); return(value); } /* - p_b_coll_elem - parse a collating-element name and look it up == static char p_b_coll_elem(register struct parse *p, int endc); */ static char /* value of collating element */ p_b_coll_elem(p, endc) register struct parse *p; int endc; /* name ended by endc,']' */ { register char *sp = p->next; register struct cname *cp; register int len; while (MORE() && !SEETWO(endc, ']')) NEXT(); if (!MORE()) { SETERROR(REG_EBRACK); return(0); } len = p->next - sp; for (cp = cnames; cp->name != NULL; cp++) if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0') return(cp->code); /* known name */ if (len == 1) return(*sp); /* single character */ SETERROR(REG_ECOLLATE); /* neither */ return(0); } /* - othercase - return the case counterpart of an alphabetic == static char othercase(int ch); */ static char /* if no counterpart, return ch */ othercase(ch) int ch; { assert(isalpha(ch)); if (isupper(ch)) return(tolower(ch)); else if (islower(ch)) return(toupper(ch)); else /* peculiar, but could happen */ return(ch); } /* - bothcases - emit a dualcase version of a two-case character == static void bothcases(register struct parse *p, int ch); * * Boy, is this implementation ever a kludge... */ static void bothcases(p, ch) register struct parse *p; int ch; { register char *oldnext = p->next; register char *oldend = p->end; char bracket[3]; assert(othercase(ch) != ch); /* p_bracket() would recurse */ p->next = bracket; p->end = bracket+2; bracket[0] = ch; bracket[1] = ']'; bracket[2] = '\0'; p_bracket(p); assert(p->next == bracket+2); p->next = oldnext; p->end = oldend; } /* - ordinary - emit an ordinary character == static void ordinary(register struct parse *p, register int ch); */ static void ordinary(p, ch) register struct parse *p; register int ch; { register cat_t *cap = p->g->categories; if ((p->g->cflags®_ICASE) && isalpha(ch) && othercase(ch) != ch) bothcases(p, ch); else { EMIT(OCHAR, (unsigned char)ch); if (cap[ch] == 0) cap[ch] = p->g->ncategories++; } } /* - nonnewline - emit REG_NEWLINE version of OANY == static void nonnewline(register struct parse *p); * * Boy, is this implementation ever a kludge... */ static void nonnewline(p) register struct parse *p; { register char *oldnext = p->next; register char *oldend = p->end; char bracket[4]; p->next = bracket; p->end = bracket+3; bracket[0] = '^'; bracket[1] = '\n'; bracket[2] = ']'; bracket[3] = '\0'; p_bracket(p); assert(p->next == bracket+3); p->next = oldnext; p->end = oldend; } /* - repeat - generate code for a bounded repetition, recursively if needed == static void repeat(register struct parse *p, sopno start, int from, int to); */ static void repeat(p, start, from, to) register struct parse *p; sopno start; /* operand from here to end of strip */ int from; /* repeated from this number */ int to; /* to this number of times (maybe INFINITY) */ { register sopno finish = HERE(); # define N 2 # define INF 3 # define REP(f, t) ((f)*8 + (t)) # define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N) register sopno copy; if (p->error != 0) /* head off possible runaway recursion */ return; assert(from <= to); switch (REP(MAP(from), MAP(to))) { case REP(0, 0): /* must be user doing this */ DROP(finish-start); /* drop the operand */ break; case REP(0, 1): /* as x{1,1}? */ case REP(0, N): /* as x{1,n}? */ case REP(0, INF): /* as x{1,}? */ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ INSERT(OCH_, start); /* offset is wrong... */ repeat(p, start+1, 1, to); ASTERN(OOR1, start); AHEAD(start); /* ... fix it */ EMIT(OOR2, 0); AHEAD(THERE()); ASTERN(O_CH, THERETHERE()); break; case REP(1, 1): /* trivial case */ /* done */ break; case REP(1, N): /* as x?x{1,n-1} */ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ INSERT(OCH_, start); ASTERN(OOR1, start); AHEAD(start); EMIT(OOR2, 0); /* offset very wrong... */ AHEAD(THERE()); /* ...so fix it */ ASTERN(O_CH, THERETHERE()); copy = dupl(p, start+1, finish+1); assert(copy == finish+4); repeat(p, copy, 1, to-1); break; case REP(1, INF): /* as x+ */ INSERT(OPLUS_, start); ASTERN(O_PLUS, start); break; case REP(N, N): /* as xx{m-1,n-1} */ copy = dupl(p, start, finish); repeat(p, copy, from-1, to-1); break; case REP(N, INF): /* as xx{n-1,INF} */ copy = dupl(p, start, finish); repeat(p, copy, from-1, to); break; default: /* "can't happen" */ SETERROR(REG_ASSERT); /* just in case */ break; } } /* - seterr - set an error condition == static int seterr(register struct parse *p, int e); */ static int /* useless but makes type checking happy */ seterr(p, e) register struct parse *p; int e; { if (p->error == 0) /* keep earliest error condition */ p->error = e; p->next = nuls; /* try to bring things to a halt */ p->end = nuls; return(0); /* make the return value well-defined */ } /* - allocset - allocate a set of characters for [] == static cset *allocset(register struct parse *p); */ static cset * allocset(p) register struct parse *p; { register int no = p->g->ncsets++; register size_t nc; register size_t nbytes; register cset *cs; register size_t css = (size_t)p->g->csetsize; register int i; if (no >= p->ncsalloc) { /* need another column of space */ p->ncsalloc += CHAR_BIT; nc = p->ncsalloc; assert(nc % CHAR_BIT == 0); nbytes = nc / CHAR_BIT * css; if (p->g->sets == NULL) p->g->sets = (cset *)malloc(nc * sizeof(cset)); else p->g->sets = (cset *)realloc((char *)p->g->sets, nc * sizeof(cset)); if (p->g->setbits == NULL) p->g->setbits = (uch *)malloc(nbytes); else { p->g->setbits = (uch *)realloc((char *)p->g->setbits, nbytes); /* xxx this isn't right if setbits is now NULL */ for (i = 0; i < no; i++) p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT); } if (p->g->sets != NULL && p->g->setbits != NULL) (void) memset((char *)p->g->setbits + (nbytes - css), 0, css); else { no = 0; SETERROR(REG_ESPACE); /* caller's responsibility not to do set ops */ } } assert(p->g->sets != NULL); /* xxx */ cs = &p->g->sets[no]; cs->ptr = p->g->setbits + css*((no)/CHAR_BIT); cs->mask = 1 << ((no) % CHAR_BIT); cs->hash = 0; cs->smultis = 0; cs->multis = NULL; return(cs); } /* - freeset - free a now-unused set == static void freeset(register struct parse *p, register cset *cs); */ static void freeset(p, cs) register struct parse *p; register cset *cs; { register size_t i; register cset *top = &p->g->sets[p->g->ncsets]; register size_t css = (size_t)p->g->csetsize; for (i = 0; i < css; i++) CHsub(cs, i); if (cs == top-1) /* recover only the easy case */ p->g->ncsets--; } /* - freezeset - final processing on a set of characters == static int freezeset(register struct parse *p, register cset *cs); * * The main task here is merging identical sets. This is usually a waste * of time (although the hash code minimizes the overhead), but can win * big if REG_ICASE is being used. REG_ICASE, by the way, is why the hash * is done using addition rather than xor -- all ASCII [aA] sets xor to * the same value! */ static int /* set number */ freezeset(p, cs) register struct parse *p; register cset *cs; { register uch h = cs->hash; register size_t i; register cset *top = &p->g->sets[p->g->ncsets]; register cset *cs2; register size_t css = (size_t)p->g->csetsize; /* look for an earlier one which is the same */ for (cs2 = &p->g->sets[0]; cs2 < top; cs2++) if (cs2->hash == h && cs2 != cs) { /* maybe */ for (i = 0; i < css; i++) if (!!CHIN(cs2, i) != !!CHIN(cs, i)) break; /* no */ if (i == css) break; /* yes */ } if (cs2 < top) { /* found one */ freeset(p, cs); cs = cs2; } return((int)(cs - p->g->sets)); } /* - firstch - return first character in a set (which must have at least one) == static int firstch(register struct parse *p, register cset *cs); */ static int /* character; there is no "none" value */ firstch(p, cs) register struct parse *p; register cset *cs; { register size_t i; register size_t css = (size_t)p->g->csetsize; for (i = 0; i < css; i++) if (CHIN(cs, i)) return((char)i); assert(never); return(0); /* arbitrary */ } /* - nch - number of characters in a set == static int nch(register struct parse *p, register cset *cs); */ static int nch(p, cs) register struct parse *p; register cset *cs; { register size_t i; register size_t css = (size_t)p->g->csetsize; register int n = 0; for (i = 0; i < css; i++) if (CHIN(cs, i)) n++; return(n); } /* - mcadd - add a collating element to a cset == static void mcadd(register struct parse *p, register cset *cs, \ == register char *cp); */ static void mcadd(p, cs, cp) register struct parse *p; register cset *cs; register char *cp; { register size_t oldend = cs->smultis; cs->smultis += strlen(cp) + 1; if (cs->multis == NULL) cs->multis = malloc(cs->smultis); else cs->multis = realloc(cs->multis, cs->smultis); if (cs->multis == NULL) { SETERROR(REG_ESPACE); return; } (void) strcpy(cs->multis + oldend - 1, cp); cs->multis[cs->smultis - 1] = '\0'; } /* - mcsub - subtract a collating element from a cset == static void mcsub(register cset *cs, register char *cp); */ static void mcsub(cs, cp) register cset *cs; register char *cp; { register char *fp = mcfind(cs, cp); register size_t len = strlen(fp); assert(fp != NULL); (void) memmove(fp, fp + len + 1, cs->smultis - (fp + len + 1 - cs->multis)); cs->smultis -= len; if (cs->smultis == 0) { free(cs->multis); cs->multis = NULL; return; } cs->multis = realloc(cs->multis, cs->smultis); assert(cs->multis != NULL); } /* - mcin - is a collating element in a cset? == static int mcin(register cset *cs, register char *cp); */ static int mcin(cs, cp) register cset *cs; register char *cp; { return(mcfind(cs, cp) != NULL); } /* - mcfind - find a collating element in a cset == static char *mcfind(register cset *cs, register char *cp); */ static char * mcfind(cs, cp) register cset *cs; register char *cp; { register char *p; if (cs->multis == NULL) return(NULL); for (p = cs->multis; *p != '\0'; p += strlen(p) + 1) if (strcmp(cp, p) == 0) return(p); return(NULL); } /* - mcinvert - invert the list of collating elements in a cset == static void mcinvert(register struct parse *p, register cset *cs); * * This would have to know the set of possibilities. Implementation * is deferred. */ static void mcinvert(p, cs) register struct parse *p; register cset *cs; { assert(cs->multis == NULL); /* xxx */ } /* - mccase - add case counterparts of the list of collating elements in a cset == static void mccase(register struct parse *p, register cset *cs); * * This would have to know the set of possibilities. Implementation * is deferred. */ static void mccase(p, cs) register struct parse *p; register cset *cs; { assert(cs->multis == NULL); /* xxx */ } /* - isinsets - is this character in any sets? == static int isinsets(register struct re_guts *g, int c); */ static int /* predicate */ isinsets(g, c) register struct re_guts *g; int c; { register uch *col; register int i; register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT; register unsigned uc = (unsigned char)c; for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize) if (col[uc] != 0) return(1); return(0); } /* - samesets - are these two characters in exactly the same sets? == static int samesets(register struct re_guts *g, int c1, int c2); */ static int /* predicate */ samesets(g, c1, c2) register struct re_guts *g; int c1; int c2; { register uch *col; register int i; register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT; register unsigned uc1 = (unsigned char)c1; register unsigned uc2 = (unsigned char)c2; for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize) if (col[uc1] != col[uc2]) return(0); return(1); } /* - categorize - sort out character categories == static void categorize(struct parse *p, register struct re_guts *g); */ static void categorize(p, g) struct parse *p; register struct re_guts *g; { register cat_t *cats = g->categories; register int c; register int c2; register cat_t cat; /* avoid making error situations worse */ if (p->error != 0) return; for (c = CHAR_MIN; c <= CHAR_MAX; c++) if (cats[c] == 0 && isinsets(g, c)) { cat = g->ncategories++; cats[c] = cat; for (c2 = c+1; c2 <= CHAR_MAX; c2++) if (cats[c2] == 0 && samesets(g, c, c2)) cats[c2] = cat; } } /* - dupl - emit a duplicate of a bunch of sops == static sopno dupl(register struct parse *p, sopno start, sopno finish); */ static sopno /* start of duplicate */ dupl(p, start, finish) register struct parse *p; sopno start; /* from here */ sopno finish; /* to this less one */ { register sopno ret = HERE(); register sopno len = finish - start; assert(finish >= start); if (len == 0) return(ret); enlarge(p, p->ssize + len); /* this many unexpected additions */ assert(p->ssize >= p->slen + len); (void) memmove((char *)(p->strip + p->slen), (char *)(p->strip + start), (size_t)len*sizeof(sop)); p->slen += len; return(ret); } /* - doemit - emit a strip operator == static void doemit(register struct parse *p, sop op, size_t opnd); * * It might seem better to implement this as a macro with a function as * hard-case backup, but it's just too big and messy unless there are * some changes to the data structures. Maybe later. */ static void doemit(p, op, opnd) register struct parse *p; sop op; size_t opnd; { /* avoid making error situations worse */ if (p->error != 0) return; /* deal with oversize operands ("can't happen", more or less) */ assert(opnd < 1<slen >= p->ssize) enlarge(p, (p->ssize+1) / 2 * 3); /* +50% */ assert(p->slen < p->ssize); /* finally, it's all reduced to the easy case */ p->strip[p->slen++] = SOP(op, opnd); } /* - doinsert - insert a sop into the strip == static void doinsert(register struct parse *p, sop op, size_t opnd, sopno pos); */ static void doinsert(p, op, opnd, pos) register struct parse *p; sop op; size_t opnd; sopno pos; { register sopno sn; register sop s; register int i; /* avoid making error situations worse */ if (p->error != 0) return; sn = HERE(); EMIT(op, opnd); /* do checks, ensure space */ assert(HERE() == sn+1); s = p->strip[sn]; /* adjust paren pointers */ assert(pos > 0); for (i = 1; i < NPAREN; i++) { if (p->pbegin[i] >= pos) { p->pbegin[i]++; } if (p->pend[i] >= pos) { p->pend[i]++; } } memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos], (HERE()-pos-1)*sizeof(sop)); p->strip[pos] = s; } /* - dofwd - complete a forward reference == static void dofwd(register struct parse *p, sopno pos, sop value); */ static void dofwd(p, pos, value) register struct parse *p; register sopno pos; sop value; { /* avoid making error situations worse */ if (p->error != 0) return; assert(value < 1<strip[pos] = OP(p->strip[pos]) | value; } /* - enlarge - enlarge the strip == static void enlarge(register struct parse *p, sopno size); */ static void enlarge(p, size) register struct parse *p; register sopno size; { register sop *sp; if (p->ssize >= size) return; sp = (sop *)realloc(p->strip, size*sizeof(sop)); if (sp == NULL) { SETERROR(REG_ESPACE); return; } p->strip = sp; p->ssize = size; } /* - stripsnug - compact the strip == static void stripsnug(register struct parse *p, register struct re_guts *g); */ static void stripsnug(p, g) register struct parse *p; register struct re_guts *g; { g->nstates = p->slen; g->strip = (sop *)realloc((char *)p->strip, p->slen * sizeof(sop)); if (g->strip == NULL) { SETERROR(REG_ESPACE); g->strip = p->strip; } } /* - findmust - fill in must and mlen with longest mandatory literal string == static void findmust(register struct parse *p, register struct re_guts *g); * * This algorithm could do fancy things like analyzing the operands of | * for common subsequences. Someday. This code is simple and finds most * of the interesting cases. * * Note that must and mlen got initialized during setup. */ static void findmust(p, g) struct parse *p; register struct re_guts *g; { register sop *scan; sop *start; register sop *newstart; register sopno newlen; register sop s; register char *cp; register sopno i; /* avoid making error situations worse */ if (p->error != 0) return; /* find the longest OCHAR sequence in strip */ newlen = 0; scan = g->strip + 1; do { s = *scan++; switch (OP(s)) { case OCHAR: /* sequence member */ if (newlen == 0) /* new sequence */ newstart = scan - 1; newlen++; break; case OPLUS_: /* things that don't break one */ case OLPAREN: case ORPAREN: break; case OQUEST_: /* things that must be skipped */ case OCH_: scan--; do { scan += OPND(s); s = *scan; /* assert() interferes w debug printouts */ if (OP(s) != O_QUEST && OP(s) != O_CH && OP(s) != OOR2) { g->iflags |= BAD; return; } } while (OP(s) != O_QUEST && OP(s) != O_CH); /* fallthrough */ default: /* things that break a sequence */ if (newlen > g->mlen) { /* ends one */ start = newstart; g->mlen = newlen; } newlen = 0; break; } } while (OP(s) != OEND); if (g->mlen == 0) /* there isn't one */ return; /* turn it into a character string */ g->must = malloc((size_t)g->mlen + 1); if (g->must == NULL) { /* argh; just forget it */ g->mlen = 0; return; } cp = g->must; scan = start; for (i = g->mlen; i > 0; i--) { while (OP(s = *scan++) != OCHAR) continue; assert(cp < g->must + g->mlen); *cp++ = (char)OPND(s); } assert(cp == g->must + g->mlen); *cp++ = '\0'; /* just on general principles */ } /* - pluscount - count + nesting == static sopno pluscount(register struct parse *p, register struct re_guts *g); */ static sopno /* nesting depth */ pluscount(p, g) struct parse *p; register struct re_guts *g; { register sop *scan; register sop s; register sopno plusnest = 0; register sopno maxnest = 0; if (p->error != 0) return(0); /* there may not be an OEND */ scan = g->strip + 1; do { s = *scan++; switch (OP(s)) { case OPLUS_: plusnest++; break; case O_PLUS: if (plusnest > maxnest) maxnest = plusnest; plusnest--; break; } } while (OP(s) != OEND); if (plusnest != 0) g->iflags |= BAD; return(maxnest); } ippsample/vcnet/regex/COPYRIGHT0000644000175000017500000000167413240604116015273 0ustar tilltillCopyright 1992, 1993, 1994, 1997 Henry Spencer. All rights reserved. This software is not subject to any license of the American Telephone and Telegraph Company or of the Regents of the University of California. Permission is granted to anyone to use this software for any purpose on any computer system, and to alter it and redistribute it, subject to the following restrictions: 1. The author is not responsible for the consequences of use of this software, no matter how awful, even if they arise from flaws in it. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. Since few users ever read sources, credits must appear in the documentation. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. Since few users ever read sources, credits must appear in the documentation. 4. This notice may not be removed or altered. ippsample/vcnet/regex/engine.ih0000644000175000017500000000253513240604116015564 0ustar tilltill/* ========= begin header generated by ./mkh ========= */ #ifdef __cplusplus extern "C" { #endif /* === engine.c === */ static int matcher(register struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[], int eflags); static char *dissect(register struct match *m, char *start, char *stop, sopno startst, sopno stopst); static char *backref(register struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev); static char *fast(register struct match *m, char *start, char *stop, sopno startst, sopno stopst); static char *slow(register struct match *m, char *start, char *stop, sopno startst, sopno stopst); static states step(register struct re_guts *g, sopno start, sopno stop, register states bef, int ch, register states aft); #define BOL (OUT+1) #define EOL (BOL+1) #define BOLEOL (BOL+2) #define NOTHING (BOL+3) #define BOW (BOL+4) #define EOW (BOL+5) #define CODEMAX (BOL+5) /* highest code used */ #define NONCHAR(c) ((c) > CHAR_MAX) #define NNONCHAR (CODEMAX-CHAR_MAX) #ifdef REDEBUG static void print(struct match *m, char *caption, states st, int ch, FILE *d); #endif #ifdef REDEBUG static void at(struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst); #endif #ifdef REDEBUG static char *pchar(int ch); #endif #ifdef __cplusplus } #endif /* ========= end header generated by ./mkh ========= */ ippsample/vcnet/regex/main.c0000644000175000017500000002562113240604116015066 0ustar tilltill#include #include #include #include #include #include "main.ih" char *progname; int debug = 0; int line = 0; int status = 0; int copts = REG_EXTENDED; int eopts = 0; regoff_t startoff = 0; regoff_t endoff = 0; extern int split(); extern void regprint(); /* - main - do the simple case, hand off to regress() for regression */ main(argc, argv) int argc; char *argv[]; { regex_t re; # define NS 10 regmatch_t subs[NS]; char erbuf[100]; int err; size_t len; int c; int errflg = 0; register int i; extern int optind; extern char *optarg; progname = argv[0]; while ((c = getopt(argc, argv, "c:e:S:E:x")) != EOF) switch (c) { case 'c': /* compile options */ copts = options('c', optarg); break; case 'e': /* execute options */ eopts = options('e', optarg); break; case 'S': /* start offset */ startoff = (regoff_t)atoi(optarg); break; case 'E': /* end offset */ endoff = (regoff_t)atoi(optarg); break; case 'x': /* Debugging. */ debug++; break; case '?': default: errflg++; break; } if (errflg) { fprintf(stderr, "usage: %s ", progname); fprintf(stderr, "[-c copt][-C][-d] [re]\n"); exit(2); } if (optind >= argc) { regress(stdin); exit(status); } err = regcomp(&re, argv[optind++], copts); if (err) { len = regerror(err, &re, erbuf, sizeof(erbuf)); fprintf(stderr, "error %s, %d/%d `%s'\n", eprint(err), len, sizeof(erbuf), erbuf); exit(status); } regprint(&re, stdout); if (optind >= argc) { regfree(&re); exit(status); } if (eopts®_STARTEND) { subs[0].rm_so = startoff; subs[0].rm_eo = strlen(argv[optind]) - endoff; } err = regexec(&re, argv[optind], (size_t)NS, subs, eopts); if (err) { len = regerror(err, &re, erbuf, sizeof(erbuf)); fprintf(stderr, "error %s, %d/%d `%s'\n", eprint(err), len, sizeof(erbuf), erbuf); exit(status); } if (!(copts®_NOSUB)) { len = (int)(subs[0].rm_eo - subs[0].rm_so); if (subs[0].rm_so != -1) { if (len != 0) printf("match `%.*s'\n", len, argv[optind] + subs[0].rm_so); else printf("match `'@%.1s\n", argv[optind] + subs[0].rm_so); } for (i = 1; i < NS; i++) if (subs[i].rm_so != -1) printf("(%d) `%.*s'\n", i, (int)(subs[i].rm_eo - subs[i].rm_so), argv[optind] + subs[i].rm_so); } exit(status); } /* - regress - main loop of regression test == void regress(FILE *in); */ void regress(in) FILE *in; { char inbuf[1000]; # define MAXF 10 char *f[MAXF]; int nf; int i; char erbuf[100]; size_t ne; char *badpat = "invalid regular expression"; # define SHORT 10 char *bpname = "REG_BADPAT"; regex_t re; while (fgets(inbuf, sizeof(inbuf), in) != NULL) { line++; if (inbuf[0] == '#' || inbuf[0] == '\n') continue; /* NOTE CONTINUE */ inbuf[strlen(inbuf)-1] = '\0'; /* get rid of stupid \n */ if (debug) fprintf(stdout, "%d:\n", line); nf = split(inbuf, f, MAXF, "\t\t"); if (nf < 3) { fprintf(stderr, "bad input, line %d\n", line); exit(1); } for (i = 0; i < nf; i++) if (strcmp(f[i], "\"\"") == 0) f[i] = ""; if (nf <= 3) f[3] = NULL; if (nf <= 4) f[4] = NULL; try(f[0], f[1], f[2], f[3], f[4], options('c', f[1])); if (opt('&', f[1])) /* try with either type of RE */ try(f[0], f[1], f[2], f[3], f[4], options('c', f[1]) &~ REG_EXTENDED); } ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf)); if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) { fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n", erbuf, badpat); status = 1; } ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, (size_t)SHORT); if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' || ne != strlen(badpat)+1) { fprintf(stderr, "end: regerror() short test gave `%s' not `%.*s'\n", erbuf, SHORT-1, badpat); status = 1; } ne = regerror(REG_ITOA|REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf)); if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname)+1) { fprintf(stderr, "end: regerror() ITOA test gave `%s' not `%s'\n", erbuf, bpname); status = 1; } re.re_endp = bpname; ne = regerror(REG_ATOI, &re, erbuf, sizeof(erbuf)); if (atoi(erbuf) != (int)REG_BADPAT) { fprintf(stderr, "end: regerror() ATOI test gave `%s' not `%ld'\n", erbuf, (long)REG_BADPAT); status = 1; } else if (ne != strlen(erbuf)+1) { fprintf(stderr, "end: regerror() ATOI test len(`%s') = %ld\n", erbuf, (long)REG_BADPAT); status = 1; } } /* - try - try it, and report on problems == void try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts); */ void try(f0, f1, f2, f3, f4, opts) char *f0; char *f1; char *f2; char *f3; char *f4; int opts; /* may not match f1 */ { regex_t re; # define NSUBS 10 regmatch_t subs[NSUBS]; # define NSHOULD 15 char *should[NSHOULD]; int nshould; char erbuf[100]; int err; int len; char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE"; register int i; char *grump; char f0copy[1000]; char f2copy[1000]; strcpy(f0copy, f0); re.re_endp = (opts®_PEND) ? f0copy + strlen(f0copy) : NULL; fixstr(f0copy); err = regcomp(&re, f0copy, opts); if (err != 0 && (!opt('C', f1) || err != efind(f2))) { /* unexpected error or wrong error */ len = regerror(err, &re, erbuf, sizeof(erbuf)); fprintf(stderr, "%d: %s error %s, %d/%d `%s'\n", line, type, eprint(err), len, sizeof(erbuf), erbuf); status = 1; } else if (err == 0 && opt('C', f1)) { /* unexpected success */ fprintf(stderr, "%d: %s should have given REG_%s\n", line, type, f2); status = 1; err = 1; /* so we won't try regexec */ } if (err != 0) { regfree(&re); return; } strcpy(f2copy, f2); fixstr(f2copy); if (options('e', f1)®_STARTEND) { if (strchr(f2, '(') == NULL || strchr(f2, ')') == NULL) fprintf(stderr, "%d: bad STARTEND syntax\n", line); subs[0].rm_so = strchr(f2, '(') - f2 + 1; subs[0].rm_eo = strchr(f2, ')') - f2; } err = regexec(&re, f2copy, NSUBS, subs, options('e', f1)); if (err != 0 && (f3 != NULL || err != REG_NOMATCH)) { /* unexpected error or wrong error */ len = regerror(err, &re, erbuf, sizeof(erbuf)); fprintf(stderr, "%d: %s exec error %s, %d/%d `%s'\n", line, type, eprint(err), len, sizeof(erbuf), erbuf); status = 1; } else if (err != 0) { /* nothing more to check */ } else if (f3 == NULL) { /* unexpected success */ fprintf(stderr, "%d: %s exec should have failed\n", line, type); status = 1; err = 1; /* just on principle */ } else if (opts®_NOSUB) { /* nothing more to check */ } else if ((grump = check(f2, subs[0], f3)) != NULL) { fprintf(stderr, "%d: %s %s\n", line, type, grump); status = 1; err = 1; } if (err != 0 || f4 == NULL) { regfree(&re); return; } for (i = 1; i < NSHOULD; i++) should[i] = NULL; nshould = split(f4, should+1, NSHOULD-1, ","); if (nshould == 0) { nshould = 1; should[1] = ""; } for (i = 1; i < NSUBS; i++) { grump = check(f2, subs[i], should[i]); if (grump != NULL) { fprintf(stderr, "%d: %s $%d %s\n", line, type, i, grump); status = 1; err = 1; } } regfree(&re); } /* - options - pick options out of a regression-test string == int options(int type, char *s); */ int options(type, s) int type; /* 'c' compile, 'e' exec */ char *s; { register char *p; register int o = (type == 'c') ? copts : eopts; register char *legal = (type == 'c') ? "bisnmp" : "^$#tl"; for (p = s; *p != '\0'; p++) if (strchr(legal, *p) != NULL) switch (*p) { case 'b': o &= ~REG_EXTENDED; break; case 'i': o |= REG_ICASE; break; case 's': o |= REG_NOSUB; break; case 'n': o |= REG_NEWLINE; break; case 'm': o &= ~REG_EXTENDED; o |= REG_NOSPEC; break; case 'p': o |= REG_PEND; break; case '^': o |= REG_NOTBOL; break; case '$': o |= REG_NOTEOL; break; case '#': o |= REG_STARTEND; break; case 't': /* trace */ o |= REG_TRACE; break; case 'l': /* force long representation */ o |= REG_LARGE; break; case 'r': /* force backref use */ o |= REG_BACKR; break; } return(o); } /* - opt - is a particular option in a regression string? == int opt(int c, char *s); */ int /* predicate */ opt(c, s) int c; char *s; { return(strchr(s, c) != NULL); } /* - fixstr - transform magic characters in strings == void fixstr(register char *p); */ void fixstr(p) register char *p; { if (p == NULL) return; for (; *p != '\0'; p++) if (*p == 'N') *p = '\n'; else if (*p == 'T') *p = '\t'; else if (*p == 'S') *p = ' '; else if (*p == 'Z') *p = '\0'; } /* - check - check a substring match == char *check(char *str, regmatch_t sub, char *should); */ char * /* NULL or complaint */ check(str, sub, should) char *str; regmatch_t sub; char *should; { register int len; register int shlen; register char *p; static char grump[500]; register char *at = NULL; if (should != NULL && strcmp(should, "-") == 0) should = NULL; if (should != NULL && should[0] == '@') { at = should + 1; should = ""; } /* check rm_so and rm_eo for consistency */ if (sub.rm_so > sub.rm_eo || (sub.rm_so == -1 && sub.rm_eo != -1) || (sub.rm_so != -1 && sub.rm_eo == -1) || (sub.rm_so != -1 && sub.rm_so < 0) || (sub.rm_eo != -1 && sub.rm_eo < 0) ) { sprintf(grump, "start %ld end %ld", (long)sub.rm_so, (long)sub.rm_eo); return(grump); } /* check for no match */ if (sub.rm_so == -1 && should == NULL) return(NULL); if (sub.rm_so == -1) return("did not match"); /* check for in range */ if (sub.rm_eo > strlen(str)) { sprintf(grump, "start %ld end %ld, past end of string", (long)sub.rm_so, (long)sub.rm_eo); return(grump); } len = (int)(sub.rm_eo - sub.rm_so); shlen = (int)strlen(should); p = str + sub.rm_so; /* check for not supposed to match */ if (should == NULL) { sprintf(grump, "matched `%.*s'", len, p); return(grump); } /* check for wrong match */ if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) { sprintf(grump, "matched `%.*s' instead", len, p); return(grump); } if (shlen > 0) return(NULL); /* check null match in right place */ if (at == NULL) return(NULL); shlen = strlen(at); if (shlen == 0) shlen = 1; /* force check for end-of-string */ if (strncmp(p, at, shlen) != 0) { sprintf(grump, "matched null at `%.20s'", p); return(grump); } return(NULL); } /* - eprint - convert error number to name == static char *eprint(int err); */ static char * eprint(err) int err; { static char epbuf[100]; size_t len; len = regerror(REG_ITOA|err, (regex_t *)NULL, epbuf, sizeof(epbuf)); assert(len <= sizeof(epbuf)); return(epbuf); } /* - efind - convert error name to number == static int efind(char *name); */ static int efind(name) char *name; { static char efbuf[100]; size_t n; regex_t re; sprintf(efbuf, "REG_%s", name); assert(strlen(efbuf) < sizeof(efbuf)); re.re_endp = efbuf; (void) regerror(REG_ATOI, &re, efbuf, sizeof(efbuf)); return(atoi(efbuf)); } ippsample/vcnet/regex/cname.h0000644000175000017500000000351213240604116015225 0ustar tilltill/* character-name table */ static struct cname { char *name; char code; } cnames[] = { "NUL", '\0', "SOH", '\001', "STX", '\002', "ETX", '\003', "EOT", '\004', "ENQ", '\005', "ACK", '\006', "BEL", '\007', "alert", '\007', "BS", '\010', "backspace", '\b', "HT", '\011', "tab", '\t', "LF", '\012', "newline", '\n', "VT", '\013', "vertical-tab", '\v', "FF", '\014', "form-feed", '\f', "CR", '\015', "carriage-return", '\r', "SO", '\016', "SI", '\017', "DLE", '\020', "DC1", '\021', "DC2", '\022', "DC3", '\023', "DC4", '\024', "NAK", '\025', "SYN", '\026', "ETB", '\027', "CAN", '\030', "EM", '\031', "SUB", '\032', "ESC", '\033', "IS4", '\034', "FS", '\034', "IS3", '\035', "GS", '\035', "IS2", '\036', "RS", '\036', "IS1", '\037', "US", '\037', "space", ' ', "exclamation-mark", '!', "quotation-mark", '"', "number-sign", '#', "dollar-sign", '$', "percent-sign", '%', "ampersand", '&', "apostrophe", '\'', "left-parenthesis", '(', "right-parenthesis", ')', "asterisk", '*', "plus-sign", '+', "comma", ',', "hyphen", '-', "hyphen-minus", '-', "period", '.', "full-stop", '.', "slash", '/', "solidus", '/', "zero", '0', "one", '1', "two", '2', "three", '3', "four", '4', "five", '5', "six", '6', "seven", '7', "eight", '8', "nine", '9', "colon", ':', "semicolon", ';', "less-than-sign", '<', "equals-sign", '=', "greater-than-sign", '>', "question-mark", '?', "commercial-at", '@', "left-square-bracket", '[', "backslash", '\\', "reverse-solidus", '\\', "right-square-bracket", ']', "circumflex", '^', "circumflex-accent", '^', "underscore", '_', "low-line", '_', "grave-accent", '`', "left-brace", '{', "left-curly-bracket", '{', "vertical-line", '|', "right-brace", '}', "right-curly-bracket", '}', "tilde", '~', "DEL", '\177', NULL, 0, }; ippsample/vcnet/regex/utils.h0000644000175000017500000000076413240604116015310 0ustar tilltill/* utility definitions */ #ifdef _POSIX2_RE_DUP_MAX #define DUPMAX _POSIX2_RE_DUP_MAX #else #define DUPMAX 255 #endif #define INFINITY (DUPMAX + 1) #define NC (CHAR_MAX - CHAR_MIN + 1) typedef unsigned char uch; /* switch off assertions (if not already off) if no REDEBUG */ #ifndef REDEBUG #ifndef NDEBUG #define NDEBUG /* no assertions please */ #endif #endif #include /* for old systems with bcopy() but no memmove() */ #ifdef USEBCOPY #define memmove(d, s, c) bcopy(s, d, c) #endif ippsample/vcnet/regex/debug.c0000644000175000017500000001174413240604116015231 0ustar tilltill#include #include #include #include #include #include #include #include "utils.h" #include "regex2.h" #include "debug.ih" /* - regprint - print a regexp for debugging == void regprint(regex_t *r, FILE *d); */ void regprint(r, d) regex_t *r; FILE *d; { register struct re_guts *g = r->re_g; register int i; register int c; register int last; int nincat[NC]; fprintf(d, "%ld states, %d categories", (long)g->nstates, g->ncategories); fprintf(d, ", first %ld last %ld", (long)g->firststate, (long)g->laststate); if (g->iflags&USEBOL) fprintf(d, ", USEBOL"); if (g->iflags&USEEOL) fprintf(d, ", USEEOL"); if (g->iflags&BAD) fprintf(d, ", BAD"); if (g->nsub > 0) fprintf(d, ", nsub=%ld", (long)g->nsub); if (g->must != NULL) fprintf(d, ", must(%ld) `%*s'", (long)g->mlen, (int)g->mlen, g->must); if (g->backrefs) fprintf(d, ", backrefs"); if (g->nplus > 0) fprintf(d, ", nplus %ld", (long)g->nplus); fprintf(d, "\n"); s_print(g, d); for (i = 0; i < g->ncategories; i++) { nincat[i] = 0; for (c = CHAR_MIN; c <= CHAR_MAX; c++) if (g->categories[c] == i) nincat[i]++; } fprintf(d, "cc0#%d", nincat[0]); for (i = 1; i < g->ncategories; i++) if (nincat[i] == 1) { for (c = CHAR_MIN; c <= CHAR_MAX; c++) if (g->categories[c] == i) break; fprintf(d, ", %d=%s", i, regchar(c)); } fprintf(d, "\n"); for (i = 1; i < g->ncategories; i++) if (nincat[i] != 1) { fprintf(d, "cc%d\t", i); last = -1; for (c = CHAR_MIN; c <= CHAR_MAX+1; c++) /* +1 does flush */ if (c <= CHAR_MAX && g->categories[c] == i) { if (last < 0) { fprintf(d, "%s", regchar(c)); last = c; } } else { if (last >= 0) { if (last != c-1) fprintf(d, "-%s", regchar(c-1)); last = -1; } } fprintf(d, "\n"); } } /* - s_print - print the strip for debugging == static void s_print(register struct re_guts *g, FILE *d); */ static void s_print(g, d) register struct re_guts *g; FILE *d; { register sop *s; register cset *cs; register int i; register int done = 0; register sop opnd; register int col = 0; register int last; register sopno offset = 2; # define GAP() { if (offset % 5 == 0) { \ if (col > 40) { \ fprintf(d, "\n\t"); \ col = 0; \ } else { \ fprintf(d, " "); \ col++; \ } \ } else \ col++; \ offset++; \ } if (OP(g->strip[0]) != OEND) fprintf(d, "missing initial OEND!\n"); for (s = &g->strip[1]; !done; s++) { opnd = OPND(*s); switch (OP(*s)) { case OEND: fprintf(d, "\n"); done = 1; break; case OCHAR: if (strchr("\\|()^$.[+*?{}!<> ", (char)opnd) != NULL) fprintf(d, "\\%c", (char)opnd); else fprintf(d, "%s", regchar((char)opnd)); break; case OBOL: fprintf(d, "^"); break; case OEOL: fprintf(d, "$"); break; case OBOW: fprintf(d, "\\{"); break; case OEOW: fprintf(d, "\\}"); break; case OANY: fprintf(d, "."); break; case OANYOF: fprintf(d, "[(%ld)", (long)opnd); cs = &g->sets[opnd]; last = -1; for (i = 0; i < g->csetsize+1; i++) /* +1 flushes */ if (CHIN(cs, i) && i < g->csetsize) { if (last < 0) { fprintf(d, "%s", regchar(i)); last = i; } } else { if (last >= 0) { if (last != i-1) fprintf(d, "-%s", regchar(i-1)); last = -1; } } fprintf(d, "]"); break; case OBACK_: fprintf(d, "(\\<%ld>", (long)opnd); break; case O_BACK: fprintf(d, "<%ld>\\)", (long)opnd); break; case OPLUS_: fprintf(d, "(+"); if (OP(*(s+opnd)) != O_PLUS) fprintf(d, "<%ld>", (long)opnd); break; case O_PLUS: if (OP(*(s-opnd)) != OPLUS_) fprintf(d, "<%ld>", (long)opnd); fprintf(d, "+)"); break; case OQUEST_: fprintf(d, "(?"); if (OP(*(s+opnd)) != O_QUEST) fprintf(d, "<%ld>", (long)opnd); break; case O_QUEST: if (OP(*(s-opnd)) != OQUEST_) fprintf(d, "<%ld>", (long)opnd); fprintf(d, "?)"); break; case OLPAREN: fprintf(d, "((<%ld>", (long)opnd); break; case ORPAREN: fprintf(d, "<%ld>))", (long)opnd); break; case OCH_: fprintf(d, "<"); if (OP(*(s+opnd)) != OOR2) fprintf(d, "<%ld>", (long)opnd); break; case OOR1: if (OP(*(s-opnd)) != OOR1 && OP(*(s-opnd)) != OCH_) fprintf(d, "<%ld>", (long)opnd); fprintf(d, "|"); break; case OOR2: fprintf(d, "|"); if (OP(*(s+opnd)) != OOR2 && OP(*(s+opnd)) != O_CH) fprintf(d, "<%ld>", (long)opnd); break; case O_CH: if (OP(*(s-opnd)) != OOR1) fprintf(d, "<%ld>", (long)opnd); fprintf(d, ">"); break; default: fprintf(d, "!%d(%d)!", OP(*s), opnd); break; } if (!done) GAP(); } } /* - regchar - make a character printable == static char *regchar(int ch); */ static char * /* -> representation */ regchar(ch) int ch; { static char buf[10]; if (isprint(ch) || ch == ' ') sprintf(buf, "%c", ch); else sprintf(buf, "\\%o", ch); return(buf); } ippsample/vcnet/regex/regexec.c0000644000175000017500000001021613240604116015556 0ustar tilltill/* * the outer shell of regexec() * * This file includes engine.c *twice*, after muchos fiddling with the * macros that code uses. This lets the same code operate on two different * representations for state sets. */ #include #include #include #include #include #include #include #include "utils.h" #include "regex2.h" static int nope = 0; /* for use in asserts; shuts lint up */ /* macros for manipulating states, small version */ #define states unsigned #define states1 unsigned /* for later use in regexec() decision */ #define CLEAR(v) ((v) = 0) #define SET0(v, n) ((v) &= ~((unsigned)1 << (n))) #define SET1(v, n) ((v) |= (unsigned)1 << (n)) #define ISSET(v, n) ((v) & ((unsigned)1 << (n))) #define ASSIGN(d, s) ((d) = (s)) #define EQ(a, b) ((a) == (b)) #define STATEVARS int dummy /* dummy version */ #define STATESETUP(m, n) /* nothing */ #define STATETEARDOWN(m) /* nothing */ #define SETUP(v) ((v) = 0) #define onestate unsigned #define INIT(o, n) ((o) = (unsigned)1 << (n)) #define INC(o) ((o) <<= 1) #define ISSTATEIN(v, o) ((v) & (o)) /* some abbreviations; note that some of these know variable names! */ /* do "if I'm here, I can also be there" etc without branches */ #define FWD(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) << (n)) #define BACK(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) >> (n)) #define ISSETBACK(v, n) ((v) & ((unsigned)here >> (n))) /* function names */ #define SNAMES /* engine.c looks after details */ #include "engine.c" /* now undo things */ #undef states #undef CLEAR #undef SET0 #undef SET1 #undef ISSET #undef ASSIGN #undef EQ #undef STATEVARS #undef STATESETUP #undef STATETEARDOWN #undef SETUP #undef onestate #undef INIT #undef INC #undef ISSTATEIN #undef FWD #undef BACK #undef ISSETBACK #undef SNAMES /* macros for manipulating states, large version */ #define states char * #define CLEAR(v) memset(v, 0, m->g->nstates) #define SET0(v, n) ((v)[n] = 0) #define SET1(v, n) ((v)[n] = 1) #define ISSET(v, n) ((v)[n]) #define ASSIGN(d, s) memcpy(d, s, m->g->nstates) #define EQ(a, b) (memcmp(a, b, m->g->nstates) == 0) #define STATEVARS int vn; char *space #define STATESETUP(m, nv) { (m)->space = malloc((nv)*(m)->g->nstates); \ if ((m)->space == NULL) return(REG_ESPACE); \ (m)->vn = 0; } #define STATETEARDOWN(m) { free((m)->space); } #define SETUP(v) ((v) = &m->space[m->vn++ * m->g->nstates]) #define onestate int #define INIT(o, n) ((o) = (n)) #define INC(o) ((o)++) #define ISSTATEIN(v, o) ((v)[o]) /* some abbreviations; note that some of these know variable names! */ /* do "if I'm here, I can also be there" etc without branches */ #define FWD(dst, src, n) ((dst)[here+(n)] |= (src)[here]) #define BACK(dst, src, n) ((dst)[here-(n)] |= (src)[here]) #define ISSETBACK(v, n) ((v)[here - (n)]) /* function names */ #define LNAMES /* flag */ #include "engine.c" /* - regexec - interface for matching = extern int regexec(const regex_t *, const char *, size_t, \ = regmatch_t [], int); = #define REG_NOTBOL 00001 = #define REG_NOTEOL 00002 = #define REG_STARTEND 00004 = #define REG_TRACE 00400 // tracing of execution = #define REG_LARGE 01000 // force large representation = #define REG_BACKR 02000 // force use of backref code * * We put this here so we can exploit knowledge of the state representation * when choosing which matcher to call. Also, by this point the matchers * have been prototyped. */ int /* 0 success, REG_NOMATCH failure */ regexec(preg, string, nmatch, pmatch, eflags) const regex_t *preg; const char *string; size_t nmatch; regmatch_t pmatch[]; int eflags; { register struct re_guts *g = preg->re_g; #ifdef REDEBUG # define GOODFLAGS(f) (f) #else # define GOODFLAGS(f) ((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND)) #endif if (preg->re_magic != MAGIC1 || g->magic != MAGIC2) return(REG_BADPAT); assert(!(g->iflags&BAD)); if (g->iflags&BAD) /* backstop for no-debug case */ return(REG_BADPAT); eflags = GOODFLAGS(eflags); if (g->nstates <= CHAR_BIT*sizeof(states1) && !(eflags®_LARGE)) return(smatcher(g, (char *)string, nmatch, pmatch, eflags)); else return(lmatcher(g, (char *)string, nmatch, pmatch, eflags)); } ippsample/vcnet/regex/split.c0000644000175000017500000001562513240604116015300 0ustar tilltill#include #include /* - split - divide a string into fields, like awk split() = int split(char *string, char *fields[], int nfields, char *sep); */ int /* number of fields, including overflow */ split(string, fields, nfields, sep) char *string; char *fields[]; /* list is not NULL-terminated */ int nfields; /* number of entries available in fields[] */ char *sep; /* "" white, "c" single char, "ab" [ab]+ */ { register char *p = string; register char c; /* latest character */ register char sepc = sep[0]; register char sepc2; register int fn; register char **fp = fields; register char *sepp; register int trimtrail; /* white space */ if (sepc == '\0') { while ((c = *p++) == ' ' || c == '\t') continue; p--; trimtrail = 1; sep = " \t"; /* note, code below knows this is 2 long */ sepc = ' '; } else trimtrail = 0; sepc2 = sep[1]; /* now we can safely pick this up */ /* catch empties */ if (*p == '\0') return(0); /* single separator */ if (sepc2 == '\0') { fn = nfields; for (;;) { *fp++ = p; fn--; if (fn == 0) break; while ((c = *p++) != sepc) if (c == '\0') return(nfields - fn); *(p-1) = '\0'; } /* we have overflowed the fields vector -- just count them */ fn = nfields; for (;;) { while ((c = *p++) != sepc) if (c == '\0') return(fn); fn++; } /* not reached */ } /* two separators */ if (sep[2] == '\0') { fn = nfields; for (;;) { *fp++ = p; fn--; while ((c = *p++) != sepc && c != sepc2) if (c == '\0') { if (trimtrail && **(fp-1) == '\0') fn++; return(nfields - fn); } if (fn == 0) break; *(p-1) = '\0'; while ((c = *p++) == sepc || c == sepc2) continue; p--; } /* we have overflowed the fields vector -- just count them */ fn = nfields; while (c != '\0') { while ((c = *p++) == sepc || c == sepc2) continue; p--; fn++; while ((c = *p++) != '\0' && c != sepc && c != sepc2) continue; } /* might have to trim trailing white space */ if (trimtrail) { p--; while ((c = *--p) == sepc || c == sepc2) continue; p++; if (*p != '\0') { if (fn == nfields+1) *p = '\0'; fn--; } } return(fn); } /* n separators */ fn = 0; for (;;) { if (fn < nfields) *fp++ = p; fn++; for (;;) { c = *p++; if (c == '\0') return(fn); sepp = sep; while ((sepc = *sepp++) != '\0' && sepc != c) continue; if (sepc != '\0') /* it was a separator */ break; } if (fn < nfields) *(p-1) = '\0'; for (;;) { c = *p++; sepp = sep; while ((sepc = *sepp++) != '\0' && sepc != c) continue; if (sepc == '\0') /* it wasn't a separator */ break; } p--; } /* not reached */ } #ifdef TEST_SPLIT /* * test program * pgm runs regression * pgm sep splits stdin lines by sep * pgm str sep splits str by sep * pgm str sep n splits str by sep n times */ int main(argc, argv) int argc; char *argv[]; { char buf[512]; register int n; # define MNF 10 char *fields[MNF]; if (argc > 4) for (n = atoi(argv[3]); n > 0; n--) { (void) strcpy(buf, argv[1]); } else if (argc > 3) for (n = atoi(argv[3]); n > 0; n--) { (void) strcpy(buf, argv[1]); (void) split(buf, fields, MNF, argv[2]); } else if (argc > 2) dosplit(argv[1], argv[2]); else if (argc > 1) while (fgets(buf, sizeof(buf), stdin) != NULL) { buf[strlen(buf)-1] = '\0'; /* stomp newline */ dosplit(buf, argv[1]); } else regress(); exit(0); } dosplit(string, seps) char *string; char *seps; { # define NF 5 char *fields[NF]; register int nf; nf = split(string, fields, NF, seps); print(nf, NF, fields); } print(nf, nfp, fields) int nf; int nfp; char *fields[]; { register int fn; register int bound; bound = (nf > nfp) ? nfp : nf; printf("%d:\t", nf); for (fn = 0; fn < bound; fn++) printf("\"%s\"%s", fields[fn], (fn+1 < nf) ? ", " : "\n"); } #define RNF 5 /* some table entries know this */ struct { char *str; char *seps; int nf; char *fi[RNF]; } tests[] = { "", " ", 0, { "" }, " ", " ", 2, { "", "" }, "x", " ", 1, { "x" }, "xy", " ", 1, { "xy" }, "x y", " ", 2, { "x", "y" }, "abc def g ", " ", 5, { "abc", "def", "", "g", "" }, " a bcd", " ", 4, { "", "", "a", "bcd" }, "a b c d e f", " ", 6, { "a", "b", "c", "d", "e f" }, " a b c d ", " ", 6, { "", "a", "b", "c", "d " }, "", " _", 0, { "" }, " ", " _", 2, { "", "" }, "x", " _", 1, { "x" }, "x y", " _", 2, { "x", "y" }, "ab _ cd", " _", 2, { "ab", "cd" }, " a_b c ", " _", 5, { "", "a", "b", "c", "" }, "a b c_d e f", " _", 6, { "a", "b", "c", "d", "e f" }, " a b c d ", " _", 6, { "", "a", "b", "c", "d " }, "", " _~", 0, { "" }, " ", " _~", 2, { "", "" }, "x", " _~", 1, { "x" }, "x y", " _~", 2, { "x", "y" }, "ab _~ cd", " _~", 2, { "ab", "cd" }, " a_b c~", " _~", 5, { "", "a", "b", "c", "" }, "a b_c d~e f", " _~", 6, { "a", "b", "c", "d", "e f" }, "~a b c d ", " _~", 6, { "", "a", "b", "c", "d " }, "", " _~-", 0, { "" }, " ", " _~-", 2, { "", "" }, "x", " _~-", 1, { "x" }, "x y", " _~-", 2, { "x", "y" }, "ab _~- cd", " _~-", 2, { "ab", "cd" }, " a_b c~", " _~-", 5, { "", "a", "b", "c", "" }, "a b_c-d~e f", " _~-", 6, { "a", "b", "c", "d", "e f" }, "~a-b c d ", " _~-", 6, { "", "a", "b", "c", "d " }, "", " ", 0, { "" }, " ", " ", 2, { "", "" }, "x", " ", 1, { "x" }, "xy", " ", 1, { "xy" }, "x y", " ", 2, { "x", "y" }, "abc def g ", " ", 4, { "abc", "def", "g", "" }, " a bcd", " ", 3, { "", "a", "bcd" }, "a b c d e f", " ", 6, { "a", "b", "c", "d", "e f" }, " a b c d ", " ", 6, { "", "a", "b", "c", "d " }, "", "", 0, { "" }, " ", "", 0, { "" }, "x", "", 1, { "x" }, "xy", "", 1, { "xy" }, "x y", "", 2, { "x", "y" }, "abc def g ", "", 3, { "abc", "def", "g" }, "\t a bcd", "", 2, { "a", "bcd" }, " a \tb\t c ", "", 3, { "a", "b", "c" }, "a b c d e ", "", 5, { "a", "b", "c", "d", "e" }, "a b\tc d e f", "", 6, { "a", "b", "c", "d", "e f" }, " a b c d e f ", "", 6, { "a", "b", "c", "d", "e f " }, NULL, NULL, 0, { NULL }, }; regress() { char buf[512]; register int n; char *fields[RNF+1]; register int nf; register int i; register int printit; register char *f; for (n = 0; tests[n].str != NULL; n++) { (void) strcpy(buf, tests[n].str); fields[RNF] = NULL; nf = split(buf, fields, RNF, tests[n].seps); printit = 0; if (nf != tests[n].nf) { printf("split `%s' by `%s' gave %d fields, not %d\n", tests[n].str, tests[n].seps, nf, tests[n].nf); printit = 1; } else if (fields[RNF] != NULL) { printf("split() went beyond array end\n"); printit = 1; } else { for (i = 0; i < nf && i < RNF; i++) { f = fields[i]; if (f == NULL) f = "(NULL)"; if (strcmp(f, tests[n].fi[i]) != 0) { printf("split `%s' by `%s', field %d is `%s', not `%s'\n", tests[n].str, tests[n].seps, i, fields[i], tests[n].fi[i]); printit = 1; } } } if (printit) print(nf, RNF, fields); } } #endif ippsample/vcnet/regex/engine.c0000644000175000017500000006171513240604116015413 0ustar tilltill/* * The matching engine and friends. This file is #included by regexec.c * after suitable #defines of a variety of macros used herein, so that * different state representations can be used without duplicating masses * of code. */ #ifdef SNAMES #define matcher smatcher #define fast sfast #define slow sslow #define dissect sdissect #define backref sbackref #define step sstep #define print sprint #define at sat #define match smat #endif #ifdef LNAMES #define matcher lmatcher #define fast lfast #define slow lslow #define dissect ldissect #define backref lbackref #define step lstep #define print lprint #define at lat #define match lmat #endif /* another structure passed up and down to avoid zillions of parameters */ struct match { struct re_guts *g; int eflags; regmatch_t *pmatch; /* [nsub+1] (0 element unused) */ char *offp; /* offsets work from here */ char *beginp; /* start of string -- virtual NUL precedes */ char *endp; /* end of string -- virtual NUL here */ char *coldp; /* can be no match starting before here */ char **lastpos; /* [nplus+1] */ STATEVARS; states st; /* current states */ states fresh; /* states for a fresh start */ states tmp; /* temporary */ states empty; /* empty set of states */ }; #include "engine.ih" #ifdef REDEBUG #define SP(t, s, c) print(m, t, s, c, stdout) #define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2) #define NOTE(str) { if (m->eflags®_TRACE) printf("=%s\n", (str)); } #else #define SP(t, s, c) /* nothing */ #define AT(t, p1, p2, s1, s2) /* nothing */ #define NOTE(s) /* nothing */ #endif /* - matcher - the actual matching engine == static int matcher(register struct re_guts *g, char *string, \ == size_t nmatch, regmatch_t pmatch[], int eflags); */ static int /* 0 success, REG_NOMATCH failure */ matcher(g, string, nmatch, pmatch, eflags) register struct re_guts *g; char *string; size_t nmatch; regmatch_t pmatch[]; int eflags; { register char *endp; register size_t i; struct match mv; register struct match *m = &mv; register char *dp; const register sopno gf = g->firststate+1; /* +1 for OEND */ const register sopno gl = g->laststate; char *start; char *stop; /* simplify the situation where possible */ if (g->cflags®_NOSUB) nmatch = 0; if (eflags®_STARTEND) { start = string + pmatch[0].rm_so; stop = string + pmatch[0].rm_eo; } else { start = string; stop = start + strlen(start); } if (stop < start) return(REG_INVARG); /* prescreening; this does wonders for this rather slow code */ if (g->must != NULL) { for (dp = start; dp < stop; dp++) if (*dp == g->must[0] && stop - dp >= g->mlen && memcmp(dp, g->must, (size_t)g->mlen) == 0) break; if (dp == stop) /* we didn't find g->must */ return(REG_NOMATCH); } /* match struct setup */ m->g = g; m->eflags = eflags; m->pmatch = NULL; m->lastpos = NULL; m->offp = string; m->beginp = start; m->endp = stop; STATESETUP(m, 4); SETUP(m->st); SETUP(m->fresh); SETUP(m->tmp); SETUP(m->empty); CLEAR(m->empty); /* this loop does only one repetition except for backrefs */ for (;;) { endp = fast(m, start, stop, gf, gl); if (endp == NULL) { /* a miss */ STATETEARDOWN(m); return(REG_NOMATCH); } if (nmatch == 0 && !g->backrefs) break; /* no further info needed */ /* where? */ assert(m->coldp != NULL); for (;;) { NOTE("finding start"); endp = slow(m, m->coldp, stop, gf, gl); if (endp != NULL) break; assert(m->coldp < m->endp); m->coldp++; } if (nmatch == 1 && !g->backrefs) break; /* no further info needed */ /* oh my, he wants the subexpressions... */ if (m->pmatch == NULL) m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) * sizeof(regmatch_t)); if (m->pmatch == NULL) { STATETEARDOWN(m); return(REG_ESPACE); } for (i = 1; i <= m->g->nsub; i++) m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1; if (!g->backrefs && !(m->eflags®_BACKR)) { NOTE("dissecting"); dp = dissect(m, m->coldp, endp, gf, gl); } else { if (g->nplus > 0 && m->lastpos == NULL) m->lastpos = (char **)malloc((g->nplus+1) * sizeof(char *)); if (g->nplus > 0 && m->lastpos == NULL) { free(m->pmatch); STATETEARDOWN(m); return(REG_ESPACE); } NOTE("backref dissect"); dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); } if (dp != NULL) break; /* uh-oh... we couldn't find a subexpression-level match */ assert(g->backrefs); /* must be back references doing it */ assert(g->nplus == 0 || m->lastpos != NULL); for (;;) { if (dp != NULL || endp <= m->coldp) break; /* defeat */ NOTE("backoff"); endp = slow(m, m->coldp, endp-1, gf, gl); if (endp == NULL) break; /* defeat */ /* try it on a shorter possibility */ #ifndef NDEBUG for (i = 1; i <= m->g->nsub; i++) { assert(m->pmatch[i].rm_so == -1); assert(m->pmatch[i].rm_eo == -1); } #endif NOTE("backoff dissect"); dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); } assert(dp == NULL || dp == endp); if (dp != NULL) /* found a shorter one */ break; /* despite initial appearances, there is no match here */ NOTE("false alarm"); start = m->coldp + 1; /* recycle starting later */ assert(start <= stop); } /* fill in the details if requested */ if (nmatch > 0) { pmatch[0].rm_so = m->coldp - m->offp; pmatch[0].rm_eo = endp - m->offp; } if (nmatch > 1) { assert(m->pmatch != NULL); for (i = 1; i < nmatch; i++) if (i <= m->g->nsub) pmatch[i] = m->pmatch[i]; else { pmatch[i].rm_so = -1; pmatch[i].rm_eo = -1; } } if (m->pmatch != NULL) free((char *)m->pmatch); if (m->lastpos != NULL) free((char *)m->lastpos); STATETEARDOWN(m); return(0); } /* - dissect - figure out what matched what, no back references == static char *dissect(register struct match *m, char *start, \ == char *stop, sopno startst, sopno stopst); */ static char * /* == stop (success) always */ dissect(m, start, stop, startst, stopst) register struct match *m; char *start; char *stop; sopno startst; sopno stopst; { register int i; register sopno ss; /* start sop of current subRE */ register sopno es; /* end sop of current subRE */ register char *sp; /* start of string matched by it */ register char *stp; /* string matched by it cannot pass here */ register char *rest; /* start of rest of string */ register char *tail; /* string unmatched by rest of RE */ register sopno ssub; /* start sop of subsubRE */ register sopno esub; /* end sop of subsubRE */ register char *ssp; /* start of string matched by subsubRE */ register char *sep; /* end of string matched by subsubRE */ register char *oldssp; /* previous ssp */ register char *dp; AT("diss", start, stop, startst, stopst); sp = start; for (ss = startst; ss < stopst; ss = es) { /* identify end of subRE */ es = ss; switch (OP(m->g->strip[es])) { case OPLUS_: case OQUEST_: es += OPND(m->g->strip[es]); break; case OCH_: while (OP(m->g->strip[es]) != O_CH) es += OPND(m->g->strip[es]); break; } es++; /* figure out what it matched */ switch (OP(m->g->strip[ss])) { case OEND: assert(nope); break; case OCHAR: sp++; break; case OBOL: case OEOL: case OBOW: case OEOW: break; case OANY: case OANYOF: sp++; break; case OBACK_: case O_BACK: assert(nope); break; /* cases where length of match is hard to find */ case OQUEST_: stp = stop; for (;;) { /* how long could this one be? */ rest = slow(m, sp, stp, ss, es); assert(rest != NULL); /* it did match */ /* could the rest match the rest? */ tail = slow(m, rest, stop, es, stopst); if (tail == stop) break; /* yes! */ /* no -- try a shorter match for this one */ stp = rest - 1; assert(stp >= sp); /* it did work */ } ssub = ss + 1; esub = es - 1; /* did innards match? */ if (slow(m, sp, rest, ssub, esub) != NULL) { dp = dissect(m, sp, rest, ssub, esub); assert(dp == rest); } else /* no */ assert(sp == rest); sp = rest; break; case OPLUS_: stp = stop; for (;;) { /* how long could this one be? */ rest = slow(m, sp, stp, ss, es); assert(rest != NULL); /* it did match */ /* could the rest match the rest? */ tail = slow(m, rest, stop, es, stopst); if (tail == stop) break; /* yes! */ /* no -- try a shorter match for this one */ stp = rest - 1; assert(stp >= sp); /* it did work */ } ssub = ss + 1; esub = es - 1; ssp = sp; oldssp = ssp; for (;;) { /* find last match of innards */ sep = slow(m, ssp, rest, ssub, esub); if (sep == NULL || sep == ssp) break; /* failed or matched null */ oldssp = ssp; /* on to next try */ ssp = sep; } if (sep == NULL) { /* last successful match */ sep = ssp; ssp = oldssp; } assert(sep == rest); /* must exhaust substring */ assert(slow(m, ssp, sep, ssub, esub) == rest); dp = dissect(m, ssp, sep, ssub, esub); assert(dp == sep); sp = rest; break; case OCH_: stp = stop; for (;;) { /* how long could this one be? */ rest = slow(m, sp, stp, ss, es); assert(rest != NULL); /* it did match */ /* could the rest match the rest? */ tail = slow(m, rest, stop, es, stopst); if (tail == stop) break; /* yes! */ /* no -- try a shorter match for this one */ stp = rest - 1; assert(stp >= sp); /* it did work */ } ssub = ss + 1; esub = ss + OPND(m->g->strip[ss]) - 1; assert(OP(m->g->strip[esub]) == OOR1); for (;;) { /* find first matching branch */ if (slow(m, sp, rest, ssub, esub) == rest) break; /* it matched all of it */ /* that one missed, try next one */ assert(OP(m->g->strip[esub]) == OOR1); esub++; assert(OP(m->g->strip[esub]) == OOR2); ssub = esub + 1; esub += OPND(m->g->strip[esub]); if (OP(m->g->strip[esub]) == OOR2) esub--; else assert(OP(m->g->strip[esub]) == O_CH); } dp = dissect(m, sp, rest, ssub, esub); assert(dp == rest); sp = rest; break; case O_PLUS: case O_QUEST: case OOR1: case OOR2: case O_CH: assert(nope); break; case OLPAREN: i = OPND(m->g->strip[ss]); assert(0 < i && i <= m->g->nsub); m->pmatch[i].rm_so = sp - m->offp; break; case ORPAREN: i = OPND(m->g->strip[ss]); assert(0 < i && i <= m->g->nsub); m->pmatch[i].rm_eo = sp - m->offp; break; default: /* uh oh */ assert(nope); break; } } assert(sp == stop); return(sp); } /* - backref - figure out what matched what, figuring in back references == static char *backref(register struct match *m, char *start, \ == char *stop, sopno startst, sopno stopst, sopno lev); */ static char * /* == stop (success) or NULL (failure) */ backref(m, start, stop, startst, stopst, lev) register struct match *m; char *start; char *stop; sopno startst; sopno stopst; sopno lev; /* PLUS nesting level */ { register int i; register sopno ss; /* start sop of current subRE */ register char *sp; /* start of string matched by it */ register sopno ssub; /* start sop of subsubRE */ register sopno esub; /* end sop of subsubRE */ register char *ssp; /* start of string matched by subsubRE */ register char *dp; register size_t len; register int hard; register sop s; register regoff_t offsave; register cset *cs; AT("back", start, stop, startst, stopst); sp = start; /* get as far as we can with easy stuff */ hard = 0; for (ss = startst; !hard && ss < stopst; ss++) switch (OP(s = m->g->strip[ss])) { case OCHAR: if (sp == stop || *sp++ != (char)OPND(s)) return(NULL); break; case OANY: if (sp == stop) return(NULL); sp++; break; case OANYOF: cs = &m->g->sets[OPND(s)]; if (sp == stop || !CHIN(cs, *sp++)) return(NULL); break; case OBOL: if ( (sp == m->beginp && !(m->eflags®_NOTBOL)) || (sp < m->endp && *(sp-1) == '\n' && (m->g->cflags®_NEWLINE)) ) { /* yes */ } else return(NULL); break; case OEOL: if ( (sp == m->endp && !(m->eflags®_NOTEOL)) || (sp < m->endp && *sp == '\n' && (m->g->cflags®_NEWLINE)) ) { /* yes */ } else return(NULL); break; case OBOW: if (( (sp == m->beginp && !(m->eflags®_NOTBOL)) || (sp < m->endp && *(sp-1) == '\n' && (m->g->cflags®_NEWLINE)) || (sp > m->beginp && !ISWORD(*(sp-1))) ) && (sp < m->endp && ISWORD(*sp)) ) { /* yes */ } else return(NULL); break; case OEOW: if (( (sp == m->endp && !(m->eflags®_NOTEOL)) || (sp < m->endp && *sp == '\n' && (m->g->cflags®_NEWLINE)) || (sp < m->endp && !ISWORD(*sp)) ) && (sp > m->beginp && ISWORD(*(sp-1))) ) { /* yes */ } else return(NULL); break; case O_QUEST: break; case OOR1: /* matches null but needs to skip */ ss++; s = m->g->strip[ss]; do { assert(OP(s) == OOR2); ss += OPND(s); } while (OP(s = m->g->strip[ss]) != O_CH); /* note that the ss++ gets us past the O_CH */ break; default: /* have to make a choice */ hard = 1; break; } if (!hard) { /* that was it! */ if (sp != stop) return(NULL); return(sp); } ss--; /* adjust for the for's final increment */ /* the hard stuff */ AT("hard", sp, stop, ss, stopst); s = m->g->strip[ss]; switch (OP(s)) { case OBACK_: /* the vilest depths */ i = OPND(s); assert(0 < i && i <= m->g->nsub); if (m->pmatch[i].rm_eo == -1) return(NULL); assert(m->pmatch[i].rm_so != -1); len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so; assert(stop - m->beginp >= len); if (sp > stop - len) return(NULL); /* not enough left to match */ ssp = m->offp + m->pmatch[i].rm_so; if (memcmp(sp, ssp, len) != 0) return(NULL); while (m->g->strip[ss] != SOP(O_BACK, i)) ss++; return(backref(m, sp+len, stop, ss+1, stopst, lev)); break; case OQUEST_: /* to null or not */ dp = backref(m, sp, stop, ss+1, stopst, lev); if (dp != NULL) return(dp); /* not */ return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev)); break; case OPLUS_: assert(m->lastpos != NULL); assert(lev+1 <= m->g->nplus); m->lastpos[lev+1] = sp; return(backref(m, sp, stop, ss+1, stopst, lev+1)); break; case O_PLUS: if (sp == m->lastpos[lev]) /* last pass matched null */ return(backref(m, sp, stop, ss+1, stopst, lev-1)); /* try another pass */ m->lastpos[lev] = sp; dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev); if (dp == NULL) return(backref(m, sp, stop, ss+1, stopst, lev-1)); else return(dp); break; case OCH_: /* find the right one, if any */ ssub = ss + 1; esub = ss + OPND(s) - 1; assert(OP(m->g->strip[esub]) == OOR1); for (;;) { /* find first matching branch */ dp = backref(m, sp, stop, ssub, esub, lev); if (dp != NULL) return(dp); /* that one missed, try next one */ if (OP(m->g->strip[esub]) == O_CH) return(NULL); /* there is none */ esub++; assert(OP(m->g->strip[esub]) == OOR2); ssub = esub + 1; esub += OPND(m->g->strip[esub]); if (OP(m->g->strip[esub]) == OOR2) esub--; else assert(OP(m->g->strip[esub]) == O_CH); } break; case OLPAREN: /* must undo assignment if rest fails */ i = OPND(s); assert(0 < i && i <= m->g->nsub); offsave = m->pmatch[i].rm_so; m->pmatch[i].rm_so = sp - m->offp; dp = backref(m, sp, stop, ss+1, stopst, lev); if (dp != NULL) return(dp); m->pmatch[i].rm_so = offsave; return(NULL); break; case ORPAREN: /* must undo assignment if rest fails */ i = OPND(s); assert(0 < i && i <= m->g->nsub); offsave = m->pmatch[i].rm_eo; m->pmatch[i].rm_eo = sp - m->offp; dp = backref(m, sp, stop, ss+1, stopst, lev); if (dp != NULL) return(dp); m->pmatch[i].rm_eo = offsave; return(NULL); break; default: /* uh oh */ assert(nope); break; } /* "can't happen" */ assert(nope); /* NOTREACHED */ return((char *)NULL); /* dummy */ } /* - fast - step through the string at top speed == static char *fast(register struct match *m, char *start, \ == char *stop, sopno startst, sopno stopst); */ static char * /* where tentative match ended, or NULL */ fast(m, start, stop, startst, stopst) register struct match *m; char *start; char *stop; sopno startst; sopno stopst; { register states st = m->st; register states fresh = m->fresh; register states tmp = m->tmp; register char *p = start; register int c = (start == m->beginp) ? OUT : *(start-1); register int lastc; /* previous c */ register int flagch; register int i; register char *coldp; /* last p after which no match was underway */ CLEAR(st); SET1(st, startst); st = step(m->g, startst, stopst, st, NOTHING, st); ASSIGN(fresh, st); SP("start", st, *p); coldp = NULL; for (;;) { /* next character */ lastc = c; c = (p == m->endp) ? OUT : *p; if (EQ(st, fresh)) coldp = p; /* is there an EOL and/or BOL between lastc and c? */ flagch = '\0'; i = 0; if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || (lastc == OUT && !(m->eflags®_NOTBOL)) ) { flagch = BOL; i = m->g->nbol; } if ( (c == '\n' && m->g->cflags®_NEWLINE) || (c == OUT && !(m->eflags®_NOTEOL)) ) { flagch = (flagch == BOL) ? BOLEOL : EOL; i += m->g->neol; } if (i != 0) { for (; i > 0; i--) st = step(m->g, startst, stopst, st, flagch, st); SP("boleol", st, c); } /* how about a word boundary? */ if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) && (c != OUT && ISWORD(c)) ) { flagch = BOW; } if ( (lastc != OUT && ISWORD(lastc)) && (flagch == EOL || (c != OUT && !ISWORD(c))) ) { flagch = EOW; } if (flagch == BOW || flagch == EOW) { st = step(m->g, startst, stopst, st, flagch, st); SP("boweow", st, c); } /* are we done? */ if (ISSET(st, stopst) || p == stop) break; /* NOTE BREAK OUT */ /* no, we must deal with this character */ ASSIGN(tmp, st); ASSIGN(st, fresh); assert(c != OUT); st = step(m->g, startst, stopst, tmp, c, st); SP("aft", st, c); assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st)); p++; } assert(coldp != NULL); m->coldp = coldp; if (ISSET(st, stopst)) return(p+1); else return(NULL); } /* - slow - step through the string more deliberately == static char *slow(register struct match *m, char *start, \ == char *stop, sopno startst, sopno stopst); */ static char * /* where it ended */ slow(m, start, stop, startst, stopst) register struct match *m; char *start; char *stop; sopno startst; sopno stopst; { register states st = m->st; register states empty = m->empty; register states tmp = m->tmp; register char *p = start; register int c = (start == m->beginp) ? OUT : *(start-1); register int lastc; /* previous c */ register int flagch; register int i; register char *matchp; /* last p at which a match ended */ AT("slow", start, stop, startst, stopst); CLEAR(st); SET1(st, startst); SP("sstart", st, *p); st = step(m->g, startst, stopst, st, NOTHING, st); matchp = NULL; for (;;) { /* next character */ lastc = c; c = (p == m->endp) ? OUT : *p; /* is there an EOL and/or BOL between lastc and c? */ flagch = '\0'; i = 0; if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || (lastc == OUT && !(m->eflags®_NOTBOL)) ) { flagch = BOL; i = m->g->nbol; } if ( (c == '\n' && m->g->cflags®_NEWLINE) || (c == OUT && !(m->eflags®_NOTEOL)) ) { flagch = (flagch == BOL) ? BOLEOL : EOL; i += m->g->neol; } if (i != 0) { for (; i > 0; i--) st = step(m->g, startst, stopst, st, flagch, st); SP("sboleol", st, c); } /* how about a word boundary? */ if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) && (c != OUT && ISWORD(c)) ) { flagch = BOW; } if ( (lastc != OUT && ISWORD(lastc)) && (flagch == EOL || (c != OUT && !ISWORD(c))) ) { flagch = EOW; } if (flagch == BOW || flagch == EOW) { st = step(m->g, startst, stopst, st, flagch, st); SP("sboweow", st, c); } /* are we done? */ if (ISSET(st, stopst)) matchp = p; if (EQ(st, empty) || p == stop) break; /* NOTE BREAK OUT */ /* no, we must deal with this character */ ASSIGN(tmp, st); ASSIGN(st, empty); assert(c != OUT); st = step(m->g, startst, stopst, tmp, c, st); SP("saft", st, c); assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st)); p++; } return(matchp); } /* - step - map set of states reachable before char to set reachable after == static states step(register struct re_guts *g, sopno start, sopno stop, \ == register states bef, int ch, register states aft); == #define BOL (OUT+1) == #define EOL (BOL+1) == #define BOLEOL (BOL+2) == #define NOTHING (BOL+3) == #define BOW (BOL+4) == #define EOW (BOL+5) == #define CODEMAX (BOL+5) // highest code used == #define NONCHAR(c) ((c) > CHAR_MAX) == #define NNONCHAR (CODEMAX-CHAR_MAX) */ static states step(g, start, stop, bef, ch, aft) register struct re_guts *g; sopno start; /* start state within strip */ sopno stop; /* state after stop state within strip */ register states bef; /* states reachable before */ int ch; /* character or NONCHAR code */ register states aft; /* states already known reachable after */ { register cset *cs; register sop s; register sopno pc; register onestate here; /* note, macros know this name */ register sopno look; register long i; for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) { s = g->strip[pc]; switch (OP(s)) { case OEND: assert(pc == stop-1); break; case OCHAR: /* only characters can match */ assert(!NONCHAR(ch) || ch != (char)OPND(s)); if (ch == (char)OPND(s)) FWD(aft, bef, 1); break; case OBOL: if (ch == BOL || ch == BOLEOL) FWD(aft, bef, 1); break; case OEOL: if (ch == EOL || ch == BOLEOL) FWD(aft, bef, 1); break; case OBOW: if (ch == BOW) FWD(aft, bef, 1); break; case OEOW: if (ch == EOW) FWD(aft, bef, 1); break; case OANY: if (!NONCHAR(ch)) FWD(aft, bef, 1); break; case OANYOF: cs = &g->sets[OPND(s)]; if (!NONCHAR(ch) && CHIN(cs, ch)) FWD(aft, bef, 1); break; case OBACK_: /* ignored here */ case O_BACK: FWD(aft, aft, 1); break; case OPLUS_: /* forward, this is just an empty */ FWD(aft, aft, 1); break; case O_PLUS: /* both forward and back */ FWD(aft, aft, 1); i = ISSETBACK(aft, OPND(s)); BACK(aft, aft, OPND(s)); if (!i && ISSETBACK(aft, OPND(s))) { /* oho, must reconsider loop body */ pc -= OPND(s) + 1; INIT(here, pc); } break; case OQUEST_: /* two branches, both forward */ FWD(aft, aft, 1); FWD(aft, aft, OPND(s)); break; case O_QUEST: /* just an empty */ FWD(aft, aft, 1); break; case OLPAREN: /* not significant here */ case ORPAREN: FWD(aft, aft, 1); break; case OCH_: /* mark the first two branches */ FWD(aft, aft, 1); assert(OP(g->strip[pc+OPND(s)]) == OOR2); FWD(aft, aft, OPND(s)); break; case OOR1: /* done a branch, find the O_CH */ if (ISSTATEIN(aft, here)) { for (look = 1; OP(s = g->strip[pc+look]) != O_CH; look += OPND(s)) assert(OP(s) == OOR2); FWD(aft, aft, look); } break; case OOR2: /* propagate OCH_'s marking */ FWD(aft, aft, 1); if (OP(g->strip[pc+OPND(s)]) != O_CH) { assert(OP(g->strip[pc+OPND(s)]) == OOR2); FWD(aft, aft, OPND(s)); } break; case O_CH: /* just empty */ FWD(aft, aft, 1); break; default: /* ooooops... */ assert(nope); break; } } return(aft); } #ifdef REDEBUG /* - print - print a set of states == #ifdef REDEBUG == static void print(struct match *m, char *caption, states st, \ == int ch, FILE *d); == #endif */ static void print(m, caption, st, ch, d) struct match *m; char *caption; states st; int ch; FILE *d; { register struct re_guts *g = m->g; register int i; register int first = 1; if (!(m->eflags®_TRACE)) return; fprintf(d, "%s", caption); if (ch != '\0') fprintf(d, " %s", pchar(ch)); for (i = 0; i < g->nstates; i++) if (ISSET(st, i)) { fprintf(d, "%s%d", (first) ? "\t" : ", ", i); first = 0; } fprintf(d, "\n"); } /* - at - print current situation == #ifdef REDEBUG == static void at(struct match *m, char *title, char *start, char *stop, \ == sopno startst, sopno stopst); == #endif */ static void at(m, title, start, stop, startst, stopst) struct match *m; char *title; char *start; char *stop; sopno startst; sopno stopst; { if (!(m->eflags®_TRACE)) return; printf("%s %s-", title, pchar(*start)); printf("%s ", pchar(*stop)); printf("%ld-%ld\n", (long)startst, (long)stopst); } #ifndef PCHARDONE #define PCHARDONE /* never again */ /* - pchar - make a character printable == #ifdef REDEBUG == static char *pchar(int ch); == #endif * * Is this identical to regchar() over in debug.c? Well, yes. But a * duplicate here avoids having a debugging-capable regexec.o tied to * a matching debug.o, and this is convenient. It all disappears in * the non-debug compilation anyway, so it doesn't matter much. */ static char * /* -> representation */ pchar(ch) int ch; { static char pbuf[10]; if (isprint(ch) || ch == ' ') sprintf(pbuf, "%c", ch); else sprintf(pbuf, "\\%o", ch); return(pbuf); } #endif #endif #undef matcher #undef fast #undef slow #undef dissect #undef backref #undef step #undef print #undef at #undef match ippsample/vcnet/regex/debug.ih0000644000175000017500000000051113240604116015375 0ustar tilltill/* ========= begin header generated by ./mkh ========= */ #ifdef __cplusplus extern "C" { #endif /* === debug.c === */ void regprint(regex_t *r, FILE *d); static void s_print(register struct re_guts *g, FILE *d); static char *regchar(int ch); #ifdef __cplusplus } #endif /* ========= end header generated by ./mkh ========= */ ippsample/vcnet/regex/regex.h0000644000175000017500000000347413240604116015263 0ustar tilltill#ifndef _REGEX_H_ #define _REGEX_H_ /* never again */ /* ========= begin header generated by ./mkh ========= */ #ifdef __cplusplus extern "C" { #endif /* === regex2.h === */ typedef long regoff_t; typedef struct { int re_magic; size_t re_nsub; /* number of parenthesized subexpressions */ const char *re_endp; /* end pointer for REG_PEND */ struct re_guts *re_g; /* none of your business :-) */ } regex_t; typedef struct { regoff_t rm_so; /* start of match */ regoff_t rm_eo; /* end of match */ } regmatch_t; /* === regcomp.c === */ extern int regcomp(regex_t *, const char *, int); #define REG_BASIC 0000 #define REG_EXTENDED 0001 #define REG_ICASE 0002 #define REG_NOSUB 0004 #define REG_NEWLINE 0010 #define REG_NOSPEC 0020 #define REG_PEND 0040 #define REG_DUMP 0200 /* === regerror.c === */ #define REG_OKAY 0 #define REG_NOMATCH 1 #define REG_BADPAT 2 #define REG_ECOLLATE 3 #define REG_ECTYPE 4 #define REG_EESCAPE 5 #define REG_ESUBREG 6 #define REG_EBRACK 7 #define REG_EPAREN 8 #define REG_EBRACE 9 #define REG_BADBR 10 #define REG_ERANGE 11 #define REG_ESPACE 12 #define REG_BADRPT 13 #define REG_EMPTY 14 #define REG_ASSERT 15 #define REG_INVARG 16 #define REG_ATOI 255 /* convert name to number (!) */ #define REG_ITOA 0400 /* convert number to name (!) */ extern size_t regerror(int, const regex_t *, char *, size_t); /* === regexec.c === */ extern int regexec(const regex_t *, const char *, size_t, regmatch_t [], int); #define REG_NOTBOL 00001 #define REG_NOTEOL 00002 #define REG_STARTEND 00004 #define REG_TRACE 00400 /* tracing of execution */ #define REG_LARGE 01000 /* force large representation */ #define REG_BACKR 02000 /* force use of backref code */ /* === regfree.c === */ extern void regfree(regex_t *); #ifdef __cplusplus } #endif /* ========= end header generated by ./mkh ========= */ #endif ippsample/vcnet/regex/mkh0000644000175000017500000000344113240604116014474 0ustar tilltill#! /bin/sh # mkh - pull headers out of C source PATH=/bin:/usr/bin ; export PATH # egrep pattern to pick out marked lines egrep='^ =([ ]|$)' # Sed program to process marked lines into lines for the header file. # The markers have already been removed. Two things are done here: removal # of backslashed newlines, and some fudging of comments. The first is done # because -o needs to have prototypes on one line to strip them down. # Getting comments into the output is tricky; we turn C++-style // comments # into /* */ comments, after altering any existing */'s to avoid trouble. peel=' /\\$/N /\\\n[ ]*/s///g /\/\//s;\*/;* /;g /\/\//s;//\(.*\);/*\1 */;' for a do case "$a" in -o) # old (pre-function-prototype) compiler # add code to comment out argument lists peel="$peel "'/^\([^#\/][^\/]*[a-zA-Z0-9_)]\)(\(.*\))/s;;\1(/*\2*/);' shift ;; -b) # funny Berkeley __P macro peel="$peel "'/^\([^#\/][^\/]*[a-zA-Z0-9_)]\)(\(.*\))/s;;\1 __P((\2));' shift ;; -s) # compiler doesn't like `static foo();' # add code to get rid of the `static' peel="$peel "'/^static[ ][^\/]*[a-zA-Z0-9_)](.*)/s;static.;;' shift ;; -p) # private declarations egrep='^ ==([ ]|$)' shift ;; -i) # wrap in #ifndef, argument is name ifndef="$2" shift ; shift ;; *) break ;; esac done if test " $ifndef" != " " then echo "#ifndef $ifndef" echo "#define $ifndef /* never again */" fi echo "/* ========= begin header generated by $0 ========= */" echo '#ifdef __cplusplus' echo 'extern "C" {' echo '#endif' for f do echo echo "/* === $f === */" egrep "$egrep" $f | sed 's/^ ==*[ ]//;s/^ ==*$//' | sed "$peel" echo done echo '#ifdef __cplusplus' echo '}' echo '#endif' echo "/* ========= end header generated by $0 ========= */" if test " $ifndef" != " " then echo "#endif" fi exit 0 ippsample/vcnet/regex/regcomp.ih0000644000175000017500000000522613240604116015753 0ustar tilltill/* ========= begin header generated by ./mkh ========= */ #ifdef __cplusplus extern "C" { #endif /* === regcomp.c === */ static void p_ere(register struct parse *p, int stop); static void p_ere_exp(register struct parse *p); static void p_str(register struct parse *p); static void p_bre(register struct parse *p, register int end1, register int end2); static int p_simp_re(register struct parse *p, int starordinary); static int p_count(register struct parse *p); static void p_bracket(register struct parse *p); static void p_b_term(register struct parse *p, register cset *cs); static void p_b_cclass(register struct parse *p, register cset *cs); static void p_b_eclass(register struct parse *p, register cset *cs); static char p_b_symbol(register struct parse *p); static char p_b_coll_elem(register struct parse *p, int endc); static char othercase(int ch); static void bothcases(register struct parse *p, int ch); static void ordinary(register struct parse *p, register int ch); static void nonnewline(register struct parse *p); static void repeat(register struct parse *p, sopno start, int from, int to); static int seterr(register struct parse *p, int e); static cset *allocset(register struct parse *p); static void freeset(register struct parse *p, register cset *cs); static int freezeset(register struct parse *p, register cset *cs); static int firstch(register struct parse *p, register cset *cs); static int nch(register struct parse *p, register cset *cs); static void mcadd(register struct parse *p, register cset *cs, register char *cp); static void mcsub(register cset *cs, register char *cp); static int mcin(register cset *cs, register char *cp); static char *mcfind(register cset *cs, register char *cp); static void mcinvert(register struct parse *p, register cset *cs); static void mccase(register struct parse *p, register cset *cs); static int isinsets(register struct re_guts *g, int c); static int samesets(register struct re_guts *g, int c1, int c2); static void categorize(struct parse *p, register struct re_guts *g); static sopno dupl(register struct parse *p, sopno start, sopno finish); static void doemit(register struct parse *p, sop op, size_t opnd); static void doinsert(register struct parse *p, sop op, size_t opnd, sopno pos); static void dofwd(register struct parse *p, sopno pos, sop value); static void enlarge(register struct parse *p, sopno size); static void stripsnug(register struct parse *p, register struct re_guts *g); static void findmust(register struct parse *p, register struct re_guts *g); static sopno pluscount(register struct parse *p, register struct re_guts *g); #ifdef __cplusplus } #endif /* ========= end header generated by ./mkh ========= */ ippsample/vcnet/regex/regex.30000644000175000017500000003515113240604116015173 0ustar tilltill.TH REGEX 3 "25 Sept 1997" .BY "Henry Spencer" .de ZR .\" one other place knows this name: the SEE ALSO section .IR regex (7) \\$1 .. .SH NAME regcomp, regexec, regerror, regfree \- regular-expression library .SH SYNOPSIS .ft B .\".na #include .br #include .HP 10 int regcomp(regex_t\ *preg, const\ char\ *pattern, int\ cflags); .HP int\ regexec(const\ regex_t\ *preg, const\ char\ *string, size_t\ nmatch, regmatch_t\ pmatch[], int\ eflags); .HP size_t\ regerror(int\ errcode, const\ regex_t\ *preg, char\ *errbuf, size_t\ errbuf_size); .HP void\ regfree(regex_t\ *preg); .\".ad .ft .SH DESCRIPTION These routines implement POSIX 1003.2 regular expressions (``RE''s); see .ZR . .I Regcomp compiles an RE written as a string into an internal form, .I regexec matches that internal form against a string and reports results, .I regerror transforms error codes from either into human-readable messages, and .I regfree frees any dynamically-allocated storage used by the internal form of an RE. .PP The header .I declares two structure types, .I regex_t and .IR regmatch_t , the former for compiled internal forms and the latter for match reporting. It also declares the four functions, a type .IR regoff_t , and a number of constants with names starting with ``REG_''. .PP .I Regcomp compiles the regular expression contained in the .I pattern string, subject to the flags in .IR cflags , and places the results in the .I regex_t structure pointed to by .IR preg . .I Cflags is the bitwise OR of zero or more of the following flags: .IP REG_EXTENDED \w'REG_EXTENDED'u+2n Compile modern (``extended'') REs, rather than the obsolete (``basic'') REs that are the default. .IP REG_BASIC This is a synonym for 0, provided as a counterpart to REG_EXTENDED to improve readability. This is an extension, compatible with but not specified by POSIX 1003.2, and should be used with caution in software intended to be portable to other systems. .IP REG_NOSPEC Compile with recognition of all special characters turned off. All characters are thus considered ordinary, so the ``RE'' is a literal string. This is an extension, compatible with but not specified by POSIX 1003.2, and should be used with caution in software intended to be portable to other systems. REG_EXTENDED and REG_NOSPEC may not be used in the same call to .IR regcomp . .IP REG_ICASE Compile for matching that ignores upper/lower case distinctions. See .ZR . .IP REG_NOSUB Compile for matching that need only report success or failure, not what was matched. .IP REG_NEWLINE Compile for newline-sensitive matching. By default, newline is a completely ordinary character with no special meaning in either REs or strings. With this flag, `[^' bracket expressions and `.' never match newline, a `^' anchor matches the null string after any newline in the string in addition to its normal function, and the `$' anchor matches the null string before any newline in the string in addition to its normal function. .IP REG_PEND The regular expression ends, not at the first NUL, but just before the character pointed to by the .I re_endp member of the structure pointed to by .IR preg . The .I re_endp member is of type .IR const\ char\ * . This flag permits inclusion of NULs in the RE; they are considered ordinary characters. This is an extension, compatible with but not specified by POSIX 1003.2, and should be used with caution in software intended to be portable to other systems. .PP When successful, .I regcomp returns 0 and fills in the structure pointed to by .IR preg . One member of that structure (other than .IR re_endp ) is publicized: .IR re_nsub , of type .IR size_t , contains the number of parenthesized subexpressions within the RE (except that the value of this member is undefined if the REG_NOSUB flag was used). If .I regcomp fails, it returns a non-zero error code; see DIAGNOSTICS. .PP .I Regexec matches the compiled RE pointed to by .I preg against the .IR string , subject to the flags in .IR eflags , and reports results using .IR nmatch , .IR pmatch , and the returned value. The RE must have been compiled by a previous invocation of .IR regcomp . The compiled form is not altered during execution of .IR regexec , so a single compiled RE can be used simultaneously by multiple threads. .PP By default, the NUL-terminated string pointed to by .I string is considered to be the text of an entire line, with the NUL indicating the end of the line. (That is, any other end-of-line marker is considered to have been removed and replaced by the NUL.) The .I eflags argument is the bitwise OR of zero or more of the following flags: .IP REG_NOTBOL \w'REG_STARTEND'u+2n The first character of the string is not the beginning of a line, so the `^' anchor should not match before it. This does not affect the behavior of newlines under REG_NEWLINE. .IP REG_NOTEOL The NUL terminating the string does not end a line, so the `$' anchor should not match before it. This does not affect the behavior of newlines under REG_NEWLINE. .IP REG_STARTEND The string is considered to start at \fIstring\fR\ + \fIpmatch\fR[0].\fIrm_so\fR and to have a terminating NUL located at \fIstring\fR\ + \fIpmatch\fR[0].\fIrm_eo\fR (there need not actually be a NUL at that location), regardless of the value of .IR nmatch . See below for the definition of .IR pmatch and .IR nmatch . This is an extension, compatible with but not specified by POSIX 1003.2, and should be used with caution in software intended to be portable to other systems. Note that a non-zero \fIrm_so\fR does not imply REG_NOTBOL; REG_STARTEND affects only the location of the string, not how it is matched. .PP See .ZR for a discussion of what is matched in situations where an RE or a portion thereof could match any of several substrings of .IR string . .PP Normally, .I regexec returns 0 for success and the non-zero code REG_NOMATCH for failure. Other non-zero error codes may be returned in exceptional situations; see DIAGNOSTICS. .PP If REG_NOSUB was specified in the compilation of the RE, or if .I nmatch is 0, .I regexec ignores the .I pmatch argument (but see below for the case where REG_STARTEND is specified). Otherwise, .I pmatch points to an array of .I nmatch structures of type .IR regmatch_t . Such a structure has at least the members .I rm_so and .IR rm_eo , both of type .I regoff_t (a signed arithmetic type at least as large as an .I off_t and a .IR ssize_t ), containing respectively the offset of the first character of a substring and the offset of the first character after the end of the substring. Offsets are measured from the beginning of the .I string argument given to .IR regexec . An empty substring is denoted by equal offsets, both indicating the character following the empty substring. .PP The 0th member of the .I pmatch array is filled in to indicate what substring of .I string was matched by the entire RE. Remaining members report what substring was matched by parenthesized subexpressions within the RE; member .I i reports subexpression .IR i , with subexpressions counted (starting at 1) by the order of their opening parentheses in the RE, left to right. Unused entries in the array\(emcorresponding either to subexpressions that did not participate in the match at all, or to subexpressions that do not exist in the RE (that is, \fIi\fR\ > \fIpreg\fR\->\fIre_nsub\fR)\(emhave both .I rm_so and .I rm_eo set to \-1. If a subexpression participated in the match several times, the reported substring is the last one it matched. (Note, as an example in particular, that when the RE `(b*)+' matches `bbb', the parenthesized subexpression matches the three `b's and then an infinite number of empty strings following the last `b', so the reported substring is one of the empties.) .PP If REG_STARTEND is specified, .I pmatch must point to at least one .I regmatch_t (even if .I nmatch is 0 or REG_NOSUB was specified), to hold the input offsets for REG_STARTEND. Use for output is still entirely controlled by .IR nmatch ; if .I nmatch is 0 or REG_NOSUB was specified, the value of .IR pmatch [0] will not be changed by a successful .IR regexec . .PP .I Regerror maps a non-zero .I errcode from either .I regcomp or .I regexec to a human-readable, printable message. If .I preg is non-NULL, the error code should have arisen from use of the .I regex_t pointed to by .IR preg , and if the error code came from .IR regcomp , it should have been the result from the most recent .I regcomp using that .IR regex_t . .RI ( Regerror may be able to supply a more detailed message using information from the .IR regex_t .) .I Regerror places the NUL-terminated message into the buffer pointed to by .IR errbuf , limiting the length (including the NUL) to at most .I errbuf_size bytes. If the whole message won't fit, as much of it as will fit before the terminating NUL is supplied. In any case, the returned value is the size of buffer needed to hold the whole message (including terminating NUL). If .I errbuf_size is 0, .I errbuf is ignored but the return value is still correct. .PP If the .I errcode given to .I regerror is first ORed with REG_ITOA, the ``message'' that results is the printable name of the error code, e.g. ``REG_NOMATCH'', rather than an explanation thereof. If .I errcode is REG_ATOI, then .I preg shall be non-NULL and the .I re_endp member of the structure it points to must point to the printable name of an error code; in this case, the result in .I errbuf is the decimal digits of the numeric value of the error code (0 if the name is not recognized). REG_ITOA and REG_ATOI are intended primarily as debugging facilities; they are extensions, compatible with but not specified by POSIX 1003.2, and should be used with caution in software intended to be portable to other systems. Be warned also that they are considered experimental and changes are possible. .PP .I Regfree frees any dynamically-allocated storage associated with the compiled RE pointed to by .IR preg . The remaining .I regex_t is no longer a valid compiled RE and the effect of supplying it to .I regexec or .I regerror is undefined. .PP None of these functions references global variables except for tables of constants; all are safe for use from multiple threads if the arguments are safe. .SH IMPLEMENTATION CHOICES There are a number of decisions that 1003.2 leaves up to the implementor, either by explicitly saying ``undefined'' or by virtue of them being forbidden by the RE grammar. This implementation treats them as follows. .PP See .ZR for a discussion of the definition of case-independent matching. .PP There is no particular limit on the length of REs, except insofar as memory is limited. Memory usage is approximately linear in RE size, and largely insensitive to RE complexity, except for bounded repetitions. See BUGS for one short RE using them that will run almost any system out of memory. .PP A backslashed character other than one specifically given a magic meaning by 1003.2 (such magic meanings occur only in obsolete [``basic''] REs) is taken as an ordinary character. .PP Any unmatched [ is a REG_EBRACK error. .PP Equivalence classes cannot begin or end bracket-expression ranges. The endpoint of one range cannot begin another. .PP RE_DUP_MAX, the limit on repetition counts in bounded repetitions, is 255. .PP A repetition operator (?, *, +, or bounds) cannot follow another repetition operator. A repetition operator cannot begin an expression or subexpression or follow `^' or `|'. .PP `|' cannot appear first or last in a (sub)expression or after another `|', i.e. an operand of `|' cannot be an empty subexpression. An empty parenthesized subexpression, `()', is legal and matches an empty (sub)string. An empty string is not a legal RE. .PP A `{' followed by a digit is considered the beginning of bounds for a bounded repetition, which must then follow the syntax for bounds. A `{' \fInot\fR followed by a digit is considered an ordinary character. .PP `^' and `$' beginning and ending subexpressions in obsolete (``basic'') REs are anchors, not ordinary characters. .SH SEE ALSO grep(1), regex(7) .PP POSIX 1003.2, sections 2.8 (Regular Expression Notation) and B.5 (C Binding for Regular Expression Matching). .SH DIAGNOSTICS Non-zero error codes from .I regcomp and .I regexec include the following: .PP .nf .ta \w'REG_ECOLLATE'u+3n REG_NOMATCH regexec() failed to match REG_BADPAT invalid regular expression REG_ECOLLATE invalid collating element REG_ECTYPE invalid character class REG_EESCAPE \e applied to unescapable character REG_ESUBREG invalid backreference number REG_EBRACK brackets [ ] not balanced REG_EPAREN parentheses ( ) not balanced REG_EBRACE braces { } not balanced REG_BADBR invalid repetition count(s) in { } REG_ERANGE invalid character range in [ ] REG_ESPACE ran out of memory REG_BADRPT ?, *, or + operand invalid REG_EMPTY empty (sub)expression REG_ASSERT ``can't happen''\(emyou found a bug REG_INVARG invalid argument, e.g. negative-length string .fi .SH HISTORY Written by Henry Spencer, henry@zoo.toronto.edu. .SH BUGS This is an alpha release with known defects. Please report problems. .PP There is one known functionality bug. The implementation of internationalization is incomplete: the locale is always assumed to be the default one of 1003.2, and only the collating elements etc. of that locale are available. .PP The back-reference code is subtle and doubts linger about its correctness in complex cases. .PP .I Regexec performance is poor. This will improve with later releases. .I Nmatch exceeding 0 is expensive; .I nmatch exceeding 1 is worse. .I Regexec is largely insensitive to RE complexity \fIexcept\fR that back references are massively expensive. RE length does matter; in particular, there is a strong speed bonus for keeping RE length under about 30 characters, with most special characters counting roughly double. .PP .I Regcomp implements bounded repetitions by macro expansion, which is costly in time and space if counts are large or bounded repetitions are nested. An RE like, say, `((((a{1,100}){1,100}){1,100}){1,100}){1,100}' will (eventually) run almost any existing machine out of swap space. .PP There are suspected problems with response to obscure error conditions. Notably, certain kinds of internal overflow, produced only by truly enormous REs or by multiply nested bounded repetitions, are probably not handled well. .PP Due to a mistake in 1003.2, things like `a)b' are legal REs because `)' is a special character only in the presence of a previous unmatched `('. This can't be fixed until the spec is fixed. .PP The standard's definition of back references is vague. For example, does `a\e(\e(b\e)*\e2\e)*d' match `abbbd'? Until the standard is clarified, behavior in such cases should not be relied on. .PP The implementation of word-boundary matching is a bit of a kludge, and bugs may lurk in combinations of word-boundary matching and anchoring. ippsample/vcnet/ippserver.vcxproj0000644000175000017500000002360013240604116016313 0ustar tilltill Debug Win32 Debug x64 Release Win32 Release x64 {82A03BC7-0746-4B85-8908-3C7A3FAA58A9} ippserver Win32Proj Application v120 Unicode true Application v120 Unicode Application v120 Unicode true Application v120 Unicode <_ProjectFileVersion>12.0.30501.0 $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ true $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ true $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ false $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ false Disabled ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level1 EditAndContinue dnssd.lib;ws2_32.lib;%(AdditionalDependencies) true Console false MachineX86 X64 Disabled ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level1 ProgramDatabase dnssd.lib;ws2_32.lib;%(AdditionalDependencies) true Console false MachineX64 ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) MultiThreadedDLL Level1 ProgramDatabase dnssd.lib;ws2_32.lib;%(AdditionalDependencies) true Console true true false MachineX86 signtool sign /n "IEEE INDUSTRY STANDARDS AND TECHNOLOGY ORGANIZATION" $(TargetPath) Sign code with IEEE-ISTO certificate X64 ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) MultiThreadedDLL Level1 ProgramDatabase dnssd.lib;ws2_32.lib;%(AdditionalDependencies) true Console true true false MachineX64 signtool sign /n "IEEE INDUSTRY STANDARDS AND TECHNOLOGY ORGANIZATION" $(TargetPath) Sign code with IEEE-ISTO certificate {cb4aa6f2-3e84-45be-b505-95cd375e8be3} false ippsample/vcnet/regex.vcxproj.filters0000644000175000017500000000314313240604116017055 0ustar tilltill {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav Source Files Source Files Source Files Source Files Source Files Source Files Header Files Header Files ippsample/vcnet/ipptool.vcxproj.filters0000644000175000017500000000164113240604116017432 0ustar tilltill {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav Source Files ippsample/vcnet/libcups2.vcxproj0000644000175000017500000006740313240604116016030 0ustar tilltill Debug Win32 Debug x64 Release Win32 Release x64 {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} libcups2 Win32Proj DynamicLibrary v120 MultiByte DynamicLibrary v120 MultiByte DynamicLibrary v120 MultiByte DynamicLibrary v120 MultiByte <_ProjectFileVersion>12.0.30501.0 $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ true $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ true $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ false $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ false Disabled ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) ZLIB_WINAPI;WIN32;DEBUG;_DEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL true Level3 EditAndContinue /NODEFAULTLIB:libcmt %(AdditionalOptions) ws2_32.lib;advapi32.lib;zlibwapi.lib;%(AdditionalDependencies) $(OutDir)libcups2.dll ..\cups\libcups2.def true $(Platform)\$(Configuration)\libcups2.pdb Windows false $(OutDir)libcups2.lib MachineX86 X64 Disabled ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) ZLIB_WINAPI;WIN32;DEBUG;_DEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL true Level3 ProgramDatabase ws2_32.lib;advapi32.lib;zlibwapi.lib;%(AdditionalDependencies) $(OutDir)libcups2.dll ..\cups\libcups2.def true $(Platform)\$(Configuration)\libcups2.pdb Windows $(OutDir)libcups2.lib MachineX64 MinSpace ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) ZLIB_WINAPI;WIN32;DEBUG;NDEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL Level3 ProgramDatabase /NODEFAULTLIB:libcmt %(AdditionalOptions) ws2_32.lib;advapi32.lib;zlibwapi.lib;%(AdditionalDependencies) $(OutDir)libcups2.dll ..\cups\libcups2.def true libcups2.pdb Windows true true false $(OutDir)libcups2.lib MachineX86 signtool sign /n "IEEE INDUSTRY STANDARDS AND TECHNOLOGY ORGANIZATION" $(TargetPath) Sign code with IEEE-ISTO cert. X64 MinSpace ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) ZLIB_WINAPI;WIN32;DEBUG;NDEBUG;_WINDOWS;_USRDLL;LIBCUPS2_EXPORTS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL Level3 ProgramDatabase ws2_32.lib;advapi32.lib;zlibwapi.lib;%(AdditionalDependencies) $(OutDir)libcups2.dll ..\cups\libcups2.def true libcups2.pdb Windows true true $(OutDir)libcups2.lib MachineX64 signtool sign /n "IEEE INDUSTRY STANDARDS AND TECHNOLOGY ORGANIZATION" $(TargetPath) Sign code with IEEE-ISTO cert. WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) WIN32;%(PreprocessorDefinitions) {18950a1b-d37a-40c7-b2df-c12986c0526e} false ippsample/vcnet/ippsample-installer.vdproj0000644000175000017500000022171013240604116020074 0ustar tilltill"DeployProject" { "VSVersion" = "3:800" "ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}" "IsWebType" = "8:FALSE" "ProjectName" = "8:ipptool-installer" "LanguageId" = "3:1033" "CodePage" = "3:1252" "UILanguageId" = "3:1033" "SccProjectName" = "8:" "SccLocalPath" = "8:" "SccAuxPath" = "8:" "SccProvider" = "8:" "Hierarchy" { "Entry" { "MsmKey" = "8:_009DC3ED78164048934ED35E89A0A1C5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1A1324305D78463BBFC62269C56DCF0B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1DBDCFABB8DF28E5F75E41EDAE4BF6BE" "OwnerKey" = "8:_EA282F32A10B4ED1A81AA6133B997C6A" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1E4B2A9BD6A44926B719E0D7E8FC0952" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_290B9B52C4784AED94FA6B87CAB18D10" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_40C483299484486C9416B704F0EF4A6C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_41260853156249FDB39A8E386F935492" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_425F2537D86148B9A4233AD27D426738" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4273A45FE6E54897AC9A4F66D9AA59EC" "OwnerKey" = "8:_8A6033CAC27E4C1185B4FDF7D2BF8D2E" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4454D1BB58774F95972FB94388DC5E6A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_46AB64FF360D4F309866FF5F49C65D88" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_531A281ACDC6420D918E2A9FE97A2D42" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_58DC0E72F0944BEFB927AED718CD1660" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_592FC984DBFD494D9FB7DFFEA35AD7A5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_65CBD149C9DA448FBACE2B02766A6537" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6F893B2A3B7048CBA39359FC368BCA27" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_80DBA85C961E447CB92C95CE1F38C56B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_842C04D73EBC4F5DBC2FD58D5B98D5D1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8A6033CAC27E4C1185B4FDF7D2BF8D2E" "OwnerKey" = "8:_58DC0E72F0944BEFB927AED718CD1660" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8A6033CAC27E4C1185B4FDF7D2BF8D2E" "OwnerKey" = "8:_EA282F32A10B4ED1A81AA6133B997C6A" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8A6033CAC27E4C1185B4FDF7D2BF8D2E" "OwnerKey" = "8:_E97571D3FBE048DABDC59B37762D800F" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8A6033CAC27E4C1185B4FDF7D2BF8D2E" "OwnerKey" = "8:_D02EB13951314EFD9C539150EF8E53B8" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8AC6B9D7EF6B4C7A8C7B5AD85AA397C3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8CC3562BCDED4676A672115D19D898B5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9314DE98517C42E9AF190B67472408DF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9967519E7058965D4C7DEF47EB39CC50" "OwnerKey" = "8:_EA282F32A10B4ED1A81AA6133B997C6A" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9FBF78D7B89EEA843380D5F10E1954D7" "OwnerKey" = "8:_EA282F32A10B4ED1A81AA6133B997C6A" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A63C5C4108AB4B588878482B26876DC5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_AF057921D20E4520A3C6420F0729A744" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B85BD013DC024B9E82862535191B405B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B9E79062FEF64745915546DDD5BF8D85" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BD5B70C103EF41D9A30CF249D2B93CEB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C430646D6E7C4CBDA84F951AE95EB76F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D02EB13951314EFD9C539150EF8E53B8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D4BEA026ABFB46DD960AD8EFCAE45E31" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D5CD9D9AB1644688A1D54B1589BDF724" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E30823E684384F4DB7385B14F714AD95" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E3C6C5A7FDD94965B68960844461D5EA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E4C0F67094B94E05AB69787080727089" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E50F2FB950DD47D993DC8FB577266549" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E7DD6A8D195B4752B0525628FF9586E4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E97571D3FBE048DABDC59B37762D800F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E9CA670571B5447682529CDB7BC3C100" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_EA282F32A10B4ED1A81AA6133B997C6A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_EA9CE1B09EF1442BAA3C3F5AE7865ABF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_EC7FE3265BDB4C52B5B87A8AC56AFDDD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F16FA7F9826E461E955A95B2EEABA975" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F22F5380A6E14A43A15A452C7C6F6C07" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } } "Configurations" { "Debug" { "DisplayName" = "8:Debug" "IsDebugOnly" = "11:TRUE" "IsReleaseOnly" = "11:FALSE" "OutputFilename" = "8:ipptool-windows.msi" "PackageFilesAs" = "3:2" "PackageFileSize" = "3:-2147483648" "CabType" = "3:1" "Compression" = "3:3" "SignOutput" = "11:FALSE" "CertificateFile" = "8:" "PrivateKeyFile" = "8:" "TimeStampServer" = "8:" "InstallerBootstrapper" = "3:2" "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" { "Enabled" = "11:TRUE" "PromptEnabled" = "11:TRUE" "PrerequisitesLocation" = "2:1" "Url" = "8:" "ComponentsUrl" = "8:" "Items" { "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.Net.Framework.3.5.SP1" { "Name" = "8:.NET Framework 3.5 SP1" "ProductCode" = "8:Microsoft.Net.Framework.3.5.SP1" } "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.Windows.Installer.3.1" { "Name" = "8:Windows Installer 3.1" "ProductCode" = "8:Microsoft.Windows.Installer.3.1" } } } } "Release" { "DisplayName" = "8:Release" "IsDebugOnly" = "11:FALSE" "IsReleaseOnly" = "11:TRUE" "OutputFilename" = "8:ipptool-windows.msi" "PackageFilesAs" = "3:2" "PackageFileSize" = "3:-2147483648" "CabType" = "3:1" "Compression" = "3:3" "SignOutput" = "11:FALSE" "CertificateFile" = "8:" "PrivateKeyFile" = "8:" "TimeStampServer" = "8:" "InstallerBootstrapper" = "3:2" "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" { "Enabled" = "11:TRUE" "PromptEnabled" = "11:TRUE" "PrerequisitesLocation" = "2:1" "Url" = "8:" "ComponentsUrl" = "8:" "Items" { "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.Net.Framework.3.5.SP1" { "Name" = "8:.NET Framework 3.5 SP1" "ProductCode" = "8:Microsoft.Net.Framework.3.5.SP1" } "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:Microsoft.Windows.Installer.3.1" { "Name" = "8:Windows Installer 3.1" "ProductCode" = "8:Microsoft.Windows.Installer.3.1" } } } } } "Deployable" { "CustomAction" { } "DefaultFeature" { "Name" = "8:DefaultFeature" "Title" = "8:" "Description" = "8:" } "ExternalPersistence" { "LaunchCondition" { } } "File" { "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_009DC3ED78164048934ED35E89A0A1C5" { "SourcePath" = "8:..\\test\\document-a4.ps" "TargetName" = "8:document-a4.ps" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1A1324305D78463BBFC62269C56DCF0B" { "SourcePath" = "8:..\\doc\\help\\man-ipptoolfile.html" "TargetName" = "8:man-ipptoolfile.html" "Tag" = "8:" "Folder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1DBDCFABB8DF28E5F75E41EDAE4BF6BE" { "SourcePath" = "8:zlibwapi.dll" "TargetName" = "8:zlibwapi.dll" "Tag" = "8:" "Folder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1E4B2A9BD6A44926B719E0D7E8FC0952" { "SourcePath" = "8:..\\test\\get-printer-attributes.test" "TargetName" = "8:get-printer-attributes.test" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_290B9B52C4784AED94FA6B87CAB18D10" { "SourcePath" = "8:..\\test\\print-job.test" "TargetName" = "8:print-job.test" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_40C483299484486C9416B704F0EF4A6C" { "SourcePath" = "8:..\\test\\testfile.pdf" "TargetName" = "8:testfile.pdf" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_41260853156249FDB39A8E386F935492" { "SourcePath" = "8:..\\test\\ipp-1.1.test" "TargetName" = "8:ipp-1.1.test" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_425F2537D86148B9A4233AD27D426738" { "SourcePath" = "8:..\\test\\ipp-2.0.test" "TargetName" = "8:ipp-2.0.test" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4454D1BB58774F95972FB94388DC5E6A" { "SourcePath" = "8:..\\test\\print-job-deflate.test" "TargetName" = "8:print-job-deflate.test" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_46AB64FF360D4F309866FF5F49C65D88" { "SourcePath" = "8:..\\test\\ipp-everywhere.test" "TargetName" = "8:ipp-everywhere.test" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_531A281ACDC6420D918E2A9FE97A2D42" { "SourcePath" = "8:..\\test\\get-notifications.test" "TargetName" = "8:get-notifications.test" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_592FC984DBFD494D9FB7DFFEA35AD7A5" { "SourcePath" = "8:..\\doc\\help\\man-ippfind.html" "TargetName" = "8:man-ippfind.html" "Tag" = "8:" "Folder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_65CBD149C9DA448FBACE2B02766A6537" { "SourcePath" = "8:..\\test\\testfile.ps" "TargetName" = "8:testfile.ps" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6F893B2A3B7048CBA39359FC368BCA27" { "SourcePath" = "8:..\\test\\onepage-letter.ps" "TargetName" = "8:onepage-letter.ps" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_80DBA85C961E447CB92C95CE1F38C56B" { "SourcePath" = "8:..\\test\\ipp-2.2.test" "TargetName" = "8:ipp-2.2.test" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_842C04D73EBC4F5DBC2FD58D5B98D5D1" { "SourcePath" = "8:..\\test\\document-a4.pdf" "TargetName" = "8:document-a4.pdf" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8AC6B9D7EF6B4C7A8C7B5AD85AA397C3" { "SourcePath" = "8:..\\test\\get-jobs.test" "TargetName" = "8:get-jobs.test" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8CC3562BCDED4676A672115D19D898B5" { "SourcePath" = "8:..\\test\\testfile.jpg" "TargetName" = "8:testfile.jpg" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9314DE98517C42E9AF190B67472408DF" { "SourcePath" = "8:..\\test\\get-subscriptions.test" "TargetName" = "8:get-subscriptions.test" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9967519E7058965D4C7DEF47EB39CC50" { "SourcePath" = "8:CRYPT32.dll" "TargetName" = "8:CRYPT32.dll" "Tag" = "8:" "Folder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9FBF78D7B89EEA843380D5F10E1954D7" { "SourcePath" = "8:Secur32.dll" "TargetName" = "8:Secur32.dll" "Tag" = "8:" "Folder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A63C5C4108AB4B588878482B26876DC5" { "SourcePath" = "8:..\\test\\validate-job.test" "TargetName" = "8:validate-job.test" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_AF057921D20E4520A3C6420F0729A744" { "SourcePath" = "8:..\\IPPTOOL.txt" "TargetName" = "8:IPPTOOL.txt" "Tag" = "8:" "Folder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B85BD013DC024B9E82862535191B405B" { "SourcePath" = "8:..\\test\\print-job-gzip.test" "TargetName" = "8:print-job-gzip.test" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B9E79062FEF64745915546DDD5BF8D85" { "SourcePath" = "8:..\\CHANGES-IPPTOOL.txt" "TargetName" = "8:CHANGES-IPPTOOL.txt" "Tag" = "8:" "Folder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BD5B70C103EF41D9A30CF249D2B93CEB" { "SourcePath" = "8:setdebug.bat" "TargetName" = "8:setdebug.bat" "Tag" = "8:" "Folder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C430646D6E7C4CBDA84F951AE95EB76F" { "SourcePath" = "8:..\\test\\color.jpg" "TargetName" = "8:color.jpg" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D4BEA026ABFB46DD960AD8EFCAE45E31" { "SourcePath" = "8:..\\test\\onepage-letter.pdf" "TargetName" = "8:onepage-letter.pdf" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D5CD9D9AB1644688A1D54B1589BDF724" { "SourcePath" = "8:..\\doc\\help\\man-ipptool.html" "TargetName" = "8:man-ipptool.html" "Tag" = "8:" "Folder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E30823E684384F4DB7385B14F714AD95" { "SourcePath" = "8:..\\test\\ipp-2.1.test" "TargetName" = "8:ipp-2.1.test" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E3C6C5A7FDD94965B68960844461D5EA" { "SourcePath" = "8:..\\LICENSE.txt" "TargetName" = "8:LICENSE.txt" "Tag" = "8:" "Folder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E4C0F67094B94E05AB69787080727089" { "SourcePath" = "8:..\\test\\create-printer-subscription.test" "TargetName" = "8:create-printer-subscription.test" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E50F2FB950DD47D993DC8FB577266549" { "SourcePath" = "8:..\\test\\document-letter.ps" "TargetName" = "8:document-letter.ps" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E7DD6A8D195B4752B0525628FF9586E4" { "SourcePath" = "8:..\\test\\onepage-a4.ps" "TargetName" = "8:onepage-a4.ps" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E9CA670571B5447682529CDB7BC3C100" { "SourcePath" = "8:..\\test\\gray.jpg" "TargetName" = "8:gray.jpg" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_EA9CE1B09EF1442BAA3C3F5AE7865ABF" { "SourcePath" = "8:..\\test\\testfile.txt" "TargetName" = "8:testfile.txt" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_EC7FE3265BDB4C52B5B87A8AC56AFDDD" { "SourcePath" = "8:..\\test\\get-completed-jobs.test" "TargetName" = "8:get-completed-jobs.test" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F16FA7F9826E461E955A95B2EEABA975" { "SourcePath" = "8:..\\test\\onepage-a4.pdf" "TargetName" = "8:onepage-a4.pdf" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F22F5380A6E14A43A15A452C7C6F6C07" { "SourcePath" = "8:..\\test\\document-letter.pdf" "TargetName" = "8:document-letter.pdf" "Tag" = "8:" "Folder" = "8:_EB00D0298C7E441EBD0257AC04FB3560" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } } "FileType" { } "Folder" { "{1525181F-901A-416C-8A58-119130FE478E}:_BEC0EAE20C954C78B294B83E6696156E" { "Name" = "8:#1919" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:ProgramMenuFolder" "Folders" { "{9EF0B969-E518-4E46-987F-47570745A589}:_E379D4EDBAD0460BB876711E9062ADB4" { "Name" = "8:ipptool" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_D115D2F4F12143B09D5FDA447A6A7D04" "Folders" { } } } } "{1525181F-901A-416C-8A58-119130FE478E}:_D02CDADE99F344CF92CA1A8D0278861F" { "Name" = "8:#1916" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:DesktopFolder" "Folders" { } } "{3C67513D-01DD-4637-8A68-80971EB9504F}:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" { "DefaultLocation" = "8:[ProgramFilesFolder]\\ipptool" "Name" = "8:#1925" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:TARGETDIR" "Folders" { "{9EF0B969-E518-4E46-987F-47570745A589}:_EB00D0298C7E441EBD0257AC04FB3560" { "Name" = "8:ipptool" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_6F223FB51798428A9F2D64A5A7F2B49C" "Folders" { } } } } } "LaunchCondition" { } "Locator" { } "MsiBootstrapper" { "LangId" = "3:1033" "RequiresElevation" = "11:FALSE" } "Product" { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:ipptool for Windows" "ProductCode" = "8:{5B0420A3-BD82-4698-B8A1-9D9EC51A7836}" "PackageCode" = "8:{ECECE842-1E95-48BD-962D-A4E62FBB5F89}" "UpgradeCode" = "8:{BAB6EBBB-515D-4155-9FEF-D98DA76814CA}" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:TRUE" "DetectNewerInstalledVersion" = "11:TRUE" "InstallAllUsers" = "11:TRUE" "ProductVersion" = "8:13.07.3100" "Manufacturer" = "8:Apple Inc." "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:http://www.cups.org/str.php" "Title" = "8:ipptool" "Subject" = "8:" "ARPCONTACT" = "8:Apple Inc." "Keywords" = "8:IPP, Internet Printing Protocol" "ARPCOMMENTS" = "8:ipptool for Windows" "ARPURLINFOABOUT" = "8:http://www.cups.org/" "ARPPRODUCTICON" = "8:" "ARPIconIndex" = "3:0" "SearchPath" = "8:" "UseSystemSearchPath" = "11:TRUE" "TargetPlatform" = "3:0" "PreBuildEvent" = "8:" "PostBuildEvent" = "8:" "RunPostBuildEvent" = "3:0" } "Registry" { "HKLM" { "Keys" { "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_BC4E66686BCA4F9A8B24B6CF2728DACD" { "Name" = "8:Software" "Condition" = "8:" "AlwaysCreate" = "11:FALSE" "DeleteAtUninstall" = "11:FALSE" "Transitive" = "11:FALSE" "Keys" { "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_F9AB9B310C7545D993D690F529048AA2" { "Name" = "8:cups.org" "Condition" = "8:" "AlwaysCreate" = "11:FALSE" "DeleteAtUninstall" = "11:FALSE" "Transitive" = "11:FALSE" "Keys" { } "Values" { "{ADCFDA98-8FDD-45E4-90BC-E3D20B029870}:_4E5BAC705A1D44E78C90C6D2A4A7BE20" { "Name" = "8:installdir" "Condition" = "8:" "Transitive" = "11:FALSE" "ValueTypes" = "3:2" "Value" = "8:[TARGETDIR]" } } } } "Values" { } } } } "HKCU" { "Keys" { "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_A4C9879F42874B6B92960A55F2D98922" { "Name" = "8:Software" "Condition" = "8:" "AlwaysCreate" = "11:FALSE" "DeleteAtUninstall" = "11:FALSE" "Transitive" = "11:FALSE" "Keys" { "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_1ACB03C307FB4B85BB27C9913FB58B09" { "Name" = "8:[Manufacturer]" "Condition" = "8:" "AlwaysCreate" = "11:FALSE" "DeleteAtUninstall" = "11:FALSE" "Transitive" = "11:FALSE" "Keys" { } "Values" { } } } "Values" { } } } } "HKCR" { "Keys" { } } "HKU" { "Keys" { } } "HKPU" { "Keys" { } } } "Sequences" { } "Shortcut" { "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_63715171338D40FFBC5B47A1418B4814" { "Name" = "8:README" "Arguments" = "8:" "Description" = "8:" "ShowCmd" = "3:1" "IconIndex" = "3:0" "Transitive" = "11:FALSE" "Target" = "8:_AF057921D20E4520A3C6420F0729A744" "Folder" = "8:_E379D4EDBAD0460BB876711E9062ADB4" "WorkingFolder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Icon" = "8:" "Feature" = "8:" } "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_70CF74DB997A408DBBFD48AB10F92321" { "Name" = "8:ipptool Documentation" "Arguments" = "8:" "Description" = "8:" "ShowCmd" = "3:1" "IconIndex" = "3:0" "Transitive" = "11:FALSE" "Target" = "8:_D5CD9D9AB1644688A1D54B1589BDF724" "Folder" = "8:_E379D4EDBAD0460BB876711E9062ADB4" "WorkingFolder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Icon" = "8:" "Feature" = "8:" } "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_BD2A7DF74D844FF5919EE8340EE36ECD" { "Name" = "8:Test File Documentation" "Arguments" = "8:" "Description" = "8:" "ShowCmd" = "3:1" "IconIndex" = "3:0" "Transitive" = "11:FALSE" "Target" = "8:_1A1324305D78463BBFC62269C56DCF0B" "Folder" = "8:_E379D4EDBAD0460BB876711E9062ADB4" "WorkingFolder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Icon" = "8:" "Feature" = "8:" } } "UserInterface" { "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_045DF90B1FF941A9BA7A742CFC0A6C00" { "UseDynamicProperties" = "11:FALSE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdUserInterface.wim" } "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_345BD86390E841A98B74ED3E07945F8C" { "Name" = "8:#1900" "Sequence" = "3:2" "Attributes" = "3:1" "Dialogs" { "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_067C143A8731427180B1568AF8C07375" { "Sequence" = "3:200" "DisplayName" = "8:Installation Folder" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdAdminFolderDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } } } "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_A2F2CC6EB9D7453599E7598D4D0629A5" { "Sequence" = "3:300" "DisplayName" = "8:Confirm Installation" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdAdminConfirmDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } } } "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_C2B41369B7334F419318792EBA031412" { "Sequence" = "3:100" "DisplayName" = "8:Welcome" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdAdminWelcomeDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "CopyrightWarning" { "Name" = "8:CopyrightWarning" "DisplayName" = "8:#1002" "Description" = "8:#1102" "Type" = "3:3" "ContextData" = "8:" "Attributes" = "3:0" "Setting" = "3:2" "Value" = "8:This computer program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2." "DefaultValue" = "8:#1202" "UsePlugInResources" = "11:TRUE" } "Welcome" { "Name" = "8:Welcome" "DisplayName" = "8:#1003" "Description" = "8:#1103" "Type" = "3:3" "ContextData" = "8:" "Attributes" = "3:0" "Setting" = "3:1" "Value" = "8:#1203" "DefaultValue" = "8:#1203" "UsePlugInResources" = "11:TRUE" } } } } } "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_6B654A06090344BA9AA443E0D0296737" { "Name" = "8:#1902" "Sequence" = "3:1" "Attributes" = "3:3" "Dialogs" { "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_FB4E7BBC3DA242309FFB58F9A6194A93" { "Sequence" = "3:100" "DisplayName" = "8:Finished" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdFinishedDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "UpdateText" { "Name" = "8:UpdateText" "DisplayName" = "8:#1058" "Description" = "8:#1158" "Type" = "3:15" "ContextData" = "8:" "Attributes" = "3:0" "Setting" = "3:1" "Value" = "8:#1258" "DefaultValue" = "8:#1258" "UsePlugInResources" = "11:TRUE" } } } } } "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_712819C7C4F042ABB708949BD4426628" { "Name" = "8:#1900" "Sequence" = "3:1" "Attributes" = "3:1" "Dialogs" { "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_2F49D4FACB954AF2B786D2AD9206D053" { "Sequence" = "3:100" "DisplayName" = "8:Welcome" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdWelcomeDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "CopyrightWarning" { "Name" = "8:CopyrightWarning" "DisplayName" = "8:#1002" "Description" = "8:#1102" "Type" = "3:3" "ContextData" = "8:" "Attributes" = "3:0" "Setting" = "3:2" "Value" = "8:This computer program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2." "DefaultValue" = "8:#1202" "UsePlugInResources" = "11:TRUE" } "Welcome" { "Name" = "8:Welcome" "DisplayName" = "8:#1003" "Description" = "8:#1103" "Type" = "3:3" "ContextData" = "8:" "Attributes" = "3:0" "Setting" = "3:1" "Value" = "8:#1203" "DefaultValue" = "8:#1203" "UsePlugInResources" = "11:TRUE" } } } "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_770E25BC453A464EA8CD51381FDDDD9F" { "Sequence" = "3:300" "DisplayName" = "8:Confirm Installation" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdConfirmDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } } } "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_9534A64B629F4F868D6D7A384C76DCB2" { "Sequence" = "3:200" "DisplayName" = "8:Installation Folder" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdFolderDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "InstallAllUsersVisible" { "Name" = "8:InstallAllUsersVisible" "DisplayName" = "8:#1059" "Description" = "8:#1159" "Type" = "3:5" "ContextData" = "8:1;True=1;False=0" "Attributes" = "3:0" "Setting" = "3:0" "Value" = "3:1" "DefaultValue" = "3:1" "UsePlugInResources" = "11:TRUE" } } } } } "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_770CCEFF81BD46A182A6E816A41A0E81" { "Name" = "8:#1901" "Sequence" = "3:2" "Attributes" = "3:2" "Dialogs" { "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_75E0C1FD245D493DA0D7E3E0BC0C365F" { "Sequence" = "3:100" "DisplayName" = "8:Progress" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdAdminProgressDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "ShowProgress" { "Name" = "8:ShowProgress" "DisplayName" = "8:#1009" "Description" = "8:#1109" "Type" = "3:5" "ContextData" = "8:1;True=1;False=0" "Attributes" = "3:0" "Setting" = "3:0" "Value" = "3:1" "DefaultValue" = "3:1" "UsePlugInResources" = "11:TRUE" } } } } } "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_933B15E9A383418F8ADF3B13F68458F3" { "UseDynamicProperties" = "11:FALSE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdBasicDialogs.wim" } "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_E310DA8CED734E00950A3C5D630CE987" { "Name" = "8:#1902" "Sequence" = "3:2" "Attributes" = "3:3" "Dialogs" { "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_CB172E69F9C74901BE1040336CFD4F72" { "Sequence" = "3:100" "DisplayName" = "8:Finished" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdAdminFinishedDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } } } } } "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_F44F9BE9B54940848289669635E4A5A2" { "Name" = "8:#1901" "Sequence" = "3:1" "Attributes" = "3:2" "Dialogs" { "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_14751F327A634B989283C8F28CFB6DFC" { "Sequence" = "3:100" "DisplayName" = "8:Progress" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdProgressDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "ShowProgress" { "Name" = "8:ShowProgress" "DisplayName" = "8:#1009" "Description" = "8:#1109" "Type" = "3:5" "ContextData" = "8:1;True=1;False=0" "Attributes" = "3:0" "Setting" = "3:0" "Value" = "3:1" "DefaultValue" = "3:1" "UsePlugInResources" = "11:TRUE" } } } } } } "MergeModule" { "{CEE29DC0-9FBA-4B99-8D47-5BC643D9B626}:_4273A45FE6E54897AC9A4F66D9AA59EC" { "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:TRUE" "SourcePath" = "8:microsoft_vc90_debugcrt_x86.msm" "Properties" { } "LanguageId" = "3:0" "Exclude" = "11:FALSE" "Folder" = "8:" "Feature" = "8:" "IsolateTo" = "8:" } "{CEE29DC0-9FBA-4B99-8D47-5BC643D9B626}:_8A6033CAC27E4C1185B4FDF7D2BF8D2E" { "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:TRUE" "SourcePath" = "8:policy_9_0_Microsoft_VC90_DebugCRT_x86.msm" "Properties" { } "LanguageId" = "3:0" "Exclude" = "11:FALSE" "Folder" = "8:" "Feature" = "8:" "IsolateTo" = "8:" } } "ProjectOutput" { "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_58DC0E72F0944BEFB927AED718CD1660" { "SourcePath" = "8:Win32\\Release\\ippfind.exe" "TargetName" = "8:" "Tag" = "8:" "Folder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" "ProjectOutputGroupRegister" = "3:1" "OutputConfiguration" = "8:" "OutputGroupCanonicalName" = "8:Built" "OutputProjectGuid" = "8:{B484DA0C-62C8-4C32-83B6-CCEB58968B85}" "ShowKeyOutput" = "11:TRUE" "ExcludeFilters" { } } "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_D02EB13951314EFD9C539150EF8E53B8" { "SourcePath" = "8:Win32\\Release\\regex.dll" "TargetName" = "8:" "Tag" = "8:" "Folder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" "ProjectOutputGroupRegister" = "3:1" "OutputConfiguration" = "8:" "OutputGroupCanonicalName" = "8:Built" "OutputProjectGuid" = "8:{18950A1B-D37A-40C7-B2DF-C12986C0526E}" "ShowKeyOutput" = "11:TRUE" "ExcludeFilters" { } } "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_E97571D3FBE048DABDC59B37762D800F" { "SourcePath" = "8:Win32\\Release\\ipptool.exe" "TargetName" = "8:" "Tag" = "8:" "Folder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" "ProjectOutputGroupRegister" = "3:1" "OutputConfiguration" = "8:" "OutputGroupCanonicalName" = "8:Built" "OutputProjectGuid" = "8:{B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}" "ShowKeyOutput" = "11:TRUE" "ExcludeFilters" { } } "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_EA282F32A10B4ED1A81AA6133B997C6A" { "SourcePath" = "8:Win32\\Release\\libcups2.dll" "TargetName" = "8:" "Tag" = "8:" "Folder" = "8:_FFAEDEA1D38D4088A03FDD6F17E2CA5D" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" "ProjectOutputGroupRegister" = "3:1" "OutputConfiguration" = "8:" "OutputGroupCanonicalName" = "8:Built" "OutputProjectGuid" = "8:{CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}" "ShowKeyOutput" = "11:TRUE" "ExcludeFilters" { } } } } } ippsample/vcnet/config.h0000644000175000017500000002010313240604116014270 0ustar tilltill/* * Configuration file for the IPP samples on Windows. * * Copyright 2007-2016 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright * law. Distribution and use rights are outlined in the file "LICENSE.txt" * which should have been included with this file. If this file is * missing or damaged, see the license at "http://www.cups.org/". */ #ifndef _CUPS_CONFIG_H_ #define _CUPS_CONFIG_H_ /* * Include necessary headers... */ #include #include #include #include #include #include /* * Microsoft renames the POSIX functions to _name, and introduces * a broken compatibility layer using the original names. As a result, * random crashes can occur when, for example, strdup() allocates memory * from a different heap than used by malloc() and free(). * * To avoid moronic problems like this, we #define the POSIX function * names to the corresponding non-standard Microsoft names. */ #define access _access #define close _close #define fileno _fileno #define lseek _lseek #define mkdir(d,p) _mkdir(d) #define open _open #define read _read #define rmdir _rmdir #define snprintf _snprintf #define strdup _strdup #define unlink _unlink #define vsnprintf _vsnprintf #define write _write /* * Map the POSIX strcasecmp() and strncasecmp() functions to the Win32 stricmp() * and strnicmp() functions... */ #define strcasecmp stricmp #define strncasecmp strnicmp /* * Map the POSIX sleep() and usleep() functions to the Win32 Sleep() function... */ typedef unsigned long useconds_t; #define sleep(X) Sleep(1000 * (X)) #define usleep(X) Sleep((X)/1000) /* * Map various parameters to Posix style system calls */ # define F_OK 00 # define W_OK 02 # define R_OK 04 # define O_RDONLY _O_RDONLY # define O_WRONLY _O_WRONLY # define O_CREAT _O_CREAT # define O_TRUNC _O_TRUNC /* * Compiler stuff... */ #undef const #undef __CHAR_UNSIGNED__ /* * Version of software... */ #define CUPS_SVERSION "IPPSAMPLE v20160531" #define CUPS_MINIMAL "IPPSAMPLE/20160531" /* * Default IPP port... */ #define CUPS_DEFAULT_IPP_PORT 631 /* * Do we have domain socket support, and if so what is the default one? */ #undef CUPS_DEFAULT_DOMAINSOCKET /* * Where are files stored? * * Note: These are defaults, which can be overridden by environment * variables at run-time... */ #define CUPS_CACHEDIR "C:/CUPS/cache" #define CUPS_DATADIR "C:/CUPS/share" #define CUPS_LOCALEDIR "C:/CUPS/locale" #define CUPS_SERVERROOT "C:/CUPS/etc" #define CUPS_STATEDIR "C:/CUPS/run" /* * Do we have posix_spawn? */ /* #undef HAVE_POSIX_SPAWN */ /* * Do we have ZLIB? */ #define HAVE_LIBZ 1 #define HAVE_INFLATECOPY 1 /* * Use ? */ /* #undef HAVE_STDINT_H */ /* * Use , , and/or ? */ #define HAVE_STRING_H 1 /* #undef HAVE_STRINGS_H */ /* #undef HAVE_BSTRING_H */ /* * Do we have the long long type? */ /* #undef HAVE_LONG_LONG */ #ifdef HAVE_LONG_LONG # define CUPS_LLFMT "%lld" # define CUPS_LLCAST (long long) #else # define CUPS_LLFMT "%ld" # define CUPS_LLCAST (long) #endif /* HAVE_LONG_LONG */ /* * Do we have the strtoll() function? */ /* #undef HAVE_STRTOLL */ #ifndef HAVE_STRTOLL # define strtoll(nptr,endptr,base) strtol((nptr), (endptr), (base)) #endif /* !HAVE_STRTOLL */ /* * Do we have the strXXX() functions? */ #define HAVE_STRDUP 1 /* #undef HAVE_STRLCAT */ /* #undef HAVE_STRLCPY */ /* * Do we have the (v)snprintf() functions? */ #define HAVE_SNPRINTF 1 #define HAVE_VSNPRINTF 1 /* * What signal functions to use? */ /* #undef HAVE_SIGSET */ /* #undef HAVE_SIGACTION */ /* * What wait functions to use? */ /* #undef HAVE_WAITPID */ /* #undef HAVE_WAIT3 */ /* * Do we have the langinfo.h header file? */ /* #undef HAVE_LANGINFO_H */ /* * Which encryption libraries do we have? */ /* #undef HAVE_CDSASSL */ /* #undef HAVE_GNUTLS */ #define HAVE_SSPISSL #define HAVE_SSL /* * Do we have the gnutls_transport_set_pull_timeout_function function? */ /* #undef HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION */ /* * Do we have the gnutls_priority_set_direct function? */ /* #undef HAVE_GNUTLS_PRIORITY_SET_DIRECT */ /* * What Security framework headers do we have? */ /* #undef HAVE_AUTHORIZATION_H */ /* #undef HAVE_SECBASEPRIV_H */ /* #undef HAVE_SECCERTIFICATE_H */ /* #undef HAVE_SECIDENTITYSEARCHPRIV_H */ /* #undef HAVE_SECITEM_H */ /* #undef HAVE_SECITEMPRIV_H */ /* #undef HAVE_SECPOLICY_H */ /* #undef HAVE_SECPOLICYPRIV_H */ /* #undef HAVE_SECURETRANSPORTPRIV_H */ /* * Do we have the cssmErrorString function? */ /* #undef HAVE_CSSMERRORSTRING */ /* * Do we have the SecGenerateSelfSignedCertificate function? */ /* #undef HAVE_SECGENERATESELFSIGNEDCERTIFICATE */ /* * Do we have the SecKeychainOpen function? */ /* #undef HAVE_SECKEYCHAINOPEN */ /* * Do we have (a working) SSLSetEnabledCiphers function? */ #define HAVE_SSLSETENABLEDCIPHERS 1 /* * Do we have mDNSResponder for DNS Service Discovery (aka Bonjour)? */ #define HAVE_DNSSD 1 /* * Do we have Avahi for DNS Service Discovery (aka Bonjour)? */ #undef HAVE_AVAHI /* * Does the "stat" structure contain the "st_gen" member? */ /* #undef HAVE_ST_GEN */ /* * Does the "tm" structure contain the "tm_gmtoff" member? */ /* #undef HAVE_TM_GMTOFF */ /* * Do we have getaddrinfo()? */ #define HAVE_GETADDRINFO 1 /* * Do we have getnameinfo()? */ #define HAVE_GETNAMEINFO 1 /* * Do we have hstrerror()? */ /* #undef HAVE_HSTRERROR */ /* * Do we have res_init()? */ /* #undef HAVE_RES_INIT */ /* * Do we have */ /* #undef HAVE_RESOLV_H */ /* * Do we have the header file? */ /* #undef HAVE_SYS_SOCKIO_H */ /* * Does the sockaddr structure contain an sa_len parameter? */ /* #undef HAVE_STRUCT_SOCKADDR_SA_LEN */ /* * Do we have pthread support? */ /* #undef HAVE_PTHREAD_H */ /* * Do we have CoreFoundation public and private headers? */ /* #undef HAVE_COREFOUNDATION_H */ /* #undef HAVE_CFPRIV_H */ /* #undef HAVE_CFBUNDLEPRIV_H */ /* * Do we have ApplicationServices public headers? */ /* #undef HAVE_APPLICATIONSERVICES_H */ /* * Do we have the MuPDF library? */ /* #undef HAVE_MUPDF */ /* * Select/poll interfaces... */ /* #undef HAVE_POLL */ /* #undef HAVE_EPOLL */ /* #undef HAVE_KQUEUE */ /* * Do we have ? */ /* #undef HAVE_SYS_PARAM_H */ /* * Do we have ? */ /* #undef HAVE_SYS_UCRED_H */ /* * Do we have removefile()? */ /* #undef HAVE_REMOVEFILE */ /* * Which random number generator function to use... */ /* #undef HAVE_ARC4RANDOM */ /* #undef HAVE_RANDOM */ /* #undef HAVE_LRAND48 */ #ifdef HAVE_ARC4RANDOM # define CUPS_RAND() arc4random() # define CUPS_SRAND(v) arc4random_stir() #elif defined(HAVE_RANDOM) # define CUPS_RAND() random() # define CUPS_SRAND(v) srandom(v) #elif defined(HAVE_LRAND48) # define CUPS_RAND() lrand48() # define CUPS_SRAND(v) srand48(v) #else # define CUPS_RAND() rand() # define CUPS_SRAND(v) srand(v) #endif /* HAVE_ARC4RANDOM */ /* * Do we have ? */ /* #undef HAVE_ICONV_H */ /* * Do we have statfs or statvfs and one of the corresponding headers? */ /* #undef HAVE_STATFS */ /* #undef HAVE_STATVFS */ /* #undef HAVE_SYS_MOUNT_H */ /* #undef HAVE_SYS_STATFS_H */ /* #undef HAVE_SYS_STATVFS_H */ /* #undef HAVE_SYS_VFS_H */ /* * Location of macOS localization bundle, if any. */ /* #undef CUPS_BUNDLEDIR */ /* * Do we have the C99 abs() function? */ /* #undef HAVE_ABS */ #if !defined(HAVE_ABS) && !defined(abs) # if defined(__GNUC__) || __STDC_VERSION__ >= 199901L # define abs(x) _cups_abs(x) static inline int _cups_abs(int i) { return (i < 0 ? -i : i); } # elif defined(_MSC_VER) # define abs(x) _cups_abs(x) static __inline int _cups_abs(int i) { return (i < 0 ? -i : i); } # else # define abs(x) ((x) < 0 ? -(x) : (x)) # endif /* __GNUC__ || __STDC_VERSION__ */ #endif /* !HAVE_ABS && !abs */ #endif /* !_CUPS_CONFIG_H_ */ ippsample/vcnet/ippfind.vcxproj.filters0000644000175000017500000000164113240604116017375 0ustar tilltill {8C1A7322-AFBD-4611-A001-CF18E3B0F00C} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {5807291C-0541-4D9C-9290-628F88CF9119} h;hpp;hxx;hm;inl;inc;xsd {7767CEF5-1BED-4C4C-82A7-37DF77126FE3} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav Source Files ippsample/vcnet/ipptool.vcxproj0000644000175000017500000002323613240604116015767 0ustar tilltill Debug Win32 Debug x64 Release Win32 Release x64 {B246D91E-61F2-4433-BFD2-6C2A96FBD4D4} ipptool Win32Proj Application v120 Unicode true Application v120 Unicode Application v120 Unicode true Application v120 Unicode <_ProjectFileVersion>12.0.30501.0 $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ true $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ true $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ false $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ false Disabled ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level1 EditAndContinue true Console false MachineX86 X64 Disabled ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level1 ProgramDatabase true Console false MachineX64 ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) MultiThreadedDLL Level1 ProgramDatabase true Console true true false MachineX86 signtool sign /n "IEEE INDUSTRY STANDARDS AND TECHNOLOGY ORGANIZATION" $(TargetPath) Sign code with IEEE-ISTO cert. X64 ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) MultiThreadedDLL Level1 ProgramDatabase true Console true true false MachineX64 signtool sign /n "IEEE INDUSTRY STANDARDS AND TECHNOLOGY ORGANIZATION" $(TargetPath) Sign code with IEEE-ISTO cert. {cb4aa6f2-3e84-45be-b505-95cd375e8be3} false {18950a1b-d37a-40c7-b2df-c12986c0526e} false ippsample/vcnet/ippserver.vcxproj.filters0000644000175000017500000000164313240604116017765 0ustar tilltill {5129820B-88C2-40AE-BE81-C7957F76540D} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {CAF4FFBF-7D66-4368-A03A-3FD0971B59A0} h;hpp;hxx;hm;inl;inc;xsd {17D3B9CD-53D2-47AF-9D2A-4516D777D695} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav Source Files ippsample/vcnet/libcups2.vcxproj.filters0000644000175000017500000001411213240604116017464 0ustar tilltill {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files ippsample/Makedefs.in0000644000175000017500000000617713240604116013621 0ustar tilltill# # Common makefile definitions for the IPP sample code. # # Copyright 2014-2017 by the IEEE-ISTO Printer Working Group. # Copyright 2007-2017 by Apple Inc. # Copyright 1997-2007 by Easy Software Products, all rights reserved. # # Licensed under Apache License v2.0. See the file "LICENSE" for more # information. # # # Version of the IPP sample code. # IPPSAMPLE_VERSION = @CUPS_VERSION@ # # Components that get built... # IPPFIND_BIN = @IPPFIND_BIN@ IPPFIND_HTML = @IPPFIND_HTML@ IPPFIND_MAN = @IPPFIND_MAN@ IPPTRANSFORM_BIN = @IPPTRANSFORM_BIN@ IPPTRANSFORM_HTML = @IPPTRANSFORM_HTML@ IPPTRANSFORM_MAN = @IPPTRANSFORM_MAN@ IPPTRANSFORM3D_BIN = @IPPTRANSFORM3D_BIN@ IPPTRANSFORM3D_HTML = @IPPTRANSFORM3D_HTML@ IPPTRANSFORM3D_MAN = @IPPTRANSFORM3D_MAN@ # # Programs... # AR = @AR@ AWK = @AWK@ CC = @CC@ CHMOD = @CHMOD@ GZIP = @GZIP@ INSTALL = @INSTALL@ RANLIB = @RANLIB@ RM = @RM@ -f RMDIR = @RMDIR@ SED = @SED@ SHELL = /bin/sh # # Installation programs... # INSTALL_BIN = $(LIBTOOL) $(INSTALL) -c -m 555 @INSTALL_STRIP@ INSTALL_DATA = $(INSTALL) -c -m 444 INSTALL_DIR = $(INSTALL) -d INSTALL_LIB = $(LIBTOOL) $(INSTALL) -c -m 555 @INSTALL_STRIP@ INSTALL_MAN = $(INSTALL) -c -m 444 # # Libraries... # LIBZ = @LIBZ@ # # Program options... # # ARCHFLAGS Defines the default architecture build options. # OPTIM Defines the common compiler optimization/debugging options # for all architectures. # OPTIONS Defines other compile-time options (currently only -DDEBUG # for extra debug info) # ALL_CFLAGS = -I.. -D_CUPS_SOURCE $(CFLAGS) $(SSLFLAGS) \ @LARGEFILE@ @PTHREAD_FLAGS@ $(OPTIONS) ALL_CXXFLAGS = -I.. -D_CUPS_SOURCE $(CXXFLAGS) $(SSLFLAGS) \ @LARGEFILE@ @PTHREAD_FLAGS@ $(OPTIONS) ARCHFLAGS = @ARCHFLAGS@ ARFLAGS = @ARFLAGS@ CFLAGS = @CPPFLAGS@ @CFLAGS@ COMMONLIBS = @LIBS@ DNSSDLIBS = @DNSSDLIBS@ LDFLAGS = @LDARCHFLAGS@ @LDFLAGS@ $(OPTIM) LINKCUPS = ../cups/libcups.a $(SSLLIBS) $(DNSSDLIBS) $(LIBZ) LIBS = $(LINKCUPS) $(COMMONLIBS) OPTIM = @OPTIM@ OPTIONS = SSLFLAGS = @SSLFLAGS@ SSLLIBS = @SSLLIBS@ # # Directories... # # The first section uses the GNU names (which are *extremely* # difficult to find in a makefile because they are lowercase...) # We have to define these first because autoconf uses ${prefix} # and ${exec_prefix} for most of the other directories... # # The "datarootdir" variable may not get defined if you are using # a version of autoconf prior to 2.60. # # This is immediately followed by definition in ALL CAPS for the # needed directories... # bindir = @bindir@ datadir = @datadir@ datarootdir = @datarootdir@ exec_prefix = @exec_prefix@ includedir = @includedir@ infodir = @infodir@ libdir = @libdir@ libexecdir = @libexecdir@ localstatedir = @localstatedir@ mandir = @mandir@ oldincludedir = @oldincludedir@ prefix = @prefix@ privateinclude = @privateinclude@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ top_srcdir = @top_srcdir@ BUILDROOT = $(DSTROOT)$(DESTDIR) IPP = @IPP@ # # Rules... # .SILENT: .SUFFIXES: .a .c .h .o .c.o: echo Compiling $<... $(CC) $(ARCHFLAGS) $(OPTIM) $(ALL_CFLAGS) -c -o $@ $< ippsample/configure0000755000175000017500000064563313240604116013467 0ustar tilltill#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for IPPSAMPLE 1.0b1. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: https://github.com/istopwg/ippsample/issues about your $0: system, including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='IPPSAMPLE' PACKAGE_TARNAME='ippsample' PACKAGE_VERSION='1.0b1' PACKAGE_STRING='IPPSAMPLE 1.0b1' PACKAGE_BUGREPORT='https://github.com/istopwg/ippsample/issues' PACKAGE_URL='http://www.pwg.org/ipp/' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS IPP IPPFIND_MAN IPPFIND_HTML IPPFIND_BIN DNSSDLIBS LARGEFILE EXPORT_SSLLIBS SSLLIBS SSLFLAGS IPPALIASES CUPS_SERVERKEYCHAIN LIBGCRYPTCONFIG LIBGNUTLSCONFIG PTHREAD_FLAGS CUPS_LISTEN_DOMAINSOCKET CUPS_DEFAULT_DOMAINSOCKET RELROFLAGS PIEFLAGS CXXLIBS LDARCHFLAGS ARCHFLAGS UNITTESTS OPTIM INSTALL_STRIP CURAENGINE IPPTRANSFORM3D_MAN IPPTRANSFORM3D_HTML IPPTRANSFORM3D_BIN IPPTRANSFORM_MAN IPPTRANSFORM_HTML IPPTRANSFORM_BIN ARFLAGS LIBZ INSTALL_GZIP EGREP GREP PKGCONFIG INSTALL SED RMDIR RM GZIP CHMOD AR RANLIB CPP OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC AWK CUPS_REVISION CUPS_VERSION target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_optim enable_debug enable_debug_guards enable_debug_printfs enable_unit_tests with_archflags with_ldarchflags enable_relro with_domainsocket enable_threads enable_ssl enable_cdsassl enable_gnutls enable_largefile enable_avahi enable_dnssd with_dnssd_libs with_dnssd_includes with_name_prefix ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures IPPSAMPLE 1.0b1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/ippsample] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of IPPSAMPLE 1.0b1:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-debug build without debugging symbols --enable-debug-guards build with memory allocation guards --disable-debug-printfs disable CUPS_DEBUG_LOG support --enable-unit-tests build and run unit tests --enable-relro build with the GCC relro option --disable-threads disable multi-threading support --disable-ssl disable SSL/TLS support --enable-cdsassl use CDSA for SSL/TLS support, default=first --enable-gnutls use GNU TLS for SSL/TLS support, default=second --disable-largefile omit support for large files --disable-avahi disable DNS Service Discovery support using Avahi --disable-dnssd disable DNS Service Discovery support using mDNSResponder Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-optim set optimization flags --with-archflags set default architecture flags --with-ldarchflags set program architecture flags --with-domainsocket set unix domain socket name --with-dnssd-libs set directory for DNS Service Discovery library --with-dnssd-includes set directory for DNS Service Discovery includes --with-name-prefix=... set prefix on command names (default is "ipp") Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . IPPSAMPLE home page: . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF IPPSAMPLE configure 1.0b1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ---------------------------------------------------------- ## ## Report this to https://github.com/istopwg/ippsample/issues ## ## ---------------------------------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else eval "$4=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by IPPSAMPLE $as_me 1.0b1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu uname=`uname` uversion=`uname -r | sed -e '1,$s/^[^0-9]*\([0-9]*\)\.\([0-9]*\).*/\1\2/'` uarch=`uname -m` case "$uname" in Darwin*) uname="Darwin" if test $uversion -lt 120; then as_fn_error $? "Sorry, this version of CUPS requires macOS 10.8 or higher." "$LINENO" 5 fi ;; GNU* | GNU/*) uname="GNU" ;; Linux*) uname="Linux" ;; esac ac_config_headers="$ac_config_headers config.h" CUPS_VERSION="1.0b1" CUPS_REVISION="" cat >>confdefs.h <<_ACEOF #define CUPS_SVERSION "IPPSAMPLE v$CUPS_VERSION$CUPS_REVISION" _ACEOF cat >>confdefs.h <<_ACEOF #define CUPS_MINIMAL "IPPSAMPLE/$CUPS_VERSION$CUPS_REVISION" _ACEOF CFLAGS="${CFLAGS:=}" CPPFLAGS="${CPPFLAGS:=}" CXXFLAGS="${CXXFLAGS:=}" LDFLAGS="${LDFLAGS:=}" for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then for ac_prog in clang cc gcc do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in clang cc gcc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_AR+:} false; then : $as_echo_n "(cached) " >&6 else case $AR in [\\/]* | ?:[\\/]*) ac_cv_path_AR="$AR" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_AR="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi AR=$ac_cv_path_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "chmod", so it can be a program name with args. set dummy chmod; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_CHMOD+:} false; then : $as_echo_n "(cached) " >&6 else case $CHMOD in [\\/]* | ?:[\\/]*) ac_cv_path_CHMOD="$CHMOD" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_CHMOD="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi CHMOD=$ac_cv_path_CHMOD if test -n "$CHMOD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CHMOD" >&5 $as_echo "$CHMOD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "gzip", so it can be a program name with args. set dummy gzip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_GZIP+:} false; then : $as_echo_n "(cached) " >&6 else case $GZIP in [\\/]* | ?:[\\/]*) ac_cv_path_GZIP="$GZIP" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_GZIP="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi GZIP=$ac_cv_path_GZIP if test -n "$GZIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GZIP" >&5 $as_echo "$GZIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "rm", so it can be a program name with args. set dummy rm; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_RM+:} false; then : $as_echo_n "(cached) " >&6 else case $RM in [\\/]* | ?:[\\/]*) ac_cv_path_RM="$RM" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_RM="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi RM=$ac_cv_path_RM if test -n "$RM"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RM" >&5 $as_echo "$RM" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "rmdir", so it can be a program name with args. set dummy rmdir; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_RMDIR+:} false; then : $as_echo_n "(cached) " >&6 else case $RMDIR in [\\/]* | ?:[\\/]*) ac_cv_path_RMDIR="$RMDIR" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_RMDIR="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi RMDIR=$ac_cv_path_RMDIR if test -n "$RMDIR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RMDIR" >&5 $as_echo "$RMDIR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "sed", so it can be a program name with args. set dummy sed; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else case $SED in [\\/]* | ?:[\\/]*) ac_cv_path_SED="$SED" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_SED="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi SED=$ac_cv_path_SED if test -n "$SED"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SED" >&5 $as_echo "$SED" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$AR" = x; then as_fn_error $? "Unable to find required library archive command." "$LINENO" 5 fi if test "x$CC" = x; then as_fn_error $? "Unable to find required C compiler command." "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for install-sh script" >&5 $as_echo_n "checking for install-sh script... " >&6; } INSTALL="`pwd`/install-sh" { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $INSTALL" >&5 $as_echo "using $INSTALL" >&6; } if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKGCONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKGCONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKGCONFIG=$ac_cv_path_PKGCONFIG if test -n "$PKGCONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 $as_echo "$PKGCONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKGCONFIG"; then ac_pt_PKGCONFIG=$PKGCONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKGCONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKGCONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG if test -n "$ac_pt_PKGCONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 $as_echo "$ac_pt_PKGCONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKGCONFIG" = x; then PKGCONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKGCONFIG=$ac_pt_PKGCONFIG fi else PKGCONFIG="$ac_cv_path_PKGCONFIG" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing abs" >&5 $as_echo_n "checking for library containing abs... " >&6; } if ${ac_cv_search_abs+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char abs (); int main () { return abs (); ; return 0; } _ACEOF for ac_lib in '' m; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_abs=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_abs+:} false; then : break fi done if ${ac_cv_search_abs+:} false; then : else ac_cv_search_abs=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_abs" >&5 $as_echo "$ac_cv_search_abs" >&6; } ac_res=$ac_cv_search_abs if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_ABS 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing fmod" >&5 $as_echo_n "checking for library containing fmod... " >&6; } if ${ac_cv_search_fmod+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char fmod (); int main () { return fmod (); ; return 0; } _ACEOF for ac_lib in '' m; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_fmod=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_fmod+:} false; then : break fi done if ${ac_cv_search_fmod+:} false; then : else ac_cv_search_fmod=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_fmod" >&5 $as_echo "$ac_cv_search_fmod" >&6; } ac_res=$ac_cv_search_fmod if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes; then : $as_echo "#define HAVE_STDLIB_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "langinfo.h" "ac_cv_header_langinfo_h" "$ac_includes_default" if test "x$ac_cv_header_langinfo_h" = xyes; then : $as_echo "#define HAVE_LANGINFO_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "$ac_includes_default" if test "x$ac_cv_header_malloc_h" = xyes; then : $as_echo "#define HAVE_MALLOC_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default" if test "x$ac_cv_header_stdint_h" = xyes; then : $as_echo "#define HAVE_STDINT_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default" if test "x$ac_cv_header_string_h" = xyes; then : $as_echo "#define HAVE_STRING_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "strings.h" "ac_cv_header_strings_h" "$ac_includes_default" if test "x$ac_cv_header_strings_h" = xyes; then : $as_echo "#define HAVE_STRINGS_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "bstring.h" "ac_cv_header_bstring_h" "$ac_includes_default" if test "x$ac_cv_header_bstring_h" = xyes; then : $as_echo "#define HAVE_BSTRING_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "sys/ioctl.h" "ac_cv_header_sys_ioctl_h" "$ac_includes_default" if test "x$ac_cv_header_sys_ioctl_h" = xyes; then : $as_echo "#define HAVE_SYS_IOCTL_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" if test "x$ac_cv_header_sys_param_h" = xyes; then : $as_echo "#define HAVE_SYS_PARAM_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "sys/ucred.h" "ac_cv_header_sys_ucred_h" "$ac_includes_default" if test "x$ac_cv_header_sys_ucred_h" = xyes; then : $as_echo "#define HAVE_SYS_UCRED_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "iconv.h" "ac_cv_header_iconv_h" "$ac_includes_default" if test "x$ac_cv_header_iconv_h" = xyes; then : SAVELIBS="$LIBS" LIBS="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing iconv_open" >&5 $as_echo_n "checking for library containing iconv_open... " >&6; } if ${ac_cv_search_iconv_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char iconv_open (); int main () { return iconv_open (); ; return 0; } _ACEOF for ac_lib in '' iconv; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_iconv_open=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_iconv_open+:} false; then : break fi done if ${ac_cv_search_iconv_open+:} false; then : else ac_cv_search_iconv_open=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_iconv_open" >&5 $as_echo "$ac_cv_search_iconv_open" >&6; } ac_res=$ac_cv_search_iconv_open if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_ICONV_H 1" >>confdefs.h SAVELIBS="$SAVELIBS $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing libiconv_open" >&5 $as_echo_n "checking for library containing libiconv_open... " >&6; } if ${ac_cv_search_libiconv_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char libiconv_open (); int main () { return libiconv_open (); ; return 0; } _ACEOF for ac_lib in '' iconv; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_libiconv_open=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_libiconv_open+:} false; then : break fi done if ${ac_cv_search_libiconv_open+:} false; then : else ac_cv_search_libiconv_open=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_libiconv_open" >&5 $as_echo "$ac_cv_search_libiconv_open" >&6; } ac_res=$ac_cv_search_libiconv_open if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_ICONV_H 1" >>confdefs.h SAVELIBS="$SAVELIBS $LIBS" fi LIBS="$SAVELIBS" fi ac_fn_c_check_header_mongrel "$LINENO" "sys/mount.h" "ac_cv_header_sys_mount_h" "$ac_includes_default" if test "x$ac_cv_header_sys_mount_h" = xyes; then : $as_echo "#define HAVE_SYS_MOUNT_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "sys/statfs.h" "ac_cv_header_sys_statfs_h" "$ac_includes_default" if test "x$ac_cv_header_sys_statfs_h" = xyes; then : $as_echo "#define HAVE_SYS_STATFS_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "sys/statvfs.h" "ac_cv_header_sys_statvfs_h" "$ac_includes_default" if test "x$ac_cv_header_sys_statvfs_h" = xyes; then : $as_echo "#define HAVE_SYS_STATVFS_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "sys/vfs.h" "ac_cv_header_sys_vfs_h" "$ac_includes_default" if test "x$ac_cv_header_sys_vfs_h" = xyes; then : $as_echo "#define HAVE_SYS_VFS_H 1" >>confdefs.h fi for ac_func in statfs statvfs do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in strdup strlcat strlcpy do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done if test "$uname" = "HP-UX" -a "$uversion" = "1020"; then echo Forcing snprintf emulation for HP-UX. else for ac_func in snprintf vsnprintf do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done fi for ac_func in random lrand48 arc4random do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done case "$uname" in Linux | GNU) # Do not use sigset on Linux or GNU HURD ;; *) # Use sigset on other platforms, if available for ac_func in sigset do : ac_fn_c_check_func "$LINENO" "sigset" "ac_cv_func_sigset" if test "x$ac_cv_func_sigset" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SIGSET 1 _ACEOF fi done ;; esac for ac_func in sigaction do : ac_fn_c_check_func "$LINENO" "sigaction" "ac_cv_func_sigaction" if test "x$ac_cv_func_sigaction" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SIGACTION 1 _ACEOF fi done for ac_func in waitpid wait3 do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in posix_spawn do : ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn" if test "x$ac_cv_func_posix_spawn" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_POSIX_SPAWN 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tm_gmtoff member in tm structure" >&5 $as_echo_n "checking for tm_gmtoff member in tm structure... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct tm t; int o = t.tm_gmtoff; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_TM_GMTOFF 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for st_gen member in stat structure" >&5 $as_echo_n "checking for st_gen member in stat structure... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct stat t; int o = t.st_gen; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_ST_GEN 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext INSTALL_GZIP="" LIBZ="" ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" if test "x$ac_cv_header_zlib_h" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gzgets in -lz" >&5 $as_echo_n "checking for gzgets in -lz... " >&6; } if ${ac_cv_lib_z_gzgets+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gzgets (); int main () { return gzgets (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_z_gzgets=yes else ac_cv_lib_z_gzgets=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzgets" >&5 $as_echo "$ac_cv_lib_z_gzgets" >&6; } if test "x$ac_cv_lib_z_gzgets" = xyes; then : $as_echo "#define HAVE_LIBZ 1" >>confdefs.h LIBZ="-lz" LIBS="$LIBS -lz" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateCopy in -lz" >&5 $as_echo_n "checking for inflateCopy in -lz... " >&6; } if ${ac_cv_lib_z_inflateCopy+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inflateCopy (); int main () { return inflateCopy (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_z_inflateCopy=yes else ac_cv_lib_z_inflateCopy=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateCopy" >&5 $as_echo "$ac_cv_lib_z_inflateCopy" >&6; } if test "x$ac_cv_lib_z_inflateCopy" = xyes; then : $as_echo "#define HAVE_INFLATECOPY 1" >>confdefs.h fi if test "x$GZIP" != z; then INSTALL_GZIP="-z" fi fi fi case $uname in Darwin* | *BSD*) ARFLAGS="-rcv" ;; *) ARFLAGS="crvs" ;; esac IPPTRANSFORM_BIN="" IPPTRANSFORM_HTML="" IPPTRANSFORM_MAN="" case $uname in Darwin*) LIBS="-framework SystemConfiguration -framework ApplicationServices -framework CoreFoundation -framework Security $LIBS" ac_fn_c_check_header_mongrel "$LINENO" "ApplicationServices/ApplicationServices.h" "ac_cv_header_ApplicationServices_ApplicationServices_h" "$ac_includes_default" if test "x$ac_cv_header_ApplicationServices_ApplicationServices_h" = xyes; then : $as_echo "#define HAVE_APPLICATIONSERVICES_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "CoreFoundation/CoreFoundation.h" "ac_cv_header_CoreFoundation_CoreFoundation_h" "$ac_includes_default" if test "x$ac_cv_header_CoreFoundation_CoreFoundation_h" = xyes; then : $as_echo "#define HAVE_COREFOUNDATION_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "CoreFoundation/CFPriv.h" "ac_cv_header_CoreFoundation_CFPriv_h" "$ac_includes_default" if test "x$ac_cv_header_CoreFoundation_CFPriv_h" = xyes; then : $as_echo "#define HAVE_CFPRIV_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "CoreFoundation/CFBundlePriv.h" "ac_cv_header_CoreFoundation_CFBundlePriv_h" "$ac_includes_default" if test "x$ac_cv_header_CoreFoundation_CFBundlePriv_h" = xyes; then : $as_echo "#define HAVE_CFBUNDLEPRIV_H 1" >>confdefs.h fi IPPTRANSFORM_BIN="ipptransform" IPPTRANSFORM_HTML="ipptransform.html" IPPTRANSFORM_MAN="ipptransform.man" ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing FT_Init_FreeType" >&5 $as_echo_n "checking for library containing FT_Init_FreeType... " >&6; } if ${ac_cv_search_FT_Init_FreeType+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char FT_Init_FreeType (); int main () { return FT_Init_FreeType (); ; return 0; } _ACEOF for ac_lib in '' mupdfthird freetype; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_FT_Init_FreeType=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_FT_Init_FreeType+:} false; then : break fi done if ${ac_cv_search_FT_Init_FreeType+:} false; then : else ac_cv_search_FT_Init_FreeType=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_FT_Init_FreeType" >&5 $as_echo "$ac_cv_search_FT_Init_FreeType" >&6; } ac_res=$ac_cv_search_FT_Init_FreeType if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing jpeg_destroy_decompress" >&5 $as_echo_n "checking for library containing jpeg_destroy_decompress... " >&6; } if ${ac_cv_search_jpeg_destroy_decompress+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char jpeg_destroy_decompress (); int main () { return jpeg_destroy_decompress (); ; return 0; } _ACEOF for ac_lib in '' mupdfthird jpeg; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_jpeg_destroy_decompress=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_jpeg_destroy_decompress+:} false; then : break fi done if ${ac_cv_search_jpeg_destroy_decompress+:} false; then : else ac_cv_search_jpeg_destroy_decompress=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_jpeg_destroy_decompress" >&5 $as_echo "$ac_cv_search_jpeg_destroy_decompress" >&6; } ac_res=$ac_cv_search_jpeg_destroy_decompress if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fz_drop_document in -lmupdf" >&5 $as_echo_n "checking for fz_drop_document in -lmupdf... " >&6; } if ${ac_cv_lib_mupdf_fz_drop_document+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lmupdf $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char fz_drop_document (); int main () { return fz_drop_document (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_mupdf_fz_drop_document=yes else ac_cv_lib_mupdf_fz_drop_document=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mupdf_fz_drop_document" >&5 $as_echo "$ac_cv_lib_mupdf_fz_drop_document" >&6; } if test "x$ac_cv_lib_mupdf_fz_drop_document" = xyes; then : $as_echo "#define HAVE_MUPDF 1" >>confdefs.h LIBS="-lmupdf $LIBS" IPPTRANSFORM_BIN="ipptransform" IPPTRANSFORM_HTML="ipptransform.html" IPPTRANSFORM_MAN="ipptransform.man" fi ;; esac # 3D support IPPTRANSFORM3D_BIN="" IPPTRANSFORM3D_HTML="" IPPTRANSFORM3D_MAN="" SAVEPATH="$PATH" PATH="$PATH:/Applications/Cura/Cura.app/Contents/Resources:/Applications/Cura.app/Contents/MacOS" # Extract the first word of "CuraEngine", so it can be a program name with args. set dummy CuraEngine; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_CURAENGINE+:} false; then : $as_echo_n "(cached) " >&6 else case $CURAENGINE in [\\/]* | ?:[\\/]*) ac_cv_path_CURAENGINE="$CURAENGINE" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_CURAENGINE="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi CURAENGINE=$ac_cv_path_CURAENGINE if test -n "$CURAENGINE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CURAENGINE" >&5 $as_echo "$CURAENGINE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi PATH="$SAVEPATH" if test "x$CURAENGINE" != x; then IPPTRANSFORM3D_BIN="ipptransform3d" IPPTRANSFORM3D_HTML="ipptransform3d.html" IPPTRANSFORM3D_MAN="ipptransform3d.man" cat >>confdefs.h <<_ACEOF #define CURAENGINE "$CURAENGINE" _ACEOF fi INSTALL_STRIP="" OPTIM="" # Check whether --with-optim was given. if test "${with_optim+set}" = set; then : withval=$with_optim; fi # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; fi # Check whether --enable-debug_guards was given. if test "${enable_debug_guards+set}" = set; then : enableval=$enable_debug_guards; fi # Check whether --enable-debug_printfs was given. if test "${enable_debug_printfs+set}" = set; then : enableval=$enable_debug_printfs; fi # Check whether --enable-unit_tests was given. if test "${enable_unit_tests+set}" = set; then : enableval=$enable_unit_tests; fi if test x$enable_debug != xno; then OPTIM="-g" else INSTALL_STRIP="-s" fi if test x$enable_debug_printfs != xno; then CFLAGS="$CFLAGS -DDEBUG" CXXFLAGS="$CXXFLAGS -DDEBUG" fi if test x$enable_debug_guards = xyes; then CFLAGS="$CFLAGS -DDEBUG_GUARDS" CXXFLAGS="$CXXFLAGS -DDEBUG_GUARDS" fi if test x$enable_unit_tests = xyes; then UNITTESTS="unittests" else UNITTESTS="" fi # Check whether --with-archflags was given. if test "${with_archflags+set}" = set; then : withval=$with_archflags; fi # Check whether --with-ldarchflags was given. if test "${with_ldarchflags+set}" = set; then : withval=$with_ldarchflags; fi if test -z "$with_archflags"; then ARCHFLAGS="" else ARCHFLAGS="$with_archflags" fi if test -z "$with_ldarchflags"; then if test "$uname" = Darwin; then # Only create Intel programs by default LDARCHFLAGS="`echo $ARCHFLAGS | sed -e '1,$s/-arch ppc64//'`" else LDARCHFLAGS="$ARCHFLAGS" fi else LDARCHFLAGS="$with_ldarchflags" fi # Check whether --enable-relro was given. if test "${enable_relro+set}" = set; then : enableval=$enable_relro; fi CXXLIBS="${CXXLIBS:=}" PIEFLAGS="" RELROFLAGS="" if test -n "$GCC"; then # Add GCC-specific compiler options... if test -z "$OPTIM"; then if test "x$with_optim" = x; then # Default to optimize-for-size and debug OPTIM="-Os -g" else OPTIM="$with_optim $OPTIM" fi fi # The -fstack-protector option is available with some versions of # GCC and adds "stack canaries" which detect when the return address # has been overwritten, preventing many types of exploit attacks. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -fstack-protector" >&5 $as_echo_n "checking whether compiler supports -fstack-protector... " >&6; } OLDCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fstack-protector" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : OPTIM="$OPTIM -fstack-protector" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$OLDCFLAGS" # The -fPIE option is available with some versions of GCC and # adds randomization of addresses, which avoids another class of # exploits that depend on a fixed address for common functions. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -fPIE" >&5 $as_echo_n "checking whether compiler supports -fPIE... " >&6; } OLDCFLAGS="$CFLAGS" case "$uname" in Darwin*) CFLAGS="$CFLAGS -fPIE -Wl,-pie" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : PIEFLAGS="-fPIE -Wl,-pie" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ;; *) CFLAGS="$CFLAGS -fPIE -pie" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : PIEFLAGS="-fPIE -pie" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ;; esac CFLAGS="$OLDCFLAGS" if test "x$with_optim" = x; then # Add useful warning options for tracking down problems... OPTIM="-Wall -Wno-format-y2k -Wunused $OPTIM" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -Wno-unused-result" >&5 $as_echo_n "checking whether compiler supports -Wno-unused-result... " >&6; } OLDCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror -Wno-unused-result" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : OPTIM="$OPTIM -Wno-unused-result" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$OLDCFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -Wsign-conversion" >&5 $as_echo_n "checking whether compiler supports -Wsign-conversion... " >&6; } OLDCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror -Wsign-conversion" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : OPTIM="$OPTIM -Wsign-conversion" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$OLDCFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -Wno-tautological-compare" >&5 $as_echo_n "checking whether compiler supports -Wno-tautological-compare... " >&6; } OLDCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror -Wno-tautological-compare" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : OPTIM="$OPTIM -Wno-tautological-compare" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$OLDCFLAGS" # Error out on any warnings... #OPTIM="-Werror $OPTIM" fi case "$uname" in Darwin*) # -D_FORTIFY_SOURCE=2 adds additional object size # checking, basically wrapping all string functions # with buffer-limited ones. Not strictly needed for # CUPS since we already use buffer-limited calls, but # this will catch any additions that are broken. CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" ;; Linux*) # The -z relro option is provided by the Linux linker command to # make relocatable data read-only. if test x$enable_relro = xyes; then RELROFLAGS="-Wl,-z,relro,-z,now" fi ;; esac else # Add vendor-specific compiler options... case $uname in SunOS*) # Solaris if test -z "$OPTIM"; then if test "x$with_optim" = x; then OPTIM="-xO2" else OPTIM="$with_optim $OPTIM" fi fi ;; *) # Running some other operating system... echo "Building with default compiler optimizations; use the" echo "--with-optim option to override these." ;; esac fi # Add general compiler options per platform... case $uname in Linux*) # glibc 2.8 and higher breaks peer credentials unless you # define _GNU_SOURCE... OPTIM="$OPTIM -D_GNU_SOURCE" ;; esac ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" " #include #include #include #include #include " if test "x$ac_cv_header_resolv_h" = xyes; then : $as_echo "#define HAVE_RESOLV_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing socket" >&5 $as_echo_n "checking for library containing socket... " >&6; } if ${ac_cv_search_socket+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char socket (); int main () { return socket (); ; return 0; } _ACEOF for ac_lib in '' socket; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_socket=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_socket+:} false; then : break fi done if ${ac_cv_search_socket+:} false; then : else ac_cv_search_socket=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_socket" >&5 $as_echo "$ac_cv_search_socket" >&6; } ac_res=$ac_cv_search_socket if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyaddr" >&5 $as_echo_n "checking for library containing gethostbyaddr... " >&6; } if ${ac_cv_search_gethostbyaddr+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyaddr (); int main () { return gethostbyaddr (); ; return 0; } _ACEOF for ac_lib in '' nsl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_gethostbyaddr=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_gethostbyaddr+:} false; then : break fi done if ${ac_cv_search_gethostbyaddr+:} false; then : else ac_cv_search_gethostbyaddr=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyaddr" >&5 $as_echo "$ac_cv_search_gethostbyaddr" >&6; } ac_res=$ac_cv_search_gethostbyaddr if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing getifaddrs" >&5 $as_echo_n "checking for library containing getifaddrs... " >&6; } if ${ac_cv_search_getifaddrs+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char getifaddrs (); int main () { return getifaddrs (); ; return 0; } _ACEOF for ac_lib in '' nsl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_getifaddrs=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_getifaddrs+:} false; then : break fi done if ${ac_cv_search_getifaddrs+:} false; then : else ac_cv_search_getifaddrs=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_getifaddrs" >&5 $as_echo "$ac_cv_search_getifaddrs" >&6; } ac_res=$ac_cv_search_getifaddrs if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_GETIFADDRS 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing hstrerror" >&5 $as_echo_n "checking for library containing hstrerror... " >&6; } if ${ac_cv_search_hstrerror+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char hstrerror (); int main () { return hstrerror (); ; return 0; } _ACEOF for ac_lib in '' nsl socket resolv; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_hstrerror=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_hstrerror+:} false; then : break fi done if ${ac_cv_search_hstrerror+:} false; then : else ac_cv_search_hstrerror=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_hstrerror" >&5 $as_echo "$ac_cv_search_hstrerror" >&6; } ac_res=$ac_cv_search_hstrerror if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_HSTRERROR 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing rresvport_af" >&5 $as_echo_n "checking for library containing rresvport_af... " >&6; } if ${ac_cv_search_rresvport_af+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char rresvport_af (); int main () { return rresvport_af (); ; return 0; } _ACEOF for ac_lib in '' nsl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_rresvport_af=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_rresvport_af+:} false; then : break fi done if ${ac_cv_search_rresvport_af+:} false; then : else ac_cv_search_rresvport_af=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_rresvport_af" >&5 $as_echo "$ac_cv_search_rresvport_af" >&6; } ac_res=$ac_cv_search_rresvport_af if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_RRESVPORT_AF 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing __res_init" >&5 $as_echo_n "checking for library containing __res_init... " >&6; } if ${ac_cv_search___res_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char __res_init (); int main () { return __res_init (); ; return 0; } _ACEOF for ac_lib in '' resolv bind; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search___res_init=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search___res_init+:} false; then : break fi done if ${ac_cv_search___res_init+:} false; then : else ac_cv_search___res_init=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search___res_init" >&5 $as_echo "$ac_cv_search___res_init" >&6; } ac_res=$ac_cv_search___res_init if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_RES_INIT 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing res_9_init" >&5 $as_echo_n "checking for library containing res_9_init... " >&6; } if ${ac_cv_search_res_9_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char res_9_init (); int main () { return res_9_init (); ; return 0; } _ACEOF for ac_lib in '' resolv bind; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_res_9_init=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_res_9_init+:} false; then : break fi done if ${ac_cv_search_res_9_init+:} false; then : else ac_cv_search_res_9_init=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_res_9_init" >&5 $as_echo "$ac_cv_search_res_9_init" >&6; } ac_res=$ac_cv_search_res_9_init if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_RES_INIT 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing res_init" >&5 $as_echo_n "checking for library containing res_init... " >&6; } if ${ac_cv_search_res_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char res_init (); int main () { return res_init (); ; return 0; } _ACEOF for ac_lib in '' resolv bind; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_res_init=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_res_init+:} false; then : break fi done if ${ac_cv_search_res_init+:} false; then : else ac_cv_search_res_init=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_res_init" >&5 $as_echo "$ac_cv_search_res_init" >&6; } ac_res=$ac_cv_search_res_init if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_RES_INIT 1" >>confdefs.h fi fi fi # Tru64 5.1b leaks file descriptors with these functions; disable until # we can come up with a test for this... if test "$uname" != "OSF1"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing getaddrinfo" >&5 $as_echo_n "checking for library containing getaddrinfo... " >&6; } if ${ac_cv_search_getaddrinfo+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char getaddrinfo (); int main () { return getaddrinfo (); ; return 0; } _ACEOF for ac_lib in '' nsl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_getaddrinfo=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_getaddrinfo+:} false; then : break fi done if ${ac_cv_search_getaddrinfo+:} false; then : else ac_cv_search_getaddrinfo=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_getaddrinfo" >&5 $as_echo "$ac_cv_search_getaddrinfo" >&6; } ac_res=$ac_cv_search_getaddrinfo if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_GETADDRINFO 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing getnameinfo" >&5 $as_echo_n "checking for library containing getnameinfo... " >&6; } if ${ac_cv_search_getnameinfo+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char getnameinfo (); int main () { return getnameinfo (); ; return 0; } _ACEOF for ac_lib in '' nsl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_getnameinfo=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_getnameinfo+:} false; then : break fi done if ${ac_cv_search_getnameinfo+:} false; then : else ac_cv_search_getnameinfo=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_getnameinfo" >&5 $as_echo "$ac_cv_search_getnameinfo" >&6; } ac_res=$ac_cv_search_getnameinfo if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_GETNAMEINFO 1" >>confdefs.h fi fi ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" "#include " if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes; then : fi ac_fn_c_check_header_mongrel "$LINENO" "sys/sockio.h" "ac_cv_header_sys_sockio_h" "$ac_includes_default" if test "x$ac_cv_header_sys_sockio_h" = xyes; then : $as_echo "#define HAVE_SYS_SOCKIO_H 1" >>confdefs.h fi CUPS_DEFAULT_DOMAINSOCKET="" # Check whether --with-domainsocket was given. if test "${with_domainsocket+set}" = set; then : withval=$with_domainsocket; default_domainsocket="$withval" else default_domainsocket="" fi if test x$enable_domainsocket != xno -a x$default_domainsocket != xno; then if test "x$default_domainsocket" = x; then case "$uname" in Darwin*) # Darwin and macOS do their own thing... CUPS_DEFAULT_DOMAINSOCKET="$localstatedir/run/cupsd" ;; *) # All others use FHS standard... CUPS_DEFAULT_DOMAINSOCKET="$CUPS_STATEDIR/cups.sock" ;; esac else CUPS_DEFAULT_DOMAINSOCKET="$default_domainsocket" fi CUPS_LISTEN_DOMAINSOCKET="Listen $CUPS_DEFAULT_DOMAINSOCKET" cat >>confdefs.h <<_ACEOF #define CUPS_DEFAULT_DOMAINSOCKET "$CUPS_DEFAULT_DOMAINSOCKET" _ACEOF else CUPS_LISTEN_DOMAINSOCKET="" fi ac_fn_c_check_func "$LINENO" "poll" "ac_cv_func_poll" if test "x$ac_cv_func_poll" = xyes; then : $as_echo "#define HAVE_POLL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "epoll_create" "ac_cv_func_epoll_create" if test "x$ac_cv_func_epoll_create" = xyes; then : $as_echo "#define HAVE_EPOLL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "kqueue" "ac_cv_func_kqueue" if test "x$ac_cv_func_kqueue" = xyes; then : $as_echo "#define HAVE_KQUEUE 1" >>confdefs.h fi # Check whether --enable-threads was given. if test "${enable_threads+set}" = set; then : enableval=$enable_threads; fi have_pthread=no PTHREAD_FLAGS="" if test "x$enable_threads" != xno; then ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" if test "x$ac_cv_header_pthread_h" = xyes; then : $as_echo "#define HAVE_PTHREAD_H 1" >>confdefs.h fi if test x$ac_cv_header_pthread_h = xyes; then for flag in -lpthreads -lpthread -pthread; do { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create using $flag" >&5 $as_echo_n "checking for pthread_create using $flag... " >&6; } SAVELIBS="$LIBS" LIBS="$flag $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_create(0, 0, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : have_pthread=yes else LIBS="$SAVELIBS" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_pthread" >&5 $as_echo "$have_pthread" >&6; } if test $have_pthread = yes; then PTHREAD_FLAGS="-D_THREAD_SAFE -D_REENTRANT" # Solaris requires -D_POSIX_PTHREAD_SEMANTICS to # be POSIX-compliant... :( if test $uname = SunOS; then PTHREAD_FLAGS="$PTHREAD_FLAGS -D_POSIX_PTHREAD_SEMANTICS" fi break fi done fi fi # Check whether --enable-ssl was given. if test "${enable_ssl+set}" = set; then : enableval=$enable_ssl; fi # Check whether --enable-cdsassl was given. if test "${enable_cdsassl+set}" = set; then : enableval=$enable_cdsassl; fi # Check whether --enable-gnutls was given. if test "${enable_gnutls+set}" = set; then : enableval=$enable_gnutls; fi SSLFLAGS="" SSLLIBS="" have_ssl=0 CUPS_SERVERKEYCHAIN="" if test x$enable_ssl != xno; then if test $have_ssl = 0 -a "x$enable_cdsassl" != "xno"; then if test $uname = Darwin; then ac_fn_c_check_header_mongrel "$LINENO" "Security/SecureTransport.h" "ac_cv_header_Security_SecureTransport_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecureTransport_h" = xyes; then : have_ssl=1 $as_echo "#define HAVE_SSL 1" >>confdefs.h $as_echo "#define HAVE_CDSASSL 1" >>confdefs.h CUPS_SERVERKEYCHAIN="/Library/Keychains/System.keychain" ac_fn_c_check_header_mongrel "$LINENO" "Security/SecureTransportPriv.h" "ac_cv_header_Security_SecureTransportPriv_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecureTransportPriv_h" = xyes; then : $as_echo "#define HAVE_SECURETRANSPORTPRIV_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "Security/SecCertificate.h" "ac_cv_header_Security_SecCertificate_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecCertificate_h" = xyes; then : $as_echo "#define HAVE_SECCERTIFICATE_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "Security/SecItem.h" "ac_cv_header_Security_SecItem_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecItem_h" = xyes; then : $as_echo "#define HAVE_SECITEM_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "Security/SecItemPriv.h" "ac_cv_header_Security_SecItemPriv_h" "#include " if test "x$ac_cv_header_Security_SecItemPriv_h" = xyes; then : $as_echo "#define HAVE_SECITEMPRIV_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "Security/SecPolicy.h" "ac_cv_header_Security_SecPolicy_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecPolicy_h" = xyes; then : $as_echo "#define HAVE_SECPOLICY_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "Security/SecPolicyPriv.h" "ac_cv_header_Security_SecPolicyPriv_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecPolicyPriv_h" = xyes; then : $as_echo "#define HAVE_SECPOLICYPRIV_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "Security/SecBasePriv.h" "ac_cv_header_Security_SecBasePriv_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecBasePriv_h" = xyes; then : $as_echo "#define HAVE_SECBASEPRIV_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "Security/SecIdentitySearchPriv.h" "ac_cv_header_Security_SecIdentitySearchPriv_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecIdentitySearchPriv_h" = xyes; then : $as_echo "#define HAVE_SECIDENTITYSEARCHPRIV_H 1" >>confdefs.h fi $as_echo "#define HAVE_CSSMERRORSTRING 1" >>confdefs.h $as_echo "#define HAVE_SECKEYCHAINOPEN 1" >>confdefs.h fi if test $uversion -ge 150; then $as_echo "#define HAVE_SSLSETENABLEDCIPHERS 1" >>confdefs.h fi fi fi if test $have_ssl = 0 -a "x$enable_gnutls" != "xno" -a "x$PKGCONFIG" != x; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}libgnutls-config", so it can be a program name with args. set dummy ${ac_tool_prefix}libgnutls-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_LIBGNUTLSCONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $LIBGNUTLSCONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_LIBGNUTLSCONFIG="$LIBGNUTLSCONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_LIBGNUTLSCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi LIBGNUTLSCONFIG=$ac_cv_path_LIBGNUTLSCONFIG if test -n "$LIBGNUTLSCONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBGNUTLSCONFIG" >&5 $as_echo "$LIBGNUTLSCONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_LIBGNUTLSCONFIG"; then ac_pt_LIBGNUTLSCONFIG=$LIBGNUTLSCONFIG # Extract the first word of "libgnutls-config", so it can be a program name with args. set dummy libgnutls-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_LIBGNUTLSCONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_LIBGNUTLSCONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_LIBGNUTLSCONFIG="$ac_pt_LIBGNUTLSCONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_LIBGNUTLSCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_LIBGNUTLSCONFIG=$ac_cv_path_ac_pt_LIBGNUTLSCONFIG if test -n "$ac_pt_LIBGNUTLSCONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LIBGNUTLSCONFIG" >&5 $as_echo "$ac_pt_LIBGNUTLSCONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_LIBGNUTLSCONFIG" = x; then LIBGNUTLSCONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIBGNUTLSCONFIG=$ac_pt_LIBGNUTLSCONFIG fi else LIBGNUTLSCONFIG="$ac_cv_path_LIBGNUTLSCONFIG" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}libgcrypt-config", so it can be a program name with args. set dummy ${ac_tool_prefix}libgcrypt-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_LIBGCRYPTCONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $LIBGCRYPTCONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_LIBGCRYPTCONFIG="$LIBGCRYPTCONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_LIBGCRYPTCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi LIBGCRYPTCONFIG=$ac_cv_path_LIBGCRYPTCONFIG if test -n "$LIBGCRYPTCONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBGCRYPTCONFIG" >&5 $as_echo "$LIBGCRYPTCONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_LIBGCRYPTCONFIG"; then ac_pt_LIBGCRYPTCONFIG=$LIBGCRYPTCONFIG # Extract the first word of "libgcrypt-config", so it can be a program name with args. set dummy libgcrypt-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_LIBGCRYPTCONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_LIBGCRYPTCONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_LIBGCRYPTCONFIG="$ac_pt_LIBGCRYPTCONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_LIBGCRYPTCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_LIBGCRYPTCONFIG=$ac_cv_path_ac_pt_LIBGCRYPTCONFIG if test -n "$ac_pt_LIBGCRYPTCONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LIBGCRYPTCONFIG" >&5 $as_echo "$ac_pt_LIBGCRYPTCONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_LIBGCRYPTCONFIG" = x; then LIBGCRYPTCONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIBGCRYPTCONFIG=$ac_pt_LIBGCRYPTCONFIG fi else LIBGCRYPTCONFIG="$ac_cv_path_LIBGCRYPTCONFIG" fi if $PKGCONFIG --exists gnutls; then have_ssl=1 SSLLIBS=`$PKGCONFIG --libs gnutls` SSLFLAGS=`$PKGCONFIG --cflags gnutls` $as_echo "#define HAVE_SSL 1" >>confdefs.h $as_echo "#define HAVE_GNUTLS 1" >>confdefs.h elif test "x$LIBGNUTLSCONFIG" != x; then have_ssl=1 SSLLIBS=`$LIBGNUTLSCONFIG --libs` SSLFLAGS=`$LIBGNUTLSCONFIG --cflags` $as_echo "#define HAVE_SSL 1" >>confdefs.h $as_echo "#define HAVE_GNUTLS 1" >>confdefs.h fi if test $have_ssl = 1; then CUPS_SERVERKEYCHAIN="ssl" SAVELIBS="$LIBS" LIBS="$LIBS $SSLLIBS" ac_fn_c_check_func "$LINENO" "gnutls_transport_set_pull_timeout_function" "ac_cv_func_gnutls_transport_set_pull_timeout_function" if test "x$ac_cv_func_gnutls_transport_set_pull_timeout_function" = xyes; then : $as_echo "#define HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "gnutls_priority_set_direct" "ac_cv_func_gnutls_priority_set_direct" if test "x$ac_cv_func_gnutls_priority_set_direct" = xyes; then : $as_echo "#define HAVE_GNUTLS_PRIORITY_SET_DIRECT 1" >>confdefs.h fi LIBS="$SAVELIBS" fi fi fi IPPALIASES="http" if test $have_ssl = 1; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using SSLLIBS=\"$SSLLIBS\"" >&5 $as_echo " Using SSLLIBS=\"$SSLLIBS\"" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using SSLFLAGS=\"$SSLFLAGS\"" >&5 $as_echo " Using SSLFLAGS=\"$SSLFLAGS\"" >&6; } IPPALIASES="http https ipps" elif test x$enable_cdsa = xyes -o x$enable_gnutls = xyes; then as_fn_error $? "Unable to enable SSL support." "$LINENO" 5 fi EXPORT_SSLLIBS="$SSLLIBS" # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi LARGEFILE="" if test x$enable_largefile != xno; then LARGEFILE="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE" if test x$ac_cv_sys_large_files = x1; then LARGEFILE="$LARGEFILE -D_LARGE_FILES" fi if test x$ac_cv_sys_file_offset_bits = x64; then LARGEFILE="$LARGEFILE -D_FILE_OFFSET_BITS=64" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long long int" >&5 $as_echo_n "checking for long long int... " >&6; } if ${ac_cv_c_long_long+:} false; then : $as_echo_n "(cached) " >&6 else if test "$GCC" = yes; then ac_cv_c_long_long=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { long long int i; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_long_long=yes else ac_cv_c_long_long=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_long_long" >&5 $as_echo "$ac_cv_c_long_long" >&6; } if test $ac_cv_c_long_long = yes; then $as_echo "#define HAVE_LONG_LONG 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strtoll" "ac_cv_func_strtoll" if test "x$ac_cv_func_strtoll" = xyes; then : $as_echo "#define HAVE_STRTOLL 1" >>confdefs.h fi # Check whether --enable-avahi was given. if test "${enable_avahi+set}" = set; then : enableval=$enable_avahi; fi # Check whether --enable-dnssd was given. if test "${enable_dnssd+set}" = set; then : enableval=$enable_dnssd; fi # Check whether --with-dnssd-libs was given. if test "${with_dnssd_libs+set}" = set; then : withval=$with_dnssd_libs; LDFLAGS="-L$withval $LDFLAGS" DSOFLAGS="-L$withval $DSOFLAGS" fi # Check whether --with-dnssd-includes was given. if test "${with_dnssd_includes+set}" = set; then : withval=$with_dnssd_includes; CFLAGS="-I$withval $CFLAGS" CPPFLAGS="-I$withval $CPPFLAGS" fi DNSSDLIBS="" IPPFIND_BIN="" IPPFIND_HTML="" IPPFIND_MAN="" if test "x$PKGCONFIG" != x -a x$enable_avahi != xno -a x$uname != xDarwin; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Avahi" >&5 $as_echo_n "checking for Avahi... " >&6; } if $PKGCONFIG --exists avahi-client; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } CFLAGS="$CFLAGS `$PKGCONFIG --cflags avahi-client`" DNSSDLIBS="`$PKGCONFIG --libs avahi-client`" IPPFIND_BIN="ippfind" IPPFIND_HTML="ippfind.html" IPPFIND_MAN="ippfind.man" $as_echo "#define HAVE_AVAHI 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test "x$DNSSD_BACKEND" = x -a x$enable_dnssd != xno; then ac_fn_c_check_header_mongrel "$LINENO" "dns_sd.h" "ac_cv_header_dns_sd_h" "$ac_includes_default" if test "x$ac_cv_header_dns_sd_h" = xyes; then : case "$uname" in Darwin*) # Darwin and macOS... $as_echo "#define HAVE_DNSSD 1" >>confdefs.h DNSSDLIBS="-framework CoreFoundation -framework SystemConfiguration" IPPFIND_BIN="ippfind" IPPFIND_HTML="ippfind.html" IPPFIND_MAN="ippfind.man" ;; *) # All others... { $as_echo "$as_me:${as_lineno-$LINENO}: checking for current version of dns_sd library" >&5 $as_echo_n "checking for current version of dns_sd library... " >&6; } SAVELIBS="$LIBS" LIBS="$LIBS -ldns_sd" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int constant = kDNSServiceFlagsShareConnection; unsigned char txtRecord[100]; uint8_t valueLen; TXTRecordGetValuePtr(sizeof(txtRecord), txtRecord, "value", &valueLen); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_DNSSD 1" >>confdefs.h DNSSDLIBS="-ldns_sd" IPPFIND_BIN="ippfind" IPPFIND_HTML="ippfind.html" IPPFIND_MAN="ippfind.man" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext LIBS="$SAVELIBS" ;; esac fi fi IPP="ipp" # Check whether --with-name-prefix was given. if test "${with_name_prefix+set}" = set; then : withval=$with_name_prefix; IPP="$withval" fi ac_config_files="$ac_config_files Makedefs" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by IPPSAMPLE $as_me 1.0b1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to . IPPSAMPLE home page: ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ IPPSAMPLE config.status 1.0b1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makedefs") CONFIG_FILES="$CONFIG_FILES Makedefs" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi ippsample/NOTICE0000644000175000017500000000277013240604116012451 0ustar tilltillIPP Sample Code Copyright © 2014-2018 by the IEEE-ISTO Printer Working Group. Copyright © 2007-2018 by Apple Inc. Copyright © 1997-2007 by Easy Software Products. CUPS and the CUPS logo are trademarks of Apple Inc. The MD5 Digest code is Copyright 1999 Aladdin Enterprises. The Kerberos support code ("KSC") is copyright 2006 by Jelmer Vernooij and is provided 'as-is', without any express or implied warranty. In no event will the author or Apple Inc. be held liable for any damages arising from the use of the KSC. Sources files containing KSC have the following text at the top of each source file: This file contains Kerberos support code, copyright 2006 by Jelmer Vernooij. The KSC copyright and license apply only to Kerberos-related feature code in CUPS. Such code is typically conditionally compiled based on the present of the HAVE_GSSAPI preprocessor definition. Permission is granted to anyone to use the KSC for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of the KSC must not be misrepresented; you must not claim that you wrote the original software. If you use the KSC in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. ippsample/PI.md0000644000175000017500000000300413240604116012366 0ustar tilltill# Raspberry Pi Build/Usage Instructions All of this sample code will build on a Raspberry Pi, which can then be used as an inexpensive print server or as part of an automated test framework. ## Prerequisites Run the following command to install the core software you'll need to build and use the ippsample code: sudo apt-get install libnss-mdns avahi-daemon avahi-utils \ libavahi-client-dev libgnutls28-dev zlib1g-dev If you want to support local conversions of PDF and JPEG files to Apple/PWG Raster or HP PCL, you'll also need version 1.11 of the MuPDF software and *not* the much older version that has been packaged for Raspbian. You can download the MuPDF 1.11 software from: http://www.mupdf.com For 3D support you'll need CuraEngine (part of Cura). The easiest way to build this is to head over to the Ultimaker Cura-build project: https://github.com/Ultimaker/cura-build and mostly follow the Ubuntu/Linux instructions, doing a `make install` at the end instead of `make package`. ## Building the IPP Sample Code If you haven't already done so, you can download the latested IPP sample sources with Git using: git clone https://github.com/istopwg/ippsample.git ippsample Then, from the ippsample source directory, run the following commands to build and install everything: ./configure make sudo make install ## Using the IPP Server The `sample-configs` directory contains sample configuration directories for `ippserver` to do different things. > Work in progress here... ippsample/server/0000755000175000017500000000000013240604116013045 5ustar tilltillippsample/server/printer-png.h0000644000175000017500000010433113240604116015465 0ustar tilltillstatic const unsigned char printer_png[] = { 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x08,0x06,0x00,0x00,0x00,0xc3,0x3e,0x61, 0xcb,0x00,0x00,0x04,0x24,0x69,0x43,0x43,0x50,0x49,0x43,0x43,0x20,0x50,0x72,0x6f, 0x66,0x69,0x6c,0x65,0x00,0x00,0x38,0x11,0x85,0x55,0xdf,0x6f,0xdb,0x54,0x14,0x3e, 0x89,0x6f,0x52,0xa4,0x16,0x3f,0x20,0x58,0x47,0x87,0x8a,0xc5,0xaf,0x55,0x53,0x5b, 0xb9,0x1b,0x1a,0xad,0xc6,0x06,0x49,0x93,0xa5,0xed,0x4a,0x16,0xa5,0xe9,0xd8,0x2a, 0x24,0xe4,0x3a,0x37,0x89,0xa9,0x1b,0x07,0xdb,0xe9,0xb6,0xaa,0x4f,0x7b,0x81,0x37, 0x06,0xfc,0x01,0x40,0xd9,0x03,0x0f,0x48,0x3c,0x21,0x0d,0x06,0x62,0x7b,0xd9,0xf6, 0xc0,0xb4,0x49,0x53,0x87,0x2a,0xaa,0x49,0x48,0x7b,0xe8,0xc4,0x0f,0x21,0x26,0xed, 0x05,0x55,0xe1,0xbb,0x76,0x62,0x27,0x53,0xc4,0x5c,0xf5,0xfa,0xcb,0x39,0xdf,0x39, 0xe7,0x3b,0xe7,0x5e,0xdb,0x44,0x3d,0x5f,0x69,0xb5,0x9a,0x19,0x55,0x88,0x96,0xab, 0xae,0x9d,0xcf,0x24,0x95,0x93,0xa7,0x16,0x94,0x9e,0x4d,0x8a,0xd2,0xb3,0xd4,0x4b, 0x03,0xd4,0xab,0xe9,0x4e,0x2d,0x91,0xcb,0xcd,0x12,0x2e,0xc1,0x15,0xf7,0xce,0xeb, 0xe1,0x1d,0x8a,0x08,0xcb,0xed,0x91,0xee,0xfe,0x4e,0xf6,0x23,0xbf,0x7a,0x8b,0xdc, 0xd1,0x89,0x22,0x4f,0xc0,0x6e,0x15,0x1d,0x7d,0x19,0xf8,0x0c,0x51,0xcc,0xd4,0x6b, 0xb6,0x4b,0x14,0xbf,0x07,0xfb,0xf8,0x69,0xb7,0x06,0xdc,0xf3,0x1c,0xf0,0xd3,0x36, 0x04,0x02,0xab,0x02,0x97,0x7d,0x9c,0x12,0x78,0xd1,0xc7,0x27,0x3d,0x4e,0x21,0x3f, 0x09,0x8e,0xd0,0x2a,0xeb,0x15,0xad,0x08,0xbc,0x06,0x3c,0xbc,0xd8,0x66,0x2f,0xb7, 0x61,0x5f,0x03,0x18,0xc8,0x93,0xe1,0x55,0x6e,0x1b,0xba,0x22,0x66,0x91,0xb3,0xad, 0x92,0x61,0x72,0xcf,0xe1,0x2f,0x8f,0x71,0xb7,0x31,0xff,0x0f,0x2e,0x9b,0x75,0xf4, 0xec,0x5d,0x83,0x58,0xfb,0x9c,0xa5,0xb9,0x63,0xb8,0x0f,0x89,0xde,0x2b,0xf6,0x54, 0xbe,0x89,0x3f,0xd7,0xb5,0xf4,0x1c,0xf0,0x4b,0xb0,0x5f,0xaf,0xb9,0x49,0x61,0x7f, 0x05,0xf8,0x8f,0xfa,0xd2,0x7c,0x02,0x78,0x1f,0x51,0xf4,0xa9,0x92,0x7d,0x74,0xde, 0xe7,0x47,0x5f,0x5f,0xad,0x14,0xde,0x06,0xde,0x05,0x7b,0xd1,0x70,0xa7,0x0b,0x4d, 0xfb,0x6a,0x75,0x31,0x7b,0x1c,0x18,0xb1,0xd1,0xf5,0x25,0xeb,0x98,0xc8,0x23,0x38, 0xd7,0x75,0x67,0x12,0xb3,0xa4,0x17,0x80,0xef,0x56,0xf8,0xb4,0xd8,0x63,0xe8,0x91, 0xa8,0xc8,0x53,0x69,0xe0,0x61,0xe0,0xc1,0x4a,0x7d,0xaa,0x99,0x5f,0x9a,0x71,0x56, 0xe6,0x84,0xdd,0xcb,0xb3,0x5a,0x99,0xcc,0x02,0x23,0x8f,0x64,0xbf,0xa7,0xcd,0xe4, 0x80,0x07,0x80,0x3f,0xb4,0xad,0xbc,0xa8,0x05,0xcd,0xd2,0x3a,0x37,0x33,0xa2,0x16, 0xf2,0x4b,0x57,0x6b,0x6e,0xae,0xa9,0x41,0xda,0xae,0x9a,0x59,0x51,0x0b,0xfd,0x32, 0x99,0x3b,0x5e,0x8f,0xc8,0x29,0x6d,0xbb,0x95,0xc2,0x94,0x1f,0xcb,0x0e,0xba,0x76, 0xa1,0x19,0xcb,0x16,0x4a,0xc6,0xd1,0xe9,0x26,0x7f,0xad,0x66,0x7a,0x67,0x11,0xda, 0xd8,0x05,0xbb,0x9e,0x17,0xda,0x90,0x9f,0xdd,0xd2,0xec,0x74,0x06,0x18,0x79,0xd8, 0x3f,0xbc,0x3a,0x2f,0xe6,0x06,0x1c,0xdb,0x5d,0xd4,0x52,0x62,0xb6,0xa3,0xc0,0x47, 0xe8,0x44,0x44,0x23,0x4e,0x16,0x2d,0x62,0xd5,0xa9,0x4a,0x3b,0xa4,0x50,0x9e,0x32, 0x94,0xc4,0xbd,0x46,0x36,0x3c,0x25,0x32,0xc8,0x84,0x85,0xc3,0xcb,0x61,0x31,0x22, 0x4f,0xd2,0x12,0x6c,0xdd,0x79,0x39,0x8f,0xe3,0xc7,0x84,0x8c,0xb2,0x17,0xbd,0x2d, 0xa2,0x51,0xa5,0x3b,0xc7,0xaf,0x70,0xbf,0xc9,0xb1,0x58,0x3f,0x53,0xd9,0x01,0xfc, 0x1f,0x62,0xb3,0xec,0x30,0x1b,0x67,0x13,0xa4,0xb0,0x37,0xd8,0x9b,0xec,0x08,0x4b, 0xc1,0x3a,0xc1,0x0e,0x05,0x0a,0x72,0x6d,0x3a,0x15,0x2a,0xd3,0x7d,0x28,0xf5,0xf3, 0xbc,0x4f,0x75,0x54,0x16,0x3a,0x4e,0x50,0xf2,0xfc,0x40,0x7d,0x28,0x88,0x51,0xce, 0xd9,0xef,0x1a,0xfa,0xcd,0x8f,0xfe,0x86,0x9a,0xb0,0x4b,0x2b,0xf4,0x23,0x4f,0xd0, 0x31,0x34,0x5b,0xed,0x13,0x20,0x07,0x13,0x68,0x75,0x37,0xd2,0x3e,0xa7,0x6b,0x6b, 0x3f,0xec,0x0e,0x3c,0xca,0x06,0xbb,0xf8,0xce,0xed,0xbe,0x6b,0x6b,0x74,0xfc,0x71, 0xf3,0x8d,0xdd,0x8b,0x6d,0xc7,0x36,0xb0,0x6e,0xc6,0xb6,0xc2,0xf8,0xd8,0xaf,0xb1, 0x2d,0xfc,0x6d,0x52,0x02,0x3b,0x60,0x7a,0x8a,0x96,0xa1,0xca,0xf0,0x76,0xc2,0x09, 0x78,0x23,0x1d,0x3d,0x5c,0x01,0xd3,0x25,0x0d,0xeb,0x6f,0xe0,0x59,0xd0,0xda,0x52, 0xda,0xb1,0xa3,0xa5,0xea,0xf9,0x81,0xd0,0x23,0x26,0xc1,0x3f,0xc8,0x3e,0xcc,0xd2, 0xb9,0xe1,0xd0,0xaa,0xfe,0xa2,0xfe,0xa9,0x6e,0xa8,0x5f,0xa8,0x17,0xd4,0xdf,0x3b, 0x6a,0x84,0x19,0x3b,0xa6,0x24,0x7d,0x2a,0x7d,0x2b,0xfd,0x28,0x7d,0x27,0x7d,0x2f, 0xfd,0x4c,0x8a,0x74,0x59,0xba,0x22,0xfd,0x24,0x5d,0x95,0xbe,0x91,0x2e,0x05,0x39, 0xbb,0xef,0xbd,0x9f,0x25,0xd8,0x7b,0xaf,0x5f,0x61,0x13,0xdd,0x8a,0x5d,0x68,0xd5, 0x6b,0x9f,0x35,0x27,0x53,0x4e,0xca,0x7b,0xe4,0x17,0xe5,0x94,0xfc,0xbc,0xfc,0xb2, 0x3c,0x1b,0xb0,0x14,0xb9,0x5f,0x1e,0x93,0xa7,0xe4,0xbd,0xf0,0xec,0x09,0xf6,0xcd, 0x0c,0xfd,0x1d,0xbd,0x18,0x74,0x0a,0xb3,0x6a,0x4d,0xb5,0x7b,0x2d,0xf1,0x04,0x18, 0x34,0x0f,0x25,0x06,0x9d,0x06,0xd7,0xc6,0x54,0xc5,0x84,0xab,0x74,0x16,0x59,0xdb, 0x9f,0x93,0xa6,0x52,0x36,0xc8,0xc6,0xd8,0xf4,0x23,0xa7,0x76,0x5c,0x9c,0xe5,0x96, 0x8a,0x78,0x3a,0x9e,0x8a,0x27,0x48,0x89,0xef,0x8b,0x4f,0xc4,0xc7,0xe2,0x33,0x02, 0xb7,0x9e,0xbc,0xf8,0x5e,0xf8,0x26,0xb0,0xa6,0x03,0xf5,0xfe,0x93,0x13,0x30,0x3a, 0x3a,0xe0,0x6d,0x2c,0x4c,0x25,0xc8,0x33,0xe2,0x9d,0x3a,0x71,0x56,0x45,0xf4,0x0a, 0x74,0x9b,0xd0,0xcd,0x5d,0x7e,0x06,0xdf,0x0e,0xa2,0x49,0xab,0x76,0xd6,0x36,0xca, 0x15,0x57,0xd9,0xaf,0xaa,0xaf,0x29,0x09,0x7c,0xca,0xb8,0x32,0x5d,0xd5,0x47,0x87, 0x15,0xcd,0x34,0x15,0xcf,0xe5,0x28,0x36,0x77,0xb8,0xbd,0xc2,0x8b,0xa3,0x24,0xbe, 0x83,0x22,0x8e,0xe8,0x41,0xde,0xfb,0xbe,0x45,0x76,0xdd,0x0c,0x6d,0xee,0x5b,0x44, 0x87,0xff,0xc2,0x3b,0xeb,0x56,0x68,0x5b,0xa8,0x13,0x7d,0xed,0x10,0xf5,0xbf,0x1a, 0xda,0x86,0xf0,0x4e,0x7c,0xe6,0x33,0xa2,0x8b,0x07,0xf5,0xba,0xbd,0xe2,0xe7,0xa3, 0x48,0xe4,0x06,0x91,0x53,0x3a,0xb0,0xdf,0xfb,0x1d,0xe9,0x4b,0xe2,0xdd,0x74,0xb7, 0xd1,0x78,0x80,0xf7,0x55,0xcf,0x27,0x44,0x3b,0x1f,0x37,0x1a,0xff,0xae,0x37,0x1a, 0x3b,0x5f,0x22,0xff,0x16,0xd1,0x65,0xf3,0x3f,0x59,0x00,0x71,0x78,0x6c,0x1b,0x2b, 0x13,0x00,0x00,0x02,0xd6,0x69,0x54,0x58,0x74,0x58,0x4d,0x4c,0x3a,0x63,0x6f,0x6d, 0x2e,0x61,0x64,0x6f,0x62,0x65,0x2e,0x78,0x6d,0x70,0x00,0x00,0x00,0x00,0x00,0x3c, 0x78,0x3a,0x78,0x6d,0x70,0x6d,0x65,0x74,0x61,0x20,0x78,0x6d,0x6c,0x6e,0x73,0x3a, 0x78,0x3d,0x22,0x61,0x64,0x6f,0x62,0x65,0x3a,0x6e,0x73,0x3a,0x6d,0x65,0x74,0x61, 0x2f,0x22,0x20,0x78,0x3a,0x78,0x6d,0x70,0x74,0x6b,0x3d,0x22,0x58,0x4d,0x50,0x20, 0x43,0x6f,0x72,0x65,0x20,0x35,0x2e,0x34,0x2e,0x30,0x22,0x3e,0x0a,0x20,0x20,0x20, 0x3c,0x72,0x64,0x66,0x3a,0x52,0x44,0x46,0x20,0x78,0x6d,0x6c,0x6e,0x73,0x3a,0x72, 0x64,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x77, 0x33,0x2e,0x6f,0x72,0x67,0x2f,0x31,0x39,0x39,0x39,0x2f,0x30,0x32,0x2f,0x32,0x32, 0x2d,0x72,0x64,0x66,0x2d,0x73,0x79,0x6e,0x74,0x61,0x78,0x2d,0x6e,0x73,0x23,0x22, 0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x72,0x64,0x66,0x3a,0x44,0x65,0x73, 0x63,0x72,0x69,0x70,0x74,0x69,0x6f,0x6e,0x20,0x72,0x64,0x66,0x3a,0x61,0x62,0x6f, 0x75,0x74,0x3d,0x22,0x22,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x78,0x6d,0x6c,0x6e,0x73,0x3a,0x64,0x63,0x3d,0x22,0x68,0x74,0x74,0x70, 0x3a,0x2f,0x2f,0x70,0x75,0x72,0x6c,0x2e,0x6f,0x72,0x67,0x2f,0x64,0x63,0x2f,0x65, 0x6c,0x65,0x6d,0x65,0x6e,0x74,0x73,0x2f,0x31,0x2e,0x31,0x2f,0x22,0x0a,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x78,0x6d,0x6c,0x6e,0x73,0x3a, 0x70,0x68,0x6f,0x74,0x6f,0x73,0x68,0x6f,0x70,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a, 0x2f,0x2f,0x6e,0x73,0x2e,0x61,0x64,0x6f,0x62,0x65,0x2e,0x63,0x6f,0x6d,0x2f,0x70, 0x68,0x6f,0x74,0x6f,0x73,0x68,0x6f,0x70,0x2f,0x31,0x2e,0x30,0x2f,0x22,0x3e,0x0a, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x64,0x63,0x3a,0x63,0x72,0x65, 0x61,0x74,0x6f,0x72,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x3c,0x72,0x64,0x66,0x3a,0x53,0x65,0x71,0x3e,0x0a,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x72,0x64,0x66,0x3a, 0x6c,0x69,0x3e,0x4d,0x69,0x63,0x68,0x61,0x65,0x6c,0x20,0x53,0x77,0x65,0x65,0x74, 0x3c,0x2f,0x72,0x64,0x66,0x3a,0x6c,0x69,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x72,0x64,0x66,0x3a,0x53,0x65,0x71,0x3e, 0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x64,0x63,0x3a,0x63, 0x72,0x65,0x61,0x74,0x6f,0x72,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x3c,0x64,0x63,0x3a,0x72,0x69,0x67,0x68,0x74,0x73,0x3e,0x0a,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x72,0x64,0x66,0x3a,0x41,0x6c, 0x74,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x3c,0x72,0x64,0x66,0x3a,0x6c,0x69,0x20,0x78,0x6d,0x6c,0x3a,0x6c,0x61, 0x6e,0x67,0x3d,0x22,0x78,0x2d,0x64,0x65,0x66,0x61,0x75,0x6c,0x74,0x22,0x3e,0x43, 0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x32,0x30,0x31,0x30,0x20,0x41,0x70, 0x70,0x6c,0x65,0x20,0x49,0x6e,0x63,0x2e,0x3c,0x2f,0x72,0x64,0x66,0x3a,0x6c,0x69, 0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f, 0x72,0x64,0x66,0x3a,0x41,0x6c,0x74,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x3c,0x2f,0x64,0x63,0x3a,0x72,0x69,0x67,0x68,0x74,0x73,0x3e,0x0a,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x70,0x68,0x6f,0x74,0x6f,0x73,0x68, 0x6f,0x70,0x3a,0x48,0x65,0x61,0x64,0x6c,0x69,0x6e,0x65,0x3e,0x4e,0x65,0x77,0x20, 0x49,0x6d,0x61,0x67,0x65,0x3c,0x2f,0x70,0x68,0x6f,0x74,0x6f,0x73,0x68,0x6f,0x70, 0x3a,0x48,0x65,0x61,0x64,0x6c,0x69,0x6e,0x65,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20, 0x20,0x3c,0x2f,0x72,0x64,0x66,0x3a,0x44,0x65,0x73,0x63,0x72,0x69,0x70,0x74,0x69, 0x6f,0x6e,0x3e,0x0a,0x20,0x20,0x20,0x3c,0x2f,0x72,0x64,0x66,0x3a,0x52,0x44,0x46, 0x3e,0x0a,0x3c,0x2f,0x78,0x3a,0x78,0x6d,0x70,0x6d,0x65,0x74,0x61,0x3e,0x0a,0xef, 0xbe,0x80,0x96,0x00,0x00,0x13,0x0d,0x49,0x44,0x41,0x54,0x78,0xda,0xed,0x9d,0x77, 0x8c,0x15,0xd5,0x17,0xc7,0xef,0x2e,0x2b,0x2a,0x8a,0x08,0x0a,0x22,0x4b,0xb7,0xa1, 0x14,0x1b,0x1a,0x14,0xd1,0x28,0x0a,0x88,0xc4,0x82,0xe5,0x47,0x50,0x62,0x6f,0xc4, 0x9a,0x58,0xc2,0x1f,0x96,0xc4,0x42,0xa2,0x89,0x89,0x25,0xa8,0x3f,0x6b,0xc4,0x1a, 0x8d,0x15,0x15,0xcb,0x82,0x35,0xfa,0xb3,0xa2,0x82,0x91,0x62,0x2c,0x14,0x91,0xa2, 0x80,0x80,0x80,0xc0,0xfc,0xce,0xe7,0xba,0x67,0x32,0x6f,0xde,0xcc,0xbc,0x37,0x6f, 0xdf,0x7b,0xbb,0xef,0xed,0x3d,0xc9,0xdd,0x99,0xbd,0xf7,0x4e,0x79,0xf7,0x7c,0xef, 0x69,0x73,0x4b,0x8d,0x49,0x20,0xcf,0xf3,0x7a,0xc8,0x61,0x9c,0xa4,0xe1,0x92,0x06, 0x48,0xea,0x2c,0xa9,0xad,0x71,0xd4,0x92,0x69,0x93,0xa4,0xe5,0x92,0x66,0x4b,0x6a, 0x90,0xf4,0x6c,0x4d,0x4d,0xcd,0xc2,0xb8,0xca,0x35,0x31,0x8c,0xaf,0x97,0xc3,0x64, 0x49,0xe3,0x25,0xb5,0x71,0x6d,0x5a,0xd1,0xb4,0x45,0xd2,0xd3,0x92,0x26,0x09,0x10, 0x16,0xe7,0x04,0x80,0x30,0x7f,0x14,0xa8,0x91,0xd4,0xc1,0xb5,0x5d,0x55,0xd1,0x6a, 0xa4,0xb9,0x80,0x60,0x7a,0x30,0xb3,0x36,0xc4,0xfc,0x8b,0xe4,0x30,0xcd,0x31,0xbf, 0x2a,0x09,0x9e,0x4e,0x6b,0xe4,0x71,0xb6,0x04,0x68,0xec,0xf9,0xd3,0x9c,0xc8,0x6f, 0x15,0x2a,0x61,0x8c,0x4a,0x82,0x9a,0x80,0xce,0x9f,0xe3,0x7a,0x7e,0xab,0x52,0x07, 0xfd,0xb1,0x09,0x54,0x05,0x4c,0x76,0xcc,0x6f,0x75,0xea,0x60,0xb2,0x95,0x00,0x8d, 0xae,0xde,0x4f,0x4e,0xf4,0xb7,0x4a,0x55,0xd0,0xa7,0xb6,0xd1,0xcf,0x77,0xcc,0x6f, 0x7d,0x04,0xcf,0xc7,0x01,0x80,0xe1,0xae,0x2d,0x5a,0x2d,0x0d,0x47,0x05,0x2c,0x92, 0x93,0x7a,0xd7,0x16,0xad,0x92,0x16,0x03,0x80,0x8d,0xc6,0x85,0x77,0x5b,0x2b,0x6d, 0x02,0x00,0x9e,0x6b,0x87,0xd6,0x4b,0x75,0x69,0x2f,0x58,0xb5,0x6a,0x95,0x99,0x3e, 0xfd,0xdf,0x68,0xe2,0x89,0x27,0x9e,0x68,0xda,0xb5,0x6b,0xe7,0x5a,0xb1,0x82,0x29, 0xb5,0x04,0x98,0x35,0x6b,0x96,0x39,0xf0,0xc0,0x03,0xed,0xf9,0xaf,0xbf,0xfe,0x6a, 0x7a,0xf4,0xe8,0xe1,0x5a,0xb1,0x35,0x49,0x00,0x89,0x1e,0x99,0xed,0xb7,0xdf,0xde, 0x3f,0x77,0xd4,0xca,0x24,0x80,0xa3,0xea,0xa2,0x5a,0xd7,0x04,0x0e,0x00,0xa9,0xe8, 0xc7,0x1f,0x7f,0x34,0x23,0x46,0x8c,0xb0,0x69,0xf9,0xf2,0xe5,0x19,0x65,0x37,0xdf, 0x7c,0xb3,0xcd,0xbf,0xeb,0xae,0xbb,0xec,0xff,0xaf,0xbc,0xf2,0x8a,0x99,0x30,0x61, 0x82,0xd9,0x7d,0xf7,0xdd,0x4d,0xaf,0x5e,0xbd,0xcc,0x69,0xa7,0x9d,0x66,0x66,0xcf, 0x9e,0x9d,0xd7,0x7d,0x7f,0xff,0xfd,0x77,0x73,0xd3,0x4d,0x37,0x99,0xa1,0x43,0x87, 0x9a,0x9d,0x76,0xda,0xc9,0x1c,0x76,0xd8,0x61,0x66,0xf2,0xe4,0xc9,0x66,0xeb,0xd6, 0xad,0x91,0xd7,0xcf,0x98,0x31,0xc3,0x8c,0x1c,0x39,0xd2,0x74,0xeb,0xd6,0xcd,0x6c, 0xbb,0xed,0xb6,0xa6,0x77,0xef,0xde,0xe6,0x88,0x23,0x8e,0x30,0xaf,0xbf,0xfe,0x7a, 0x64,0xfd,0x9f,0x7f,0xfe,0xd9,0x9c,0x7b,0xee,0xb9,0x66,0xbf,0xfd,0xf6,0xb3,0x86, 0xec,0xa1,0x87,0x1e,0x6a,0x6e,0xbd,0xf5,0xd6,0xd8,0xfb,0x87,0x7f,0xdb,0x53,0x4f, 0x3d,0x65,0x4e,0x3e,0xf9,0x64,0xfb,0x6e,0xf7,0xdd,0x77,0x9f,0x2d,0xe3,0xf9,0x2b, 0x56,0xac,0x88,0x6d,0xbb,0x07,0x1e,0x78,0xc0,0xd6,0xbb,0xf7,0xde,0x7b,0xb3,0xca, 0x1e,0x7c,0xf0,0x41,0x73,0xdc,0x71,0xc7,0x99,0x8e,0x1d,0x3b,0x9a,0xee,0xdd,0xbb, 0xdb,0x7b,0x7f,0xfb,0xed,0xb7,0x79,0xb5,0xd5,0x2f,0xbf,0xfc,0x62,0xae,0xbd,0xf6, 0x5a,0xd3,0xbf,0x7f,0x7f,0x33,0x68,0xd0,0xa0,0x74,0x0c,0xf5,0x52,0xd2,0xd7,0x5f, 0x7f,0x8d,0xca,0xb0,0x49,0x8c,0xc0,0x8c,0xb2,0x93,0x4e,0x3a,0xc9,0xe6,0x9f,0x77, 0xde,0x79,0xde,0x93,0x4f,0x3e,0xe9,0x89,0x8d,0xe0,0xd7,0xd5,0xb4,0xe3,0x8e,0x3b, 0x7a,0x6f,0xbe,0xf9,0x66,0xe2,0x7d,0xe7,0xcc,0x99,0xe3,0x1d,0x74,0xd0,0x41,0x59, 0xd7,0x92,0x8e,0x3f,0xfe,0x78,0x6f,0xd3,0xa6,0x4d,0x19,0xd7,0x3e,0xf7,0xdc,0x73, 0x7e,0xb9,0x34,0xa0,0x37,0x64,0xc8,0x10,0x6f,0xe7,0x9d,0x77,0xb6,0xff,0x0b,0xc3, 0xb2,0x9e,0xf5,0xf6,0xdb,0x6f,0x7b,0x9d,0x3a,0x75,0xb2,0xe5,0x7b,0xed,0xb5,0x97, 0x27,0xe0,0xf2,0x04,0x04,0xf6,0xff,0x51,0xa3,0x46,0x79,0x9b,0x37,0x6f,0xce,0xba, 0x26,0xf8,0xdb,0x84,0x91,0x19,0xef,0xf4,0xcc,0x33,0xcf,0x78,0x02,0x38,0x7b,0x2e, 0xcc,0x8d,0x6c,0xb7,0x2d,0x5b,0xb6,0x78,0xc2,0x58,0x5b,0xe7,0xbd,0xf7,0xde,0xf3, 0xf3,0xd7,0xaf,0x5f,0xef,0x9d,0x71,0xc6,0x19,0x36,0xbf,0x7d,0xfb,0xf6,0xde,0xe1, 0x87,0x1f,0xee,0xf5,0xed,0xdb,0xd7,0xfe,0xbf,0xc3,0x0e,0x3b,0x78,0x6f,0xbd,0xf5, 0x56,0x62,0x5b,0x7d,0xf3,0xcd,0x37,0x5e,0xbf,0x7e,0xfd,0xfc,0xff,0x39,0x4f,0x43, 0x25,0x01,0x80,0x20,0xd1,0x6b,0xdb,0xb6,0xad,0x77,0xc9,0x25,0x97,0x78,0x33,0x67, 0xce,0xf4,0xfe,0xf8,0xe3,0x0f,0xcb,0x74,0x91,0x04,0xb6,0x5c,0xa4,0x41,0x16,0x13, 0x83,0xf7,0x15,0x2f,0xc3,0xdb,0x63,0x8f,0x3d,0xbc,0x87,0x1f,0x7e,0xd8,0x13,0x74, 0x7b,0x0b,0x16,0x2c,0xf0,0x2e,0xbd,0xf4,0x52,0xbf,0x5c,0x7a,0x4b,0xc6,0xb5,0x7d, 0xfa,0xf4,0xb1,0xf9,0x57,0x5f,0x7d,0xb5,0x27,0x3d,0xd8,0xcf,0x97,0x5e,0x9e,0xf5, 0x8e,0x2b,0x57,0xae,0xf4,0xc1,0x01,0x48,0x95,0xa8,0xc7,0x33,0xc9,0x97,0xde,0x1d, 0x0b,0x00,0x91,0x18,0x5e,0x5d,0x5d,0x9d,0x05,0x42,0x43,0x43,0x83,0xfd,0x6d,0xe2, 0x1a,0x7b,0x37,0xde,0x78,0xa3,0x2d,0x1f,0x3c,0x78,0x70,0x64,0xbb,0xbd,0xf1,0xc6, 0x1b,0xb6,0x7c,0xef,0xbd,0xf7,0xce,0xc8,0xd7,0xeb,0x00,0xa1,0xf4,0x66,0x3f,0xff, 0xb6,0xdb,0x6e,0xb3,0xf9,0xfb,0xec,0xb3,0x8f,0x05,0x4f,0x5c,0x5b,0xed,0xbf,0xff, 0xfe,0x16,0x30,0x00,0x6f,0xe1,0xc2,0x85,0xde,0xa2,0x45,0x8b,0x9a,0x1f,0x00,0x22, 0x82,0xbd,0xa9,0x53,0xa7,0x66,0x5d,0x0b,0x18,0xf4,0xda,0xc7,0x1e,0x7b,0x2c,0xf6, 0xbe,0x47,0x1e,0x79,0xa4,0x27,0xa2,0x34,0xeb,0xfa,0xa3,0x8e,0x3a,0xca,0x96,0xd3, 0xdb,0x94,0x36,0x6e,0xdc,0xe8,0xd5,0xd6,0xd6,0xda,0xfc,0x77,0xde,0x79,0x27,0xe7, 0xfb,0x5f,0x75,0xd5,0x55,0xb6,0x2e,0xef,0x1a,0x26,0x80,0x45,0x19,0xd2,0x27,0x0e, 0x00,0x0a,0xb4,0x30,0x01,0xd2,0xa0,0x04,0x0b,0xd3,0xd8,0xb1,0x63,0x6d,0xd9,0x1d, 0x77,0xdc,0xe1,0xe7,0x2d,0x5e,0xbc,0xd8,0x97,0x3c,0xfc,0xfe,0x20,0x21,0x85,0xc4, 0xc5,0xb6,0x65,0xaf,0xbe,0xfa,0x6a,0x6c,0x5b,0xed,0xba,0xeb,0xae,0xf6,0xd9,0x85, 0x52,0x49,0x00,0x70,0xce,0x39,0xe7,0xc4,0x5e,0xdf,0xb3,0x67,0x4f,0x5b,0x67,0xe2, 0xc4,0x89,0xb1,0xf7,0xa5,0xe7,0x46,0xd1,0x23,0x8f,0x3c,0xe2,0xd7,0x59,0xb6,0x6c, 0x99,0x9f,0x7f,0xf4,0xd1,0x47,0xdb,0x3c,0xd1,0xe3,0xde,0xfc,0xf9,0xf3,0x13,0xdf, 0xbf,0xbe,0xbe,0xde,0xd6,0xbd,0xff,0xfe,0xfb,0xb3,0xca,0x3e,0xff,0xfc,0x73,0x5b, 0xb6,0xcd,0x36,0xdb,0x64,0xf5,0x3a,0xfd,0x6d,0x62,0x57,0x64,0x95,0x29,0x51,0x46, 0x9d,0xeb,0xaf,0xbf,0x3e,0x23,0x5f,0xec,0x19,0x7b,0x4f,0x12,0xe7,0x4a,0x0f,0x3d, 0xf4,0x90,0xad,0xbf,0xdb,0x6e,0xbb,0x45,0xde,0xef,0x84,0x13,0x4e,0xb0,0xe5,0xb7, 0xdc,0x72,0x4b,0x6c,0x5b,0x45,0xa9,0x88,0x34,0x54,0x57,0x12,0xcb,0xb2,0x36,0xde, 0xb6,0x14,0x71,0x65,0x03,0x48,0x18,0x61,0x69,0xaf,0x17,0x11,0x9d,0x61,0xc4,0x75, 0xee,0xdc,0xd9,0x9e,0x5f,0x7e,0xf9,0xe5,0xe6,0xc3,0x0f,0x3f,0x34,0x9f,0x7d,0xf6, 0x99,0x19,0x38,0x70,0xa0,0x19,0x3f,0x7e,0xbc,0x35,0x8a,0x44,0x1f,0x66,0x5c,0xbf, 0x6e,0xdd,0x3a,0x23,0xbd,0xce,0x37,0xba,0x5e,0x78,0xe1,0x85,0x8c,0xf2,0xbf,0xff, 0xfe,0xdb,0x1e,0xff,0xf9,0xe7,0x1f,0xb3,0x74,0xe9,0x52,0x6b,0x50,0x86,0x49,0x44, 0x78,0xec,0xfb,0x9d,0x7d,0xf6,0xd9,0xe6,0xa3,0x8f,0x3e,0x32,0xa2,0x5a,0xcc,0xed, 0xb7,0xdf,0xee,0xd7,0x7b,0xe2,0x89,0x27,0xec,0x3d,0x31,0x82,0xbb,0x74,0xe9,0xe2, 0xd7,0x9f,0x37,0x6f,0x9e,0xff,0xdc,0x63,0x8f,0x3d,0x36,0xeb,0x7e,0x22,0x49,0xfc, 0x80,0x5b,0x1c,0xed,0xbb,0xef,0xbe,0xe5,0x0d,0x04,0x35,0x95,0xb0,0x72,0xa1,0x35, 0x6b,0xd6,0x14,0x7c,0x6d,0xf8,0xfa,0x53,0x4e,0x39,0xc5,0x7c,0xf2,0xc9,0x27,0x96, 0x01,0xdf,0x7f,0xff,0xbd,0x79,0xf4,0xd1,0x47,0xcd,0xe3,0x8f,0x3f,0x6e,0xad,0x7c, 0x2c,0x6e,0x0d,0x5c,0x89,0x8e,0xcc,0x88,0x68,0x26,0x11,0xd6,0x75,0x14,0x00,0x92, 0x48,0x8c,0x39,0x73,0xc5,0x15,0x57,0x58,0x90,0x89,0x7d,0x60,0xad,0x7a,0x48,0x24, 0x97,0x3d,0x5e,0x78,0xe1,0x85,0x19,0xf5,0x95,0xb1,0xfc,0x16,0xea,0x27,0xbd,0x4b, 0xd5,0xc4,0x01,0xc4,0x68,0xb2,0x47,0xdc,0xc2,0x42,0xaf,0x8d,0xba,0x5e,0x8c,0x2f, 0xf3,0xd5,0x57,0x5f,0x19,0x11,0xab,0xb6,0x97,0xe2,0xce,0xd1,0xf0,0x67,0x9d,0x75, 0x96,0x5f,0x47,0xc4,0xbf,0x7f,0x2e,0xa2,0xd3,0x34,0xaa,0xc0,0xc8,0x24,0xc6,0x55, 0xea,0xf7,0xc3,0x25,0x04,0x8c,0xda,0xeb,0xa1,0x8f,0x3f,0xfe,0xd8,0xfc,0xf0,0xc3, 0x0f,0xd6,0x2d,0x55,0x40,0x28,0xe1,0xee,0x41,0xb8,0xb8,0x49,0xef,0xf2,0xd2,0x4b, 0x2f,0x55,0x0f,0x00,0x54,0x04,0xa3,0x0a,0x0a,0xbd,0x16,0xd1,0x1a,0x05,0x20,0xfc, 0xff,0x0b,0x2e,0xb8,0xc0,0xfa,0xcf,0x97,0x5d,0x76,0x99,0xcd,0x13,0x03,0xca,0xf7, 0xcd,0xc5,0xcd,0xf2,0xbf,0x5d,0x20,0xaa,0x4b,0x41,0x48,0x21,0xe8,0xc5,0x17,0x5f, 0x34,0x7f,0xfd,0xf5,0x97,0x11,0x4f,0xc6,0xfe,0x7f,0xfe,0xf9,0xe7,0x67,0x85,0xce, 0x89,0x41,0x40,0x5f,0x7e,0xf9,0xa5,0xd9,0xb0,0x61,0x43,0xf5,0x44,0x02,0xe3,0xa2, 0xcb,0xdf,0x7d,0xf7,0x9d,0x11,0x8b,0xd5,0x9e,0x13,0x34,0x49,0x7b,0x3d,0x8d,0x0a, 0x1d,0x73,0xcc,0x31,0x46,0x0c,0xaa,0xd8,0xeb,0x01,0x02,0x41,0x23,0x71,0xd7,0x8c, 0x58,0xd3,0x46,0xbc,0x0f,0xbf,0x4c,0xe2,0x08,0xf6,0x88,0x9a,0x28,0x44,0x0d,0xe5, 0x22,0x74,0x39,0x92,0x46,0xfc,0x7b,0x23,0x9e,0x8e,0x79,0xfe,0xf9,0xe7,0x4d,0x9b, 0x36,0x6d,0x8c,0xb8,0x8d,0x59,0x75,0xc5,0x78,0xb5,0xef,0x2a,0x2e,0xb1,0x99,0x32, 0x65,0x4a,0xf3,0x84,0x02,0x4b,0xe1,0x05,0x88,0xce,0xf5,0xee,0xb9,0xe7,0x9e,0x0c, 0x9f,0x5c,0x0c,0x1d,0x1b,0x64,0xa1,0x7c,0xf8,0xf0,0xe1,0x89,0xf7,0xc5,0x9a,0x96, 0x68,0x57,0x46,0x39,0x2e,0x1e,0x56,0x34,0xe5,0x62,0xf0,0xf9,0xf9,0xf8,0xce,0x12, 0x71,0xcc,0x0a,0xde,0xbc,0xfc,0xf2,0xcb,0xfe,0xfd,0x44,0x22,0xf8,0xf9,0xb8,0x97, 0xb8,0x4e,0xe4,0x8b,0xb8,0xf6,0xfe,0xfc,0xf3,0xcf,0xac,0x77,0x59,0xb2,0x64,0x89, 0x27,0x3d,0x32,0x36,0x10,0x94,0x8b,0xf0,0x02,0xb4,0x1d,0x38,0xca,0x67,0xf3,0xd8, 0xba,0x12,0x61,0xf4,0x83,0x3e,0x12,0xb5,0xcc,0x2a,0x27,0x5e,0x12,0xf6,0xed,0x93, 0x78,0xd0,0x22,0xdc,0x40,0x22,0x5e,0x82,0x7a,0x1b,0x10,0xba,0xf2,0xca,0x2b,0xbd, 0x6b,0xae,0xb9,0xc6,0x9e,0x53,0x26,0x56,0xb0,0x8d,0x5e,0x25,0xdd,0x17,0x3f,0x9f, 0x06,0x91,0x70,0xa8,0x6d,0xa0,0x71,0xe3,0xc6,0xd9,0xc0,0x12,0x65,0x04,0x97,0x82, 0x34,0x77,0xee,0x5c,0x9b,0x8f,0x7b,0x27,0xfa,0xde,0xd6,0x3f,0xf5,0xd4,0x53,0x7d, 0xff,0x9a,0x6b,0xc3,0xf4,0xda,0x6b,0xaf,0x79,0xa2,0xaf,0x7d,0x17,0xec,0xcc,0x33, 0xcf,0xf4,0x6e,0xb8,0xe1,0x06,0x1b,0x91,0x53,0x37,0x35,0xec,0x5b,0xa7,0x01,0x80, 0x18,0xa2,0x19,0x91,0x42,0x9e,0x17,0x47,0x00,0x6d,0xf4,0xe8,0xd1,0x7e,0x5d,0x62, 0x1d,0xc4,0x2a,0x88,0x35,0x10,0x15,0xdc,0x6e,0xbb,0xed,0xec,0xef,0xaa,0x28,0x00, 0xd0,0x48,0x04,0x7d,0x34,0x3c,0x4a,0x22,0x58,0xc3,0x0f,0x8a,0xf3,0xf1,0x83,0xf7, 0x15,0xa3,0xc9,0x13,0x9d,0xe9,0x33,0x5d,0x43,0xbc,0x77,0xde,0x79,0x67,0xd6,0x75, 0xf8,0xd5,0x04,0x59,0x82,0xcf,0x22,0x01,0x80,0x49,0x93,0x26,0xd9,0x50,0x6b,0x14, 0x11,0x61,0x24,0xac,0x4c,0xd0,0x2a,0x78,0x1d,0x00,0x18,0x33,0x66,0x4c,0x46,0x9c, 0x21,0x2d,0x00,0x20,0x62,0x12,0x0a,0xcc,0xa8,0xd0,0x72,0x98,0x08,0x2f,0x6b,0x8c, 0x22,0xf8,0x1b,0x0e,0x39,0xe4,0x10,0x4f,0xd4,0x43,0xcb,0x01,0x40,0x12,0x45,0x35, 0x12,0xe2,0x0b,0x91,0xbd,0x7a,0xf5,0xea,0xd4,0xc0,0xa2,0x77,0x88,0x6f,0x6f,0x01, 0x11,0x54,0x27,0x71,0x44,0x58,0xf6,0x83,0x0f,0x3e,0xb0,0x22,0x3f,0x8e,0xf1,0x61, 0x12,0xff,0xdc,0x93,0x0f,0x54,0x9e,0x58,0xeb,0x36,0xa4,0xdb,0xdc,0x84,0x4a,0x7b, 0xff,0xfd,0xf7,0x3d,0x89,0x11,0xc4,0x06,0x9c,0x8a,0x49,0x25,0x8f,0x03,0x60,0x10, 0x05,0xdd,0xaf,0x34,0x84,0x81,0x24,0x3d,0x20,0x55,0x9c,0x60,0xd8,0xb0,0x61,0xe9, 0x02,0x21,0x62,0x28,0xf2,0x15,0xad,0xa5,0x90,0xd8,0x27,0x46,0x42,0xe1,0x6e,0x3c, 0x80,0x23,0x07,0x00,0x47,0x65,0xa0,0xa2,0xaa,0x00,0xfc,0x5a,0xf9,0xd4,0x6a,0xc4, 0xd8,0x4b,0x7d,0xad,0x7c,0x9f,0xf7,0x83,0x28,0xe2,0x01,0x38,0xce,0x94,0x89,0xdc, 0x98,0x40,0xa7,0x02,0x1c,0x39,0x00,0x38,0x72,0x00,0x70,0xe4,0x00,0xe0,0xc8,0x01, 0xc0,0x91,0x03,0x80,0x23,0x07,0x00,0x47,0x0e,0x00,0x8e,0x1c,0x00,0x1c,0x39,0x00, 0x38,0x72,0x00,0x70,0xe4,0x00,0xe0,0xa8,0x8a,0xa9,0x2c,0x13,0x43,0x18,0xa3,0xcf, 0xe8,0xd8,0x69,0xd3,0xa6,0x19,0x99,0x9c,0x99,0x91,0x4f,0x92,0x91,0x2f,0xf6,0x7f, 0x1d,0x36,0xcd,0xb0,0x6f,0x06,0x83,0xc8,0x78,0x38,0x3b,0x75,0x9b,0x2f,0x8c,0x0c, 0xf6,0x60,0xb0,0x04,0x83,0x4b,0x64,0xd8,0x96,0x1d,0x56,0x1e,0x9c,0x28,0xe2,0xa8, 0x30,0x2a,0xd9,0xd7,0x40,0x6e,0xcb,0x74,0x2d,0x19,0x1d,0x6c,0x99,0xae,0xb3,0x73, 0xc8,0x87,0xd1,0x71,0x8f,0xd5,0x32,0x05,0x43,0x54,0x7d,0x86,0x73,0x03,0x90,0x77, 0xdf,0x7d,0xd7,0x96,0xb9,0xa5,0x6a,0x5a,0x90,0x04,0x80,0x51,0x32,0xfe,0xcf,0x5c, 0x7c,0xf1,0xc5,0x96,0xf1,0xf4,0xe2,0xe0,0xf7,0xfd,0x5c,0x0c,0x0e,0x97,0x07,0x89, 0x15,0xca,0x90,0x18,0x2c,0x38,0x01,0x31,0x9e,0x9e,0xf9,0x01,0x48,0x0c,0x07,0x82, 0x16,0x00,0x00,0x7a,0x26,0x33,0x71,0x98,0x74,0x09,0x13,0x8b,0x35,0xb0,0x83,0x29, 0x61,0x32,0x0d,0xdc,0x8a,0x7f,0x98,0xad,0x60,0x61,0xb2,0xa7,0x2c,0x38,0x61,0x41, 0xe0,0x00,0xd0,0x8c,0x00,0x60,0xf2,0xa2,0x8c,0x7d,0xb7,0x22,0x99,0x29,0x4e,0x49, 0xb3,0x83,0xd3,0x10,0x53,0xba,0xd6,0xae,0x5d,0x6b,0xe7,0xd0,0x45,0xcd,0x04,0xa2, 0x0c,0x55,0xc0,0xc0,0x4e,0x47,0x65,0x06,0x00,0x86,0x1b,0x33,0x72,0x31,0xec,0x7e, 0xfa,0xe9,0x27,0xdf,0x90,0x63,0x1a,0x54,0x9c,0x08,0xcf,0x47,0xe4,0x73,0x8e,0xea, 0x00,0x54,0xcc,0xe3,0xdb,0x65,0x97,0x5d,0x32,0xea,0x33,0xcd,0x1a,0x15,0x83,0x41, 0xc8,0xb4,0x6a,0xa6,0x7e,0xb9,0x41,0x4d,0x65,0x02,0x00,0x0d,0x2d,0xe3,0xf7,0x8d, 0xac,0xfe,0x61,0xe7,0xe7,0xd3,0xfb,0x94,0x89,0xda,0x0b,0x9b,0x62,0xe4,0x31,0x9f, 0x8e,0x39,0xf3,0xf4,0x78,0x66,0xf8,0x06,0xcb,0xd0,0xfd,0xa8,0x18,0x12,0x60,0x03, 0x18,0x80,0x21,0x6e,0x51,0x27,0x47,0x45,0x06,0x00,0xa2,0x9d,0x55,0xb4,0xe2,0x56, 0xdd,0x2a,0x16,0xe9,0x8c,0x59,0x05,0x10,0x0c,0x46,0xd4,0xd3,0xeb,0x61,0x38,0xcc, 0x27,0x05,0xa7,0x4f,0x3b,0x2a,0x21,0x00,0x68,0x60,0x0c,0x30,0x16,0x3e,0x90,0x25, 0x54,0x4a,0xfe,0x42,0x41,0x86,0x22,0xe2,0x65,0xf2,0xa6,0xb5,0xf6,0x61,0x3a,0xe2, 0x1e,0x40,0x70,0x6c,0x6e,0xe2,0x7d,0x50,0x53,0x00,0x53,0x16,0x72,0xaa,0x4e,0x00, 0xc0,0x0c,0x7e,0xe8,0xdd,0x77,0xdf,0x5d,0x16,0xe6,0xeb,0x33,0x61,0x38,0x0d,0x0b, 0xf0,0x78,0x3e,0x47,0x0d,0x18,0xc1,0x7c,0xb5,0x37,0x4a,0x41,0xb8,0x9a,0x2c,0x0f, 0xa3,0xe9,0xb7,0xdf,0x7e,0x33,0x32,0x5b,0xd8,0xae,0xc5,0x27,0xd3,0xdc,0xec,0xfa, 0x85,0x78,0x25,0xbc,0x07,0x6b,0x11,0x5c,0x77,0xdd,0x75,0x89,0x36,0x4f,0x45,0x03, 0x80,0x46,0x97,0x45,0x97,0x8c,0xac,0xc3,0x57,0xb6,0x17,0xa2,0x31,0x65,0x62,0xa6, 0xdf,0xd3,0x61,0x36,0xa2,0x5f,0xcf,0x55,0x0a,0xa4,0xd1,0xfd,0xa8,0xaf,0x20,0x43, 0xf5,0x1c,0xa6,0xb2,0x6c,0x0c,0x79,0x78,0x1c,0x30,0x1f,0x0f,0x86,0xa0,0x95,0xda, 0x34,0xfa,0x7c,0x8d,0x3b,0xf0,0x7e,0xcc,0xf5,0x87,0xf1,0xc4,0x23,0x30,0x7a,0x79, 0x97,0x4a,0x8d,0x45,0xd4,0x25,0x31,0x9f,0xc6,0x66,0x79,0x92,0x72,0xeb,0x59,0x15, 0xf9,0xc1,0x1e,0x4f,0x5e,0x50,0x05,0xf0,0x4e,0x30,0x0c,0x49,0x81,0x61,0x08,0x68, 0x60,0x2a,0x0c,0x65,0xed,0x1d,0x7a,0x2d,0x79,0xf4,0x56,0x18,0x48,0x48,0x59,0x66, 0x1b,0xfb,0x71,0x04,0xee,0xc7,0x39,0x0c,0x24,0xe1,0x66,0x76,0xed,0xda,0x35,0x8b, 0x89,0x3c,0x1b,0x00,0xa1,0x8e,0x58,0xf5,0x54,0xa6,0xa7,0xdb,0xc5,0xa9,0xb8,0x17, 0x79,0x04,0xba,0xb8,0xa6,0x58,0xae,0x6f,0x8b,0x02,0x00,0xa2,0xf7,0x8b,0x2f,0xbe, 0x28,0xfb,0x4b,0xa9,0xe8,0x0f,0xf6,0x78,0x05,0x00,0x0d,0x4f,0xa3,0xcb,0xc2,0x8b, 0x76,0xe5,0x0f,0xce,0x61,0x9e,0xaa,0x2b,0x75,0x45,0x49,0xf4,0x62,0x98,0xca,0x79, 0xbe,0xa4,0x5e,0x07,0xf7,0x22,0xd0,0x84,0x01,0xca,0xe2,0x4f,0xac,0xf0,0xc5,0x37, 0x09,0xf5,0x46,0x08,0x72,0xc1,0x74,0xde,0xa7,0xea,0x8c,0x40,0x6d,0x00,0x10,0xae, 0xeb,0xf2,0x94,0x53,0x05,0x04,0x25,0x80,0x82,0x40,0x63,0xfe,0xf4,0x7a,0x3e,0x02, 0xc9,0x12,0xaf,0x96,0xc1,0x69,0x42,0xc9,0xfa,0xbb,0xb8,0x9f,0x26,0xa4,0x03,0x00, 0xa1,0xbe,0x4a,0x17,0x7a,0x3c,0xf9,0xa7,0x9f,0x7e,0xba,0x5d,0xd8,0x89,0x68,0x23, 0x65,0xb8,0xa9,0x1a,0xdd,0x54,0x80,0x55,0x7a,0x18,0x3a,0x16,0x00,0xda,0x10,0x30, 0xa3,0x9c,0xa4,0x92,0x47,0x99,0x11,0xb4,0x05,0x10,0xbd,0x2c,0x0e,0x15,0x14,0xb7, 0xfa,0xae,0x41,0x5b,0x21,0x6c,0x33,0xf0,0xbf,0xe6,0xc1,0x34,0xe2,0x17,0x2a,0x49, 0x60,0x2e,0xff,0x47,0x25,0xd4,0x4b,0x78,0x2d,0xc1,0x7c,0xe2,0x19,0xf9,0xd4,0xcf, 0x15,0x20,0x6b,0x0a,0x21,0xb5,0xf8,0xbd,0xb2,0x56,0x42,0x4e,0x70,0x26,0x02,0x00, 0x46,0x34,0x07,0x01,0x3a,0x15,0xfb,0x80,0x90,0x89,0xa3,0xe8,0x70,0x7e,0x14,0x96, 0x78,0x14,0x53,0x61,0xa8,0x26,0x98,0xa7,0x3a,0x5f,0x99,0xad,0x29,0x9f,0xde,0xaa, 0xae,0x6f,0x53,0x18,0x5c,0x4c,0x86,0xe6,0x0b,0x20,0x6d,0x2f,0x82,0x64,0x80,0x9b, 0xff,0x69,0x9b,0x24,0x15,0x18,0x0b,0x00,0x18,0xa0,0xd6,0x6f,0xb9,0x88,0x97,0x67, 0x25,0x31,0x54,0x0f,0xbd,0x17,0x86,0x21,0xee,0xf9,0x11,0x94,0xc1,0x4c,0xfd,0xf8, 0x43,0x19,0x47,0xfd,0x10,0x94,0x8b,0x01,0x1c,0xb9,0x47,0xa1,0x21,0xea,0x62,0xd7, 0x2f,0x26,0x80,0xd4,0x48,0x46,0x42,0x06,0xf7,0x70,0x42,0x65,0xf1,0x7f,0x92,0x9a, 0xaa,0x4b,0xea,0x05,0xe5,0x0c,0xb3,0xf2,0x2c,0x9e,0x89,0x6e,0x67,0xc5,0x0e,0xd5, 0xc9,0x04,0x82,0xa0,0x38,0x2b,0xbb,0xd0,0x77,0x2c,0x35,0xc3,0xcb,0x65,0x2f,0xd1, 0x59,0x58,0x7e,0x36,0xf8,0xb1,0x4c,0xdf,0x11,0x55,0x40,0x7e,0x92,0x14,0x48,0x04, 0x40,0x39,0xdd,0x3f,0xf5,0xbf,0xe9,0xe5,0x3c,0x97,0x45,0x16,0xc9,0x43,0x94,0xe5, 0xd3,0x43,0xd2,0x32,0xa4,0xd4,0x0c,0x2d,0x76,0x8f,0x0f,0xd7,0xc7,0x13,0xd1,0x91, 0x52,0x51,0xd7,0xe9,0xb7,0x15,0x16,0xc7,0x4c,0xe2,0x63,0x8b,0xfa,0x8e,0xaa,0xa2, 0x1e,0xd4,0x02,0x86,0xa6,0x34,0x60,0x53,0xcb,0xd3,0xea,0xe4,0x62,0x4b,0x94,0xb8, 0xf7,0xa1,0x63,0xd0,0x3e,0xb2,0xbc,0x5d,0x64,0xf8,0x3c,0xf8,0x7e,0x6a,0x4b,0x35, 0xe9,0x5b,0x40,0x39,0x09,0x83,0x4e,0x45,0xbe,0xa3,0x68,0x22,0xae,0x91,0x24,0x75, 0x82,0x60,0xca,0x47,0x8a,0xbb,0x51,0xc1,0x15,0x4c,0x41,0x03,0x37,0xc8,0xe8,0x34, 0xea,0xdb,0x01,0xa0,0x42,0x19,0x1f,0x64,0x7e,0x14,0x20,0x9a,0x1c,0x0a,0xce,0x45, 0xb8,0x61,0x1d,0x3a,0x74,0x70,0xdc,0x28,0x61,0x2c,0x84,0x40,0x54,0x5c,0xaf,0x8f, 0x12,0xf9,0x69,0x99,0x5f,0x30,0x00,0x78,0x20,0xcc,0x0f,0x8f,0xd3,0x4b,0x32,0x64, 0x70,0x57,0x48,0xb9,0x5e,0x10,0xe3,0xaf,0x52,0xf7,0x23,0x2e,0x66,0x30,0x28,0x8a, 0xf9,0xc1,0x7b,0x86,0x9f,0x19,0x57,0x5e,0x12,0x00,0xc0,0x20,0xdc,0xb3,0xa8,0x1f, 0x18,0xf5,0x72,0xcb,0x96,0xaf,0x35,0x6d,0xb6,0xe9,0x69,0x76,0xec,0xd0,0xd3,0x68, 0x55,0xaa,0x71,0xee,0x57,0x97,0xf3,0xcd,0x5b,0x36,0x98,0x65,0x4b,0xff,0x67,0xea, 0xbb,0xfd,0xe3,0xbb,0x7f,0x95,0x16,0xac,0x09,0xff,0xfe,0xf0,0x31,0x1f,0x06,0xe5, 0x13,0x82,0x0f,0xeb,0xff,0xa8,0x77,0x2b,0x19,0x00,0xd8,0x19,0x23,0xdf,0xcf,0x9f, 0xcb,0x57,0xac,0x31,0xdd,0x7a,0x8d,0x30,0xdd,0xba,0xef,0x2f,0x3c,0x96,0x17,0x34, 0x8d,0x3f,0xbe,0xe6,0x5f,0xa6,0x9b,0x50,0x5b,0x6c,0xda,0xb8,0x44,0xfe,0xae,0x6c, 0x96,0xcf,0xab,0xa5,0x0e,0xe7,0xe6,0x4b,0xb9,0xf6,0x31,0x88,0x7a,0x9f,0x28,0xd5, 0x50,0x12,0x00,0x84,0x27,0x7a,0x24,0x11,0xa1,0x64,0xaf,0x4d,0x27,0xb3,0xf7,0x80, 0xa1,0xa6,0x26,0x0f,0x86,0x6e,0xda,0xb8,0xde,0x6c,0xd9,0xba,0xca,0x02,0x2c,0x1f, 0x31,0xd6,0x52,0x18,0x56,0x4c,0xc0,0xe1,0xe7,0xf3,0x19,0x3a,0x6e,0xa8,0x7b,0x5c, 0x2f,0x0f,0xfe,0xf6,0x34,0x6a,0x20,0x35,0x00,0x88,0x2c,0x69,0x58,0x31,0x97,0x88, 0xfd,0x73,0xd5,0x6a,0x33,0x60,0xf0,0x7f,0x4c,0x97,0x1e,0x5d,0xf3,0xba,0xf7,0xfc, 0x39,0x1f,0x9b,0xf6,0xed,0xb6,0xf8,0xf7,0xcf,0x47,0x64,0x07,0x27,0x8a,0xe4,0x12, 0xb9,0xa5,0x0e,0xd6,0x14,0xe3,0x7e,0x3a,0x1a,0x2a,0xad,0x04,0x28,0xd4,0x13,0x48, 0x0d,0x00,0x7a,0x7f,0xdc,0x76,0x2d,0xe1,0x1f,0xb8,0xd9,0xdb,0xce,0xf4,0xee,0x37, 0xc8,0xb4,0xef,0xb8,0x53,0x14,0xfc,0x33,0x8c,0x80,0xf5,0x6b,0x57,0x99,0x9f,0xe7, 0xce,0x30,0x5d,0x3a,0xef,0x9a,0x37,0xc0,0x4a,0xe1,0x5e,0x35,0x67,0x78,0x19,0xd1, 0x4f,0xef,0x4f,0x52,0x7f,0x49,0x7a,0xbe,0x10,0x35,0x90,0x1a,0x00,0x3a,0x08,0x22, 0x2f,0xda,0xba,0xc1,0xcc,0x9f,0xfd,0xbe,0xa9,0xef,0x3b,0x20,0xbb,0x71,0x02,0x26, 0xc0,0xba,0x35,0x2b,0xcc,0xdc,0x59,0xef,0x9a,0x0e,0xdb,0x33,0xd7,0xaf,0x5d,0xd9, 0x44,0x7e,0xb9,0x55,0x48,0xd2,0xf3,0xe8,0xf5,0xba,0x97,0xa2,0x7e,0x18,0x8b,0x02, 0x4e,0x1c,0xa8,0x0a,0xed,0x18,0xa9,0x01,0x00,0x42,0x51,0x03,0xf9,0x50,0x8f,0xfa, 0xdd,0xcc,0xb2,0x05,0x33,0xcd,0xd2,0x79,0x0d,0xb1,0x3d,0x44,0x63,0x0a,0x5d,0xe4, 0xa3,0x46,0x6d,0x6d,0xfb,0xa2,0xf6,0xa8,0x7c,0x7a,0x6c,0x50,0x85,0xe8,0x79,0xa9, 0x0c,0xd0,0xb8,0xe7,0xe9,0x84,0x9b,0xe0,0xe7,0xf7,0xa4,0x51,0x4d,0xc5,0x08,0x00, 0x15,0x0c,0x00,0x76,0xfd,0x42,0x05,0x30,0x35,0x4b,0x87,0x52,0xc5,0x3d,0x38,0xf8, 0x51,0xa7,0x14,0x3a,0xb6,0xa9,0x6e,0x5b,0xa9,0x3e,0xd8,0xe4,0xea,0xad,0x4a,0x0c, 0x3a,0x61,0x20,0x2b,0xfb,0x0a,0x86,0x3f,0xd9,0xea,0x48,0xe3,0x5c,0xba,0x3e,0x4a, 0x12,0x44,0xe5,0x17,0xd5,0x0d,0xfc,0xf4,0xd3,0x4f,0xfd,0x97,0x64,0x30,0x42,0xa1, 0x3d,0xb2,0xdc,0x46,0x56,0xb9,0xeb,0xe7,0xf3,0xfb,0x61,0x3c,0x5e,0x4f,0xf8,0x7b, 0x7d,0x9c,0x21,0x18,0x06,0x1b,0xf5,0x82,0xef,0x11,0xf4,0x04,0x4a,0x02,0x00,0x82, 0x40,0x3a,0x60,0x34,0x8d,0xdb,0x11,0x57,0x5e,0x0a,0x83,0x2e,0x78,0xcf,0x42,0x82, 0x23,0x85,0x5a,0xe0,0x69,0xca,0x61,0x38,0x2e,0xb5,0x0e,0x2b,0x2f,0x46,0xbb,0x94, 0xc5,0x08,0xe4,0xc5,0x40,0x2c,0x49,0x11,0xa8,0xe3,0xe7,0x1c,0x15,0x8f,0xe2,0x46, 0xf0,0x44,0xa9,0x9d,0x70,0x27,0x4c,0x23,0x95,0x9a,0x6c,0xed,0xe8,0xa8,0x1d,0x44, 0x99,0x5b,0xa4,0xa1,0xe9,0xa4,0xeb,0x23,0xe5,0xa3,0xff,0xa3,0xf2,0x4b,0x1e,0x07, 0x88,0x93,0x0a,0x95,0x3e,0x41,0xa2,0x12,0x29,0xce,0x08,0x4d,0x23,0x8d,0xdd,0x78, 0x80,0x0a,0x65,0x7c,0x92,0x3b,0x98,0x4a,0xe2,0xb8,0xe6,0xac,0x3c,0xe6,0x27,0x01, 0x21,0xed,0x60,0x5e,0x07,0x80,0x0a,0x05,0x40,0xd4,0x60,0x90,0x42,0xa4,0x80,0x03, 0x40,0x15,0x00,0x21,0x78,0x9e,0xd6,0xe5,0x75,0x00,0xa8,0x70,0x35,0xd0,0x14,0xfd, 0xef,0x00,0x50,0xc1,0xcc,0x0f,0x47,0xfc,0x0a,0xb5,0x01,0xdc,0x02,0x7b,0x55,0x22, 0x01,0xe2,0x6c,0x04,0x07,0x80,0x2a,0xf5,0xfd,0xa3,0x98,0x5c,0x88,0x31,0xe8,0x54, 0x40,0x85,0x51,0xdc,0xc7,0x9e,0x42,0x6d,0x00,0x27,0x01,0xaa,0xc8,0x00,0x74,0x81, 0xa0,0x56,0x06,0x84,0x38,0x30,0xb8,0x40,0x50,0x2b,0x62,0xbc,0x8e,0x1b,0x08,0x0f, 0x04,0x71,0x46,0x60,0x2b,0x54,0x0b,0x25,0x19,0x0f,0xd0,0x12,0x96,0x65,0x75,0x94, 0xed,0x05,0x44,0x19,0x81,0x85,0x8c,0x07,0xc8,0x09,0x00,0xb7,0x16,0x7f,0xe5,0xc4, 0x01,0x9c,0x1b,0xe8,0x44,0x7f,0x6a,0x43,0xd0,0x01,0xa0,0xc2,0x0d,0x41,0x37,0x1e, 0xa0,0x15,0x8b,0x7f,0xf7,0x2d,0xc0,0x19,0x81,0x59,0x06,0x61,0x78,0x0f,0x46,0x07, 0x80,0x56,0x00,0x04,0x9d,0x9b,0x11,0x3e,0x77,0x00,0xa8,0x62,0xe6,0xeb,0x84,0x10, 0xed,0xf5,0xc1,0x39,0x86,0x4e,0x05,0x54,0x31,0x29,0xb3,0x83,0x8c,0x0e,0xee,0xa0, 0xa2,0xfb,0x29,0x39,0x15,0x50,0xa5,0xa4,0x8c,0x0f,0x33,0x3d,0x0c,0x80,0xd1,0xa3, 0x47,0x3b,0x00,0x54,0x23,0x69,0x64,0x36,0xd8,0xd3,0x75,0x3f,0x05,0x05,0x06,0x1b, 0x6b,0x0f,0x1b,0x36,0x2c,0xaf,0xbd,0x0c,0x72,0x02,0x80,0xb9,0x80,0xac,0x39,0xeb, 0xa8,0xe5,0x88,0x7f,0xed,0xf1,0x0a,0x80,0xa0,0x3a,0x60,0x69,0xfd,0xb1,0x63,0xc7, 0xda,0xd9,0x45,0xcc,0xce,0xd6,0x19,0xdc,0x05,0xc7,0x01,0x82,0x6b,0xd2,0x3a,0x6a, 0xfe,0xde,0x1f,0xdc,0xf1,0x44,0x37,0xd3,0xd0,0xfc,0x3d,0xf7,0xdc,0xd3,0x8c,0x1f, 0x3f,0xde,0xae,0xdf,0x40,0xd2,0xcd,0xaf,0x92,0x00,0x10,0x2b,0x01,0x74,0xaa,0xf1, 0xc0,0x81,0x03,0xed,0xd6,0xb0,0x8e,0x9a,0x9f,0xf9,0xda,0xd3,0x83,0x3d,0x5e,0x25, 0x02,0x3a,0x9f,0xdd,0x56,0x59,0x41,0x9c,0x0d,0x23,0x58,0x45,0x5c,0x97,0xf3,0x29, 0x18,0x00,0x88,0x0f,0x76,0xf2,0x64,0xb7,0xd0,0x52,0xee,0xd5,0xe7,0x28,0x37,0xf3, 0x59,0x3b,0x30,0x6c,0xf4,0x31,0x43,0x7b,0xe8,0xd0,0xa1,0x76,0xab,0x5d,0x36,0xd2, 0x80,0xe9,0xec,0x1d,0x80,0xd4,0xe6,0x1c,0x09,0x90,0x4b,0x05,0xd4,0x25,0x31,0x1f, 0xf1,0xc1,0x8d,0x46,0x8d,0x1a,0x55,0xf2,0x2d,0x63,0x1d,0x45,0x13,0x0b,0x46,0xea, 0x26,0x5a,0xca,0xc8,0x03,0x0e,0x38,0xc0,0x4a,0x66,0xec,0x33,0x7a,0x38,0x47,0x56, 0x6e,0x65,0xc7,0x10,0x00,0xc0,0xea,0x2d,0xa8,0x00,0xdd,0x26,0x2f,0x97,0x11,0xc8, 0x92,0x94,0x6d,0xa3,0x00,0x80,0x21,0x01,0x8a,0xfa,0xf5,0xeb,0x67,0x97,0x2f,0x2b, 0xd7,0xee,0xa1,0x8e,0xfe,0x25,0x7a,0xbd,0xee,0xdb,0x44,0xaf,0x1e,0x32,0x64,0x88, 0x3d,0xea,0x3e,0x87,0x4c,0xcb,0x87,0xf9,0x48,0x02,0x8c,0x3f,0x18,0xcf,0x11,0xe6, 0xc3,0xbb,0x5c,0xbd,0x1f,0xde,0x03,0x80,0xe5,0x92,0xea,0xc3,0x00,0xa0,0xf7,0xc3, 0x7c,0x6e,0xc6,0x03,0x0e,0x3e,0xf8,0x60,0x2b,0x0d,0x1a,0x1a,0x1a,0x9c,0x3a,0x28, 0x13,0xf3,0x49,0x18,0x76,0xb8,0x74,0x6a,0xd5,0xd3,0xab,0x75,0x3d,0x65,0x74,0x3c, 0xfc,0xa1,0xf7,0x93,0xe0,0x13,0x79,0xd4,0xc9,0x83,0xf9,0xd0,0xf2,0x1a,0x31,0x26, 0xa6,0xcb,0xc9,0xc8,0x28,0xbd,0x83,0xfb,0xb7,0x72,0xe5,0x4a,0xbb,0x77,0x20,0x3b, 0x71,0xb2,0xbd,0x2a,0x79,0x48,0x03,0xb6,0x79,0x67,0xf3,0x64,0xe7,0x22,0x16,0x97, 0xd0,0xe5,0x30,0x18,0x43,0x6e,0xd0,0xa0,0x41,0xfe,0x8e,0x68,0xf4,0x76,0xf2,0x61, 0x30,0x75,0x82,0x89,0x3c,0xca,0x74,0xa1,0x8e,0x14,0x7b,0x19,0xbe,0x85,0x04,0x68, 0x88,0x02,0x80,0xaa,0x00,0x10,0x86,0x68,0xd1,0x00,0x04,0x3b,0x7a,0x50,0x46,0x9e, 0x06,0x23,0xd4,0x27,0x75,0x54,0x38,0x05,0x57,0x37,0x85,0x81,0xca,0x78,0x65,0x3a, 0x7c,0x80,0xd9,0x1c,0xf9,0x1f,0x09,0xa0,0x7b,0x2c,0x51,0x4f,0x19,0x9f,0x72,0x89, 0xbb,0x06,0x24,0x40,0x0f,0x39,0xc1,0xcf,0x6b,0x13,0x15,0x78,0xc0,0x00,0x61,0xfd, 0x5a,0xf6,0xe0,0x45,0x02,0x70,0xe4,0x7f,0x16,0x89,0x62,0x5d,0xbb,0xb4,0x1f,0x1f, 0x1c,0x25,0x83,0x20,0xc8,0x7c,0xed,0xed,0x88,0xf6,0x20,0xe3,0x95,0xe9,0x1a,0xe8, 0x29,0x70,0xf7,0x52,0xf4,0x78,0x9f,0x3a,0xb9,0x70,0xa1,0x30,0xf0,0x69,0xf9,0x67, 0x42,0x56,0x94,0xa8,0x71,0x6f,0x5c,0x1e,0xae,0x6b,0xd7,0xf0,0x42,0x0a,0x00,0xb5, 0x4e,0xcb,0xbd,0xc3,0x58,0xb5,0x32,0x5f,0x01,0xa0,0x06,0x9e,0x02,0x20,0xc8,0x78, 0xdd,0x06,0x4e,0x99,0xde,0x84,0x75,0x99,0x9e,0x86,0xf7,0x35,0x8d,0xe2,0x1b,0x23, 0x70,0x8e,0xa4,0xac,0x2d,0x40,0x34,0xf0,0xa0,0x3b,0x89,0xc2,0x78,0xb5,0x4e,0x9d, 0x04,0x28,0x8d,0x04,0x50,0xf5,0x4b,0x02,0x08,0xc1,0xb0,0x6e,0x91,0xf6,0x2a,0x66, 0x37,0x8a,0xfe,0x72,0x9f,0xc5,0x35,0x01,0x46,0x8f,0x92,0xc3,0xb4,0x28,0x55,0xa0, 0x40,0x08,0x6f,0xe9,0xee,0x6c,0x80,0xd2,0xd9,0x00,0x1a,0x87,0xd1,0x9d,0xd0,0x9b, 0xd8,0xdb,0xc3,0xa2,0x7f,0x8c,0xdc,0x6b,0xba,0x7d,0x5e,0x88,0xc9,0x17,0xc9,0x61, 0x4a,0x1c,0x08,0x94,0xd1,0xf9,0x6e,0x49,0xe6,0xa8,0x69,0xea,0xa0,0x88,0x4c,0x0f, 0x32,0x7f,0xa2,0xdc,0xf3,0xbf,0xfe,0xb3,0x22,0x18,0x8c,0x24,0x78,0x36,0x4a,0x1d, 0x38,0xaa,0x68,0x42,0xec,0x8f,0xd3,0x9e,0xef,0xdb,0x79,0x11,0xe8,0xa3,0x42,0x7f, 0x49,0x53,0x1b,0x11,0xe3,0xa8,0xb2,0x69,0x4b,0x23,0x2f,0xfb,0x87,0x99,0x1f,0x29, 0x01,0x42,0xd2,0x00,0x17,0x71,0x9c,0xa4,0xe1,0x92,0x06,0x48,0xea,0x6c,0x42,0x61, 0x63,0x47,0x2d,0x8e,0x08,0xed,0x13,0xdd,0x9d,0xdd,0x18,0xe3,0x79,0x16,0x6b,0x3f, 0xae,0xf2,0xff,0x01,0x71,0x8a,0x65,0x57,0x95,0xb3,0xe7,0x00,0x00,0x00,0x00,0x00, 0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; ippsample/server/job.c0000644000175000017500000003341613240604116013772 0ustar tilltill/* * Job object code for sample IPP server implementation. * * Copyright © 2014-2018 by the IEEE-ISTO Printer Working Group * Copyright © 2010-2018 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ #include "ippserver.h" /* * 'serverCheckJobs()' - Check for new jobs to process. */ void serverCheckJobs(server_printer_t *printer) /* I - Printer */ { server_job_t *job; /* Current job */ if (printer->processing_job) return; _cupsRWLockWrite(&(printer->rwlock)); for (job = (server_job_t *)cupsArrayFirst(printer->active_jobs); job; job = (server_job_t *)cupsArrayNext(printer->active_jobs)) { if (job->state == IPP_JSTATE_PENDING) { _cups_thread_t t = _cupsThreadCreate((_cups_thread_func_t)serverProcessJob, job); if (t) { _cupsThreadDetach(t); } else { job->state = IPP_JSTATE_ABORTED; job->completed = time(NULL); serverAddEvent(printer, job, SERVER_EVENT_JOB_COMPLETED, "Job aborted because creation of processing thread failed."); } break; } } _cupsRWUnlock(&(printer->rwlock)); } /* * 'serverCleanJobs()' - Clean out old (completed) jobs. */ void serverCleanJobs(server_printer_t *printer) /* I - Printer */ { server_job_t *job; /* Current job */ time_t cleantime; /* Clean time */ serverLogPrinter(SERVER_LOGLEVEL_DEBUG, printer, "Cleaning jobs, %d completed jobs in memory...", cupsArrayCount(printer->completed_jobs)); if (cupsArrayCount(printer->completed_jobs) == 0) return; cleantime = time(NULL) - 60; serverLogPrinter(SERVER_LOGLEVEL_DEBUG, printer, "Clean time is %ld.", (long)cleantime); _cupsRWLockWrite(&(printer->rwlock)); for (job = (server_job_t *)cupsArrayFirst(printer->completed_jobs); job; job = (server_job_t *)cupsArrayNext(printer->completed_jobs)) if (job->completed && job->completed < cleantime) { serverLogJob(SERVER_LOGLEVEL_DEBUG, job, "Cleaning job #%d.", job->id); cupsArrayRemove(printer->completed_jobs, job); cupsArrayRemove(printer->jobs, job); /* Last since removing a job from here calls serverDeleteJob() */ } else if (job->completed) serverLogJob(SERVER_LOGLEVEL_DEBUG, job, "Not cleaning job #%d - completed on %ld.", job->id, (long)job->completed); else break; _cupsRWUnlock(&(printer->rwlock)); } /* * 'serverCopyJobStateReasons()' - Copy printer-state-reasons values. */ void serverCopyJobStateReasons( ipp_t *ipp, /* I - Attributes */ ipp_tag_t group_tag, /* I - Group */ server_job_t *job) /* I - Printer */ { server_jreason_t creasons; /* Combined job-state-reasons */ creasons = job->state_reasons | job->dev_state_reasons; if (!creasons) { ippAddString(ipp, group_tag, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "none"); } else { int i, /* Looping var */ num_reasons = 0;/* Number of reasons */ server_jreason_t reason; /* Current reason */ const char *reasons[32]; /* Reason strings */ for (i = 0, reason = 1; i < (int)(sizeof(server_jreasons) / sizeof(server_jreasons[0])); i ++, reason <<= 1) { if (creasons & reason) reasons[num_reasons ++] = server_jreasons[i]; } ippAddStrings(ipp, group_tag, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", num_reasons, NULL, reasons); } } /* * 'serverCreateJob()' - Create a new job object from a Print-Job or Create-Job * request. */ server_job_t * /* O - Job */ serverCreateJob(server_client_t *client) /* I - Client */ { server_job_t *job; /* Job */ ipp_attribute_t *attr; /* Job attribute */ char uri[1024], /* job-uri value */ uuid[64]; /* job-uuid value */ server_listener_t *lis = (server_listener_t *)cupsArrayFirst(Listeners); /* First listener */ _cupsRWLockWrite(&(client->printer->rwlock)); if (MaxJobs > 0 && cupsArrayCount(client->printer->active_jobs) >= MaxJobs) { _cupsRWUnlock(&(client->printer->rwlock)); return (NULL); } /* * Allocate and initialize the job object... */ if ((job = calloc(1, sizeof(server_job_t))) == NULL) { perror("Unable to allocate memory for job"); return (NULL); } job->printer = client->printer; job->attrs = ippNew(); job->state = IPP_JSTATE_HELD; job->fd = -1; /* * Copy all of the job attributes... */ serverCopyAttributes(job->attrs, client->request, NULL, IPP_TAG_JOB, 0); /* * Get the requesting-user-name, document format, and priority... */ if ((attr = ippFindAttribute(client->request, "job-priority", IPP_TAG_INTEGER)) != NULL) job->priority = ippGetInteger(attr, 0); else job->priority = 50; if ((attr = ippFindAttribute(client->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) job->username = ippGetString(attr, 0, NULL); else job->username = "anonymous"; ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-user-name", NULL, job->username); if (ippGetOperation(client->request) != IPP_OP_CREATE_JOB) { if ((attr = ippFindAttribute(job->attrs, "document-format-detected", IPP_TAG_MIMETYPE)) != NULL) job->format = ippGetString(attr, 0, NULL); else if ((attr = ippFindAttribute(job->attrs, "document-format-supplied", IPP_TAG_MIMETYPE)) != NULL) job->format = ippGetString(attr, 0, NULL); else job->format = "application/octet-stream"; } if ((attr = ippFindAttribute(client->request, "job-impressions", IPP_TAG_INTEGER)) != NULL) job->impressions = ippGetInteger(attr, 0); if ((attr = ippFindAttribute(client->request, "job-name", IPP_TAG_NAME)) != NULL) job->name = ippGetString(attr, 0, NULL); /* * Add job description attributes and add to the jobs array... */ job->id = client->printer->next_job_id ++; snprintf(uri, sizeof(uri), "%s/%d", client->printer->default_uri, job->id); httpAssembleUUID(lis->host, lis->port, client->printer->name, job->id, uuid, sizeof(uuid)); ippAddDate(job->attrs, IPP_TAG_JOB, "date-time-at-creation", ippTimeToDate(time(&job->created))); ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, uri); ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uuid", NULL, uuid); if ((attr = ippFindAttribute(client->request, "printer-uri", IPP_TAG_URI)) != NULL) ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, ippGetString(attr, 0, NULL)); else ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, client->printer->default_uri); ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation", (int)(job->created - client->printer->start_time)); cupsArrayAdd(client->printer->jobs, job); cupsArrayAdd(client->printer->active_jobs, job); _cupsRWUnlock(&(client->printer->rwlock)); return (job); } /* * 'serverCreateJobFilename()' - Create the filename for a document in a job. */ void serverCreateJobFilename( server_printer_t *printer, /* I - Printer */ server_job_t *job, /* I - Job */ const char *format, /* I - Format or NULL */ char *fname, /* I - Filename buffer */ size_t fnamesize) /* I - Size of filename buffer */ { char name[256], /* "Safe" filename */ *nameptr; /* Pointer into filename */ const char *ext, /* Filename extension */ *job_name; /* job-name value */ ipp_attribute_t *job_name_attr; /* job-name attribute */ /* * Make a name from the job-name attribute... */ if ((job_name_attr = ippFindAttribute(job->attrs, "job-name", IPP_TAG_NAME)) != NULL) job_name = ippGetString(job_name_attr, 0, NULL); else job_name = "untitled"; for (nameptr = name; *job_name && nameptr < (name + sizeof(name) - 1); job_name ++) if (isalnum(*job_name & 255) || *job_name == '-') *nameptr++ = (char)tolower(*job_name & 255); else *nameptr++ = '_'; *nameptr = '\0'; /* * Figure out the extension... */ if (!format) format = job->format; if (!strcasecmp(format, "image/jpeg")) ext = "jpg"; else if (!strcasecmp(format, "image/png")) ext = "png"; else if (!strcasecmp(format, "image/pwg-raster")) ext = "ras"; else if (!strcasecmp(format, "image/urf")) ext = "apple"; else if (!strcasecmp(format, "model/3mf")) ext = "3mf"; else if (!strcasecmp(format, "model/amf")) ext = "amf"; else if (!strcasecmp(format, "application/pdf")) ext = "pdf"; else if (!strcasecmp(format, "application/postscript")) ext = "ps"; else if (!strcasecmp(format, "application/sla")) ext = "stl"; else ext = "prn"; /* * Create a filename with the job-id, job-name, and document-format (extension)... */ snprintf(fname, fnamesize, "%s/%s/%d-%s.%s", SpoolDirectory, printer->name, job->id, name, ext); } /* * 'serverDeleteJob()' - Remove from the printer and free all memory used by a job * object. */ void serverDeleteJob(server_job_t *job) /* I - Job */ { serverLogJob(SERVER_LOGLEVEL_DEBUG, job, "Removing job #%d from history.", job->id); _cupsRWLockWrite(&job->rwlock); ippDelete(job->attrs); job->attrs = NULL; if (job->filename) { if (!KeepFiles) unlink(job->filename); free(job->filename); job->filename = NULL; } _cupsRWDeinit(&job->rwlock); free(job); } /* * 'serverFindJob()' - Find a job specified in a request. */ server_job_t * /* O - Job or NULL */ serverFindJob( server_client_t *client, /* I - Client */ int job_id) /* I - Job ID to find or 0 to lookup */ { ipp_attribute_t *attr; /* job-id or job-uri attribute */ server_job_t key, /* Job search key */ *job; /* Matching job, if any */ if (job_id > 0) { key.id = job_id; } else if ((attr = ippFindAttribute(client->request, "job-uri", IPP_TAG_URI)) != NULL) { const char *uri = ippGetString(attr, 0, NULL); /* job-uri value */ char scheme[32], /* URI scheme */ userpass[256], /* username:password */ host[256], /* Hostname/IP */ resource[1024]; /* Resource path */ int port; /* Port number */ if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) >= HTTP_URI_STATUS_OK && !strncmp(resource, client->printer->resource, client->printer->resourcelen) && resource[client->printer->resourcelen] == '/') key.id = atoi(resource + client->printer->resourcelen + 1); else return (NULL); } else if ((attr = ippFindAttribute(client->request, "job-id", IPP_TAG_INTEGER)) != NULL) { key.id = ippGetInteger(attr, 0); } _cupsRWLockRead(&(client->printer->rwlock)); job = (server_job_t *)cupsArrayFind(client->printer->jobs, &key); _cupsRWUnlock(&(client->printer->rwlock)); return (job); } /* * 'serverGetJobStateReasonsBits()' - Get the bits associates with "job-state-reasons" values. */ server_jreason_t /* O - Bits */ serverGetJobStateReasonsBits( ipp_attribute_t *attr) /* I - "job-state-reasons" attribute */ { int i, j, /* Looping vars */ count; /* Number of "job-state-reasons" values */ const char *keyword; /* "job-state-reasons" value */ server_jreason_t jreasons = SERVER_JREASON_NONE; /* Bits for "job-state-reasons" values */ count = ippGetCount(attr); for (i = 0; i < count; i ++) { keyword = ippGetString(attr, i, NULL); for (j = 0; j < (int)(sizeof(server_jreasons) / sizeof(server_jreasons[0])); j ++) { if (!strcmp(keyword, server_jreasons[j])) { jreasons |= (server_jreason_t)(1 << j); break; } } } return (jreasons); } /* * 'serverProcessJob()' - Process a print job. */ void * /* O - Thread exit status */ serverProcessJob(server_job_t *job) /* I - Job */ { job->state = IPP_JSTATE_PROCESSING; job->printer->state = IPP_PSTATE_PROCESSING; job->processing = time(NULL); job->printer->processing_job = job; serverAddEvent(job->printer, job, SERVER_EVENT_JOB_STATE_CHANGED, "Job processing."); while (job->printer->state_reasons & SERVER_PREASON_MEDIA_EMPTY) { job->printer->state_reasons |= SERVER_PREASON_MEDIA_NEEDED; sleep(1); } job->printer->state_reasons &= (server_preason_t)~SERVER_PREASON_MEDIA_NEEDED; if (job->printer->pinfo.command) { /* * Execute a command with the job spool file and wait for it to complete... */ serverTransformJob(NULL, job, job->printer->pinfo.command, job->printer->pinfo.output_format, SERVER_TRANSFORM_COMMAND); } else { /* * Sleep for a random amount of time to simulate job processing. */ sleep((unsigned)(1 + (CUPS_RAND() % 4))); } if (job->cancel) job->state = IPP_JSTATE_CANCELED; else if (job->state == IPP_JSTATE_PROCESSING) job->state = IPP_JSTATE_COMPLETED; job->completed = time(NULL); job->printer->state = IPP_PSTATE_IDLE; job->printer->processing_job = NULL; _cupsRWLockWrite(&job->printer->rwlock); cupsArrayAdd(job->printer->completed_jobs, job); cupsArrayRemove(job->printer->active_jobs, job); if (MaxCompletedJobs > 0) { /* * Make sure the job history doesn't go over the limit... */ while (cupsArrayCount(job->printer->completed_jobs) > MaxCompletedJobs) { server_job_t *tjob = (server_job_t *)cupsArrayFirst(job->printer->completed_jobs); if (tjob == job) tjob = (server_job_t *)cupsArrayNext(job->printer->completed_jobs); cupsArrayRemove(job->printer->completed_jobs, tjob); cupsArrayRemove(job->printer->jobs, tjob); /* Removing here calls serverDeleteJob */ } } _cupsRWUnlock(&job->printer->rwlock); serverAddEvent(job->printer, job, SERVER_EVENT_JOB_STATE_CHANGED, "Job fetchable."); return (NULL); } ippsample/server/log.c0000644000175000017500000001634013240604116013776 0ustar tilltill/* * Logging support for sample IPP server implementation. * * Copyright © 2014-2018 by the IEEE-ISTO Printer Working Group * Copyright © 2010-2018 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ #include "ippserver.h" #include /* * Local globals... */ static _cups_mutex_t log_mutex = _CUPS_MUTEX_INITIALIZER; static int log_fd = -1; /* * Local functions... */ static void server_log_to_file(server_loglevel_t level, const char *format, va_list ap); /* * 'serverLog()' - Log a message. */ void serverLog(server_loglevel_t level, /* I - Log level */ const char *format, /* I - Printf-style format string */ ...) /* I - Additional arguments as needed */ { va_list ap; /* Pointer to arguments */ if (level > LogLevel) return; va_start(ap, format); server_log_to_file(level, format, ap); va_end(ap); } /* * 'serverLogAttributes()' - Log attributes in a request or response. */ void serverLogAttributes( server_client_t *client, /* I - Client */ const char *title, /* I - Title */ ipp_t *ipp, /* I - Request/response */ int type) /* I - 0 = object, 1 = request, 2 = response */ { ipp_tag_t group_tag; /* Current group */ ipp_attribute_t *attr; /* Current attribute */ char buffer[8192]; /* String buffer for value */ int major, minor; /* Version */ if (LogLevel < SERVER_LOGLEVEL_DEBUG) return; major = ippGetVersion(ipp, &minor); serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "%s version=%d.%d", title, major, minor); if (type == 1) serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "%s operation-id=%s(%04x)", title, ippOpString(ippGetOperation(ipp)), ippGetOperation(ipp)); else if (type == 2) serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "%s status-code=%s(%04x)", title, ippErrorString(ippGetStatusCode(ipp)), ippGetStatusCode(ipp)); serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "%s request-id=%d", title, ippGetRequestId(ipp)); for (attr = ippFirstAttribute(ipp), group_tag = IPP_TAG_ZERO; attr; attr = ippNextAttribute(ipp)) { if (ippGetGroupTag(attr) != group_tag) { group_tag = ippGetGroupTag(attr); serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "%s %s", title, ippTagString(group_tag)); } if (ippGetName(attr)) { ippAttributeString(attr, buffer, sizeof(buffer)); serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "%s %s (%s%s) %s", title, ippGetName(attr), ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr)), buffer); } } } /* * 'serverLogClient()' - Log a client message. */ void serverLogClient( server_loglevel_t level, /* I - Log level */ server_client_t *client, /* I - Client */ const char *format, /* I - Printf-style format string */ ...) /* I - Additional arguments as needed */ { char temp[1024]; /* Temporary format string */ va_list ap; /* Pointer to arguments */ if (level > LogLevel) return; va_start(ap, format); if (client) { #ifdef HAVE_SSL if (httpIsEncrypted(client->http)) snprintf(temp, sizeof(temp), "[Client %dE] %s", client->number, format); else #endif /* HAVE_SSL */ snprintf(temp, sizeof(temp), "[Client %d] %s", client->number, format); server_log_to_file(level, temp, ap); } else server_log_to_file(level, format, ap); va_end(ap); } /* * 'serverLogJob()' - Log a job message. */ void serverLogJob( server_loglevel_t level, /* I - Log level */ server_job_t *job, /* I - Job */ const char *format, /* I - Printf-style format string */ ...) /* I - Additional arguments as needed */ { char temp[1024]; /* Temporary format string */ va_list ap; /* Pointer to arguments */ if (level > LogLevel) return; va_start(ap, format); snprintf(temp, sizeof(temp), "[Job %d] %s", job->id, format); server_log_to_file(level, temp, ap); va_end(ap); } /* * 'serverLogPrinter()' - Log a printer message. */ void serverLogPrinter( server_loglevel_t level, /* I - Log level */ server_printer_t *printer, /* I - Printer */ const char *format, /* I - Printf-style format string */ ...) /* I - Additional arguments as needed */ { char temp[1024]; /* Temporary format string */ va_list ap; /* Pointer to arguments */ if (level > LogLevel) return; va_start(ap, format); snprintf(temp, sizeof(temp), "[Printer %s] %s", printer->name, format); server_log_to_file(level, temp, ap); va_end(ap); } /* * 'serverTimeString()' - Return the local time in hours, minutes, and seconds. */ char * /* O - Time string */ serverTimeString(time_t tv, /* I - Time value */ char *buffer, /* I - Buffer */ size_t bufsize) /* I - Size of buffer */ { struct tm *curtime = localtime(&tv); /* Local time */ strftime(buffer, bufsize, "%X", curtime); return (buffer); } /* * 'server_log_to_file()' - Log a formatted message to a file. */ static void server_log_to_file( server_loglevel_t level, /* I - Log level */ const char *format, /* I - Printf-style format string */ va_list ap) /* I - Pointer to additional arguments */ { char buffer[8192], /* Message buffer */ *bufptr; /* Pointer into buffer */ ssize_t bytes; /* Number of bytes in message */ struct timeval curtime; /* Current time */ struct tm *curdate; /* Current date and time */ static const char * const pris[] = /* Log priority strings */ { "<63>", /* Error message */ "<66>", /* Informational message */ "<67>" /* Debugging message */ }; gettimeofday(&curtime, NULL); curdate = gmtime(&curtime.tv_sec); if (LogFile) { /* * When logging to a file, use the syslog format... */ snprintf(buffer, sizeof(buffer), "%s1 %04d-%02d-%02dT%02d:%02d:%02d.%03dZ %s ippserver %d - ", pris[level], curdate->tm_year + 1900, curdate->tm_mon + 1, curdate->tm_mday, curdate->tm_hour, curdate->tm_min, curdate->tm_sec, (int)curtime.tv_usec / 1000, ServerName, getpid()); } else { /* * Otherwise just include the date and time for convenience... */ snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ ", curdate->tm_year + 1900, curdate->tm_mon + 1, curdate->tm_mday, curdate->tm_hour, curdate->tm_min, curdate->tm_sec, (int)curtime.tv_usec / 1000); } bufptr = buffer + strlen(buffer); if ((bytes = _cups_safe_vsnprintf(bufptr, sizeof(buffer) - (size_t)(bufptr - buffer + 1), format, ap)) > 0) { bufptr += bytes; if (bufptr > (buffer + sizeof(buffer) - 1)) bufptr = buffer + sizeof(buffer) - 1; if (bufptr > buffer && bufptr[-1] != '\n') *bufptr++ = '\n'; if (log_fd < 0) { _cupsMutexLock(&log_mutex); if (log_fd < 0) { if (LogFile) { if ((log_fd = open(LogFile, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0644)) < 0) { fprintf(stderr, "Unable to open log file \"%s\": %s\n", LogFile, strerror(errno)); log_fd = 2; } } else log_fd = 2; } _cupsMutexUnlock(&log_mutex); } write(log_fd, buffer, (size_t)(bufptr - buffer)); } } ippsample/server/Makefile0000644000175000017500000000342713240604116014513 0ustar tilltill# # Makefile for sample IPP server implementation. # # Copyright © 2014-2018 by the IEEE-ISTO Printer Working Group. # Copyright © 2015-2018 by Apple Inc. # # Licensed under Apache License v2.0. See the file "LICENSE" for more # information. # include ../Makedefs # # Object files... # OBJS = \ client.o \ conf.o \ device.o \ ipp.o \ job.o \ log.o \ main.o \ printer.o \ subscription.o \ transform.o # # Targets in this directory... # TARGETS = ippserver # # Make all targets... # all: $(TARGETS) # # Remove object and target files... # clean: $(RM) $(OBJS) $(TARGETS) # # Update dependencies (without system header dependencies...) # depend: $(CC) -MM $(ALL_CFLAGS) $(OBJS:.o=.c) >Dependencies # # Install the server. # install: all $(INSTALL_DIR) -m 755 $(BUILDROOT)$(sbindir) $(INSTALL_BIN) ippserver $(BUILDROOT)$(sbindir)/$(IPP)server # # Test the server. # test: # # ippserver # ippserver: $(OBJS) ../cups/libcups.a echo Linking $@... $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) # # printer-png.h # printer-png.h: printer.png echo "Generating printer-png.h from printer.png..." echo "static const unsigned char printer_png[] =" >printer-png.h echo "{" >>printer-png.h od -t x1 printer.png | cut -b12- | awk '{printf(" "); for (i = 1; i <= NF; i ++) printf("0x%s,", $$i); print "";}' >>printer-png.h echo "};" >>printer-png.h # # printer3d-png.h # printer3d-png.h: printer3d.png echo "Generating printer3d-png.h from printer3d.png..." echo "static const unsigned char printer3d_png[] =" >printer3d-png.h echo "{" >>printer3d-png.h od -t x1 printer3d.png | cut -b12- | awk '{printf(" "); for (i = 1; i <= NF; i ++) printf("0x%s,", $$i); print "";}' >>printer3d-png.h echo "};" >>printer3d-png.h # # Dependencies... # include Dependencies ippsample/server/printer.opacity0000644000175000017500000012331213240604116016124 0ustar tilltillbplist00X$versionX$objectsY$archiverT$top*dpqrstxy !()9:;<=>?@HLPSTAcW]dou{|   :=@EKQTUVWX]^_fk$*04JMRX^cden~   "%*06:PSX^dijk}  &,/01237MPU[afgh{$'-069:;<=AWZ_ekpqr} &,123>JVbjklmnopqrstuv~ #+,-./01234567?QRfilqw}   ' * - 2 8 > A E [ ^ c i o t u v     * 0 1 E H K P V \ _ c y |    ! ' * + , - . 3 4 5 : L R S T U i l q w }    ! & ' ( 9 < = Q T W \ b h k l m n o s     $ % & 8 > ? S V [ a g k   (/:@FGKLRSW\ntuvw '+26PQRu9:%)=>?@ABCDEFGHIM_`abcdefpqryz{|}<U$null0  !"#$%&'()*+,-./0123456789:;<=>??ABC::DEFGHI:JKLMAO?QRSTUAWXYZ[C]^_`?C[cGUNSRGB\NSColorSpace_NSCustomColorSpaceJ0 0 0 0.524I"JKTNSID3z{MN\NSColorSpaceO~\NSColorSpacez{QRWNSColorQ~#V#@ z{XYXPCFilterZ[\~XPCFilterZPCDrawableXPCObjectz{^_]PCFilterLayer`abc~]PCFilterLayerWPCLayerZPCDrawableXPCObject"::cfgAikcm@< AD#@Y"?rC;=ef"vxow>y? #?"g~<#?WPrinteref"oBC #?";#?f"wEӁ2Vzс "cEAAcAcTrectSisIVcomTypWfilPropSshXTantiSflVTvecsUstrosSshYUalPixSangSflHF G# k[#; #_{{0, 0}, {0, 0}}"c::?::AVrelLP2SblHWgradAngUradGCTfilTWrelRadCVfilPosSaEqStypXrelLinP1VfilColVrelLP1UfilImVothColXrelLinP2SgEqUfilGrSrEqXgradStopUpgNumSbEqT#@ QQZYSHRIEUWVJX AB"EGF0 0 04AB"EGL0.6 0.6 0.64f"KNP"?=ValtColSlocScolG#LMB"<GWNSWhiteB14z{^PCGradientStop~^PCGradientStopZPCDrawableXPCObject"?G#@YOMAB"EGL0.6 0.6 0.64z{  ^NSMutableArray |~V{0, 0}_{0, -0.38275384010550079}_{0, -0.59095584796146183}_{0, -0.38275384010550079}_{0, -0.59095584796146183}Q0QtW100 - tS100z{_PCDrawVectorProperties~_PCDrawVectorPropertiesZPCDrawableXPCObjectf"\P "!"#$%c(:*:,?./:A24:^7:9TcapSSposUinvisSwidUdashSeQ#@VQjYdc^E fW#?]V_XgB";<GB04AB">EGL0.4 0.4 0.44f"ABC`aP"?H^\#]M"?NO\#@YbMAB"REGL0.4 0.4 0.44_{0, -0.38275384010550079}_{0, -0.59095584796146183}_{0, -0.38275384010550079}_{0, -0.59095584796146183}f"YwZ[hi #@ #z{`a_PCStrokeVectorPropertiesbcde~_PCStrokeVectorProperties_PCDrawVectorPropertiesZPCDrawableXPCObjectf"gwhil lmn"opcAstAcwxyz{A~cUdimLKVcornRXVcornRYmp q# #@ #@ v#E #ef"ono ]cornerRadiusX]cornerRadiusY_5{{19.002601226657074, 14.001547070515279}, {100, 64}}"cE:=?h:EcQ#@ QQZYQLQrlQWVsXAB"EGL0.6 0.6 0.64f"tuP"?s=q#LM"?sq#@YrMf"wP "!"#$c:*:?h:A:^EʀQQ#@VQjYQQxl QW#?]VyX|AB"EGL0.4 0.4 0.44f"рz{P"?^w#]M"?w#@YxMf"w}~ #@ #z{\PCRectVector~\PCRectVector\PCPathVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObjectlmn"cAAcyAc # ###E #ef"ono _4{{47.002601226657077, 64.501547070515272}, {76, 14}}"c E:=?i:EcQ#@VQQZYQLQQWVXAB"EGL0.6 0.6 0.64f" !"P"?'=#LM"?-#@YMf"12P "!"#$c8:*:??i:AD:^GEIQQ#@VQjYQQ QW#?]VXAB"KEGL0.4 0.4 0.44f"NOPP"?2U^#]M"?2[?#@YMf"_w`a #@ #z{fg_PCPathGroupVectorhijklm~_PCPathGroupVector\PCPathVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObject"ocEArsAcvxyA|c # #; #_{{0, 0}, {0, 0}}"c::?::A#@ QQZYWV AB"EGO'0.1897665858 0.1897609085 0.18976412714AB"EGL0.6 0.6 0.64f"P"?r=#LM"?r#@YMAB"EGL0.6 0.6 0.64_{0, -0.3827538401055009}_{0, -0.59095584796146183}_{0, -0.3827538401055009}_{0, -0.59095584796146183}W100 - tf"P "!"#$c:*:?:A:^:ˀQ#@VQjY W#?]VAB"EGL0.4 0.4 0.44f"ҀP"?^#]M"?#@YMAB"EGL0.4 0.4 0.44_{0, -0.3827538401055009}_{0, -0.59095584796146183}_{0, -0.3827538401055009}_{0, -0.59095584796146183}f"wꀬ #@ #f"w񀯀€ lmn"cAAcyAc # #@ #@ # #ef"o ]cornerRadiusX]cornerRadiusY_{{8, 9}, {100, 64}}"cE:=?:EcQ#@ QQZYQLQQWVAB"#EGL0.6 0.6 0.64f"&'(P"?-=#LM"?3#@YMf"78P "!"#$c>:*:?E:AJ:^MEOQQ#@VQjYQQ QW#?]VAB"QEGL0.4 0.4 0.44f"TUVP"?8[^#]M"?8aE#@YMf"ewfg #@ #lmn"lmcApqActuywxA{cÀ # ### #ef"~o _{{36, 59.5}, {76, 14}}"cE:=?:EcQ#@VQQZYQLQƀ€QWVǀAB"EGL0.6 0.6 0.64f"ȀɀP"?p=#LM"?p#@YƀMf"ˀP "!"#$c:*:?:A:^EŀQQ#@VQjYQQ̀ QW#?]V̀AB"EGL0.4 0.4 0.44f"̀΀πP"?^#]M"?#@ỲMf"w݀рҀ #@ #"cAAcAcVfConPtVconPtsVlConPtԀ # #; #_{{101, 9}, {18, 56}}"cE::?:EA#@VQQZY߀րހ׀ӀWV؀ AB" EGO$0.192297894 0.192297894 0.1922978944AB"EGO'0.2923743207 0.2923743207 0.29237432074f"ـۀ܀P"?#ڀMAB"EGO*0.01031759511 0.01031759511 0.010317595114"?##@Y׀M"?)*#@;+ \݀MAB"-EGO'0.2265200408 0.2265200408 0.22652004084_{17, -28.000000000000004}_{94.444444444444443, -50}_{0, 28.000000000000018}_{0, 50.000000000000028}f"45P "!"#$c;:*:?B:AG:^JELQQ#@VQjYQQ QW#?]V借AB"NEGL0.4 0.4 0.44f"QRSP"?5X^#]M"?5^B#@YMf"bwcd #@ #ijklmnop"cAcuvcxyz:YhasConPt1VcPLinkUisCloRptTnextYhasConPt2VconPt1VconPt2 Ӂnp"|loijmkc~zEcAcTprev Ӏnp"|loijmkczvEcAc Ӏnp"|loijmkczEcAc Ӏnp"|loijmkczEcAc Ӏnp"|loijmkczEcAc Ӏikj"n|cEAAzc z{]PCCustomPoint~]PCCustomPointZPCDrawableXPCObjectY{108, 16}Y{108, 16}Y{108, 16}Y{108, 59}Y{108, 59}Y{108, 59}Y{119, 65}Y{119, 65}Y{119, 65}Y{119, 19}Y{119, 19}Y{119, 19}Y{114, 14}Y{114, 14}Y{114, 14}X{101, 9}X{101, 9}X{101, 9}f"vPz{^PCCustomVector~^PCCustomVector\PCPathVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObject"cAAcAc 1  # $#; #_{{35, 59}, {84, 6}}"cE::?  :EA#@VQQZY  WV AB"EGO'0.1790293818 0.1790293818 0.17902938184AB"EGL0.6 0.6 0.64f" P"?!" #MAB"%EGO'0.2920346467 0.2920346467 0.29203464674"?*+ #@YMAB".EGO'0.3288255774 0.3288255774 0.32882557744"?34 #@GSMAB"7EGO'0.2026154891 0.2026154891 0.20261548914_{0, -3.0000000000000071}_{0, -50.000000000000121}_{0, 3.0000000000000142}_{0, 50.000000000000242}f">?P "!"#$cE:*:?L:AQ:^TEVQQ#@VQjYQQ QW#?]VAB"XEGL0.4 0.4 0.44f"[\]P"??b^#]M"??hL#@YMf"lwmn #@ #ijklmnop"cAcwxcz{z: .!/0np"|loijmkczEcAc- +, "np"|loijmkczxEcAc*!() #np"|loijmkczEcAc'"%& $ikj"n|cEAAzc  #X{48, 65}X{48, 65}X{48, 65}Y{119, 65}Y{119, 65}Y{119, 65}Y{108, 59}Y{108, 59}Y{108, 59}X{35, 59}X{35, 59}X{35, 59}f"x !"#$P"cAAcAc3DU 4# H;#; #_{{36, 59}, {11, 19}}"cE:?:EAQ#@VQQZYQ5Q62QWV7 AB"EGO'0.2802522079 0.2802522079 0.28025220794AB"EGO'0.3288680367 0.3288680367 0.32886803674f"89P"?=4#LM"?4#@Y:MAB"EGL0.6 0.6 0.64f"AAB"EGL0.4 0.4 0.44f"?@P"?#^<#]M"?) <#@Y=Mf"-w./BC #@ #ijklmnop"cAc89c;<z: 2RESTnp"|loijmkc@zCEDcAHcQDOP 2Fnp"|loijmkcLz9OEPcATcNELM 2Gnp"|loijmkcXzH[E\cAcKFIJ 2Hikj"n|cEAAzcT 2 GX{47, 78}X{47, 78}X{47, 78}X{36, 72}X{36, 72}X{36, 72}X{36, 59}X{36, 59}X{36, 59}X{47, 65}X{47, 65}X{47, 65}f"w9HTȁDEFGHP"cAAcAcWhy X# l_#; #_{{13, 72}, {34, 7}}"cE:?:EAQ#@VQQZYQYQZVQWV[ AB"EGO'0.3420940897 0.3420940897 0.34209408974AB"EGO'0.2653277853 0.2653277853 0.26532778534f"\]P"?=X#LM"?X#@Y^MAB"EGL0.6 0.6 0.64f"`P "!"#$c:*:?:A:^E؀QQ#@VQjYQQaV QW#?]VbeAB"EGL0.4 0.4 0.44f"߁cdP"?^`#]M"?`#@YaMf"wfg #@ #ijklmnop"cAccz: Vviwxnp"|loijmkczEcA cuhst Vjnp"|loijmkc zEcAcripq Vknp"|loijmkcz EcAcojmn Vlikj"n|cEAAzc V kX{35, 72}X{35, 72}X{35, 72}X{47, 78}X{47, 78}X{47, 78}X{28, 79}X{28, 79}X{28, 79}X{13, 72}X{13, 72}X{13, 72}f"8 hijklP"@AcCAEFAcJKLAOc{ |# #; #_{{37.5, 62.5}, {41, 7}}"cUE:[?^:cEAQ#@VQQZYQ}Q~zQWV AB"gEGO'0.2359459918 0.2359459918 0.23594599184AB"jEGO*0.06109884511 0.06109884511 0.061098845114f"mnoP"?Et=|#LM"?Ez{|#@YMAB"~EGL0.6 0.6 0.64f"P "!"#$c:*:?:c:^EQQ#@VQjYQQzQW#?]VAB"EGL0.4 0.4 0.44f"P"?^#]M"?#@YMf"w #@ #ijklmnop"cAccz: znp"|loijmkczAEcAc znp"|loijmkczEcAc znp"|loijmkczEcAJc zikj"n|cEAAzc z \{46.5, 66.5}\{46.5, 66.5}\{46.5, 66.5}\{78.5, 69.5}\{78.5, 69.5}\{78.5, 69.5}\{70.5, 65.5}\{70.5, 65.5}\{70.5, 65.5}\{37.5, 62.5}\{37.5, 62.5}\{37.5, 62.5}f"AJP"  c A  Ac A c # #; #_{{37, 62}, {9, 12}}"c E: ? : $EAQ#@^QQZYQQQWV AB" (EGO*0.04050611413 0.04050611413 0.040506114134AB" +EGO'0.2160962976 0.2160962976 0.21609629764f" . / 0P"?  5=#LM"?  ; <#@YMAB" ?EGL0.6 0.6 0.64f" B CP "!"#$c I:*:? P:A U:^ XE ZQQ#@VQjYQQ QW#?]VAB" \EGL0.4 0.4 0.44f" _ ` aP"? C f^#]M"? C l P#@YMf" pw q r #@ #ijklmnop"cAc { |c ~ z: np"|loijmkc z  E cA c np"|loijmkc z | E cA c np"|loijmkc z E cA c ikj"n|cEAAzc   X{46, 74}X{46, 74}X{46, 74}X{46, 67}X{46, 67}X{46, 67}X{37, 62}X{37, 62}X{37, 62}\{37.5, 69.5}\{37.5, 69.5}\{37.5, 69.5}f"   | P  " c A? Ac A cSpt1Spt2 # ρЁ#; #_{{0, 0}, {0, 0}}f"  ׁŀP "!"#$c :*:? :c :  E QQ#@VQjYQQǁQW#?ƀVȀAB" EGO'0.1716202446 0.1716202446 0.17162024464AB" EGL0.4 0.4 0.44f"  ɁʀP"? ^#]M"?  #@YǀMf" w  ́̀ #@ #W{9, 28}Y{108, 28}z{  \PCLineVector      ~\PCLineVector\PCPathVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObjectlmn"  cA  Ac ! "y $ %A (cҁ #& #@#@#; #ef" + -o _{{15, 42}, {87, 13}}"c 4E: :? =: BEAQ#@VQQZYQՀQցрQWV׀ AB" FEGJ0 0 0 0.24AB" IEGK0 0 0 0.194f" L M N؁ـP"?  S=#LM"?  Y Z#@YڀMAB" ]EGL0.6 0.6 0.64f" ` a܀P "!"#$c g:*:? n:A s:^ vE xQQ#@VQjYQQ݁ QW#?]VހAB" zEGL0.4 0.4 0.44f" } ~ ߁P"? a ^#]M"? a n#@Y݀Mf" w  #@ #"  cA A c A cVorBnds # #; ~#_T{{12.000000000000002, 44.249136083608384}, {90.543616808306169, 11.503086363086119}}f" w *i  " cEA Ac  A cVpreTKV # # # " WNS.dataO streamtyped@z{ ]NSMutableData ~VNSData_{{0, 0}, {0, 0}}" c E: ? : : A#@VQQZYWV AB" EGJ0 0 0 0.54AB" EGK0 0 0 0.754f"  P"? =#LM"? #@YMAB" EGL0.6 0.6 0.64_{0, 5.1463130614683354}_{0, 44.738541457734918}_{0, 5.1463130614683354}_{0, 44.738541457734918}W100 - tf"  P "!"#$ c :*: ?   :A  :^ : Q#@VQjY W#?]VAB" EGL0.4 0.4 0.44f"   P"? ^#]M"? $ %#@YMAB" (EGL0.4 0.4 0.44_{0, 5.1463130614683354}_{0, 44.738541457734918}_{0, 5.1463130614683354}_{0, 44.738541457734918}f" /w 0 1 #@ #f" 6w 7 8 lmn" ; <cA ? @Ac C Dy F G A Jc   #@6 #@#@# #ef" M Oo N P ]cornerRadiusX]cornerRadiusY_T{{15.394291957465503, 44.252204139492406}, {86.622653214236578, 21.789508371540805}}"c XE:=? a 7: fE cQ#@VQQZYQLQ QWV AB" jEGL0.6 0.6 0.64f" m n oP"? ? t= #LM"? ? z a #@Y Mf" ~ P "!"#$c :*:? 7:A :^ E QQ#@VQjYQQ QW#?]VAB" EGL0.4 0.4 0.44f"  P"?  ^#]M"?  #@YMf" w  #@ #lmn" cA Ac y A c # ##!# #ef" o N P _T{{12.933421127515606, 55.752222446694503}, {96.466136534036195, 15.736867157223941}}"c E:=? 8: E cQ#@VQQZYQLQQWVAB" EGL0.6 0.6 0.64f"   P"? =#LM"? #@YMf"  "P "!"#$c :*:?  8:A :^ E QQ#@VQjYQQ# QW#?]V$'AB" EGL0.4 0.4 0.44f"   %&P"? ^"#]M"?  "#@Y#Mf" "w # $() #@ # " ) *cEA - .Ac 1 3 4A 7c+, -# F8# # " : O streamtyped@NSMutableDictionary NSDictionaryNSObjectiNSString+sizeWidthCenteredNSNumberNSValue*dsizeHeightCentered_{{0, 0}, {0, 0}}" >c @E: E F G? I K: N:A6#@VQQZY5.4/*7WV0 AB" REGO$0.403851053 0.403851053 0.4038510534AB" UEGO'0.2658160666 0.2658160666 0.26581606664f" X Y Z12P"? - _=-#LM"? - e f-#@Y3MAB" iEGL0.6 0.6 0.64_{0, 4.2515341609509996}_{0, 44.738541457734918}_{0, 4.2515341609509996}_{0, 44.738541457734918}f" p q9P "!"#$ tc w:*: {? } ~ :A  :^ : AQ#@VQjY@?:* BW#?]V;CAB" EGL0.4 0.4 0.44f"  <=P"? q ^9#]M"? q 9#@Y>MAB" EGL0.4 0.4 0.44_{0, 4.2515341609509996}_{0, 44.738541457734918}_{0, 4.2515341609509996}_{0, 44.738541457734918}f" w DE #@ #f" w GX lmn" cA Ac y A cHI J#@6 #@#@O#* #ef" o _4{{14.336510027119617, 46.003068321901999}, {88, 18}}"c E:=? : EcQ#@VQQZYQLQKGQWVLAB" EGL0.6 0.6 0.64f"  MNP"? =J#LM"? J#@YKMf"  PP "!"#$c :*:? :A :^ E QQ#@VQjYQQQG QW#?]VRUAB" EGL0.4 0.4 0.44f"   STP"? ^P#]M"?  P#@YQMf" w ! "VW #@ #lmn" ' (cA + ,Ac / 0y 2 3 A 6cYZ [# ##`#* #ef" 9 ;o _4{{11.836510027119623, 55.503068321901999}, {98, 13}}"c BE:=? K : PEcQ#@VQQZYQLQ\XQWV]AB" TEGL0.6 0.6 0.64f" W X Y^_P"? + ^=[#LM"? + d K[#@Y\Mf" h iaP "!"#$c o:*:? v :A {:^ ~E QQ#@VQjYQQbX QW#?]VcfAB" EGL0.4 0.4 0.44f"  deP"? i ^a#]M"? i va#@YbMf" w gh #@ # mn"l c cA Ac y A kl m#@6 #@#@t# #jef" o " O streamtyped@_#{{24.207106781186546, 48}, {12, 6}}"c E: ? : EAQ#@VQQZYQnQoiQWVp AB" EGO0.6863980707 0.8061224313 14AB" EGO0.3126169177 0.3186546528 0.64f"  ցqrP"? =m#LM"? m#@YsMAB" EGL0.6 0.6 0.64f"  uP "!"#$c :*:? :c :  EQQ#@VQjYQQwiQW#?vVx{B"<GF0 0.54AB"EGL0.4 0.4 0.44f"  yzP"? ^u#]M"?  u#@YwMf"w|} #@ #_T{{12.000000000000002, 44.249136083608384}, {90.543616808306169, 11.503086363086119}}z{!"]PCGroupVector#$%&'~]PCGroupVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObjectz{)*]PCFolderLayer+,-.~]PCFolderLayerWPCLayerZPCDrawableXPCObject"::c12A46c8S #@Y"?=Cef"ACoBD #?"2I#?ZBackgroundef"MOoNP #?"U#?f"XwYZ lmn"]^cAabAcefyhiAlc # #@(#@(# #ef"oqopr ]cornerRadiusX]cornerRadiusY_{{0, 0}, {128, 128}}"cz::=?Y:EAQ#@VQQZYQLQQWV AB"EGL0.6 0.6 0.64f"P"?a=#LM"?a#@YMW100 - tf"P "!"#$c:*:?Y:A:^EQQ#@VQjYQQ QW#?]VAB"EGL0.4 0.4 0.44f"P"?^#]M"?#@YMf"wс #@ #" ccAAcAcTstrYXstrTBndsTstrXVattStr#@Y #@Y# # #_{{0, 64}, {128, 56}}"XNSString\NSAttributesYippserveref"^]WNSColor_NSParagraphStyleVNSFont"?ZNSTabStops[NSAlignmentz{_NSMutableParagraphStyle ~_NSMutableParagraphStyle_NSParagraphStyle   "VNSSizeXNSfFlagsVNSName#@8_.LucidaGrandeUIz{VNSFont~z{~z{_NSAttributedString~_NSAttributedStringB"<GD1 04z{ !\PCTextVector"#$%&~\PCTextVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObjectf"(wŁ z{,-WPCFrame./01~WPCFrame_PCMetadataObjectZPCDrawableXPCObjectf"3w4 789:";<=>?@ Acc?EF?:H?AccNCYauSizCropVnewFacUapIn1TpathTapIDUcropRUapIn2UisRelUisColTcropVvarValπ _{{0.5, 0}, {0, 0}}[printer.pngSTUVWXY"Z[\]^_`abcASfghi?klmAop4rsZUcodeSUprColVprShTiSfraVcodePlVcodeFrUcodeFTsnShVexPropTpropUgenCHUgrTypVanLooCVprLinCUcodeL Ɂʁ́΀ǁ ȁˀef"v}owxyz{|~=LĀ V{JFIF}U{GIF}_"kCGImageDestinationBackgroundColorU{PNG}V{TIFF}_*kCGImageDestinationLossyCompressionQualityef"o ef"o ef"o ef"o¡À [Compression#?Zpublic.png]public.folderef"o AB"EGL0.5 0 0 0.54SiosUcocoaUtouchVMyViewVUIViewz{_PCBitmapProperties~_PCBitmapPropertiesXPCObjectz{YPCFactory~YPCFactoryZPCDrawableXPCObjectf"저PYselectionZ{128, 128}B"<GE0.754_CICheckerboardGeneratorSTUVWXY"Z[\]^_`abcASfghi?AopsZ Ɂʁ́΀݁ց ƀށˀef"owxyz{|=ׁ؀Lفځۀ ef"o ef"o ef"o ef"o¡À #?_com.likethought.opacity.opacityef"o AB"EGL0.5 0 0 0.54ef" o76  77787888 _framePickerVisibleZhideRulers[windowFrame_layerViewDimension]hideVariablesZexpansionsYprintInfo]toolbarHidden_editFrameMetadata_{{62, 0}, {1195, 778}}#@cef" "o!67 "&'(\NSAttributesef"*3o+,-./0126567!6:;77 _NSHorizontallyCentered]NSRightMargin\NSLeftMargin_NSHorizonalPagination_NSVerticalPagination_NSVerticallyCentered[NSTopMargin^NSBottomMargin"B"B"B"Bz{JK[NSPrintInfoL~[NSPrintInfoef"NVoOPQRSTUWX4Z[O]  _"com.likethought.opacity.preview.ui_(com.likethought.opacity.preview.elementsWfactory_#com.likethought.opacity.preview.web_&com.likethought.opacity.preview.cursorTtype_&com.likethought.opacity.preview.iphoneef"gkohTj=!nL Ucolor[resolutionsf"stuvw    P#?#?#?#@ef"~o777888 VstatusWtoolbarTdockef"o WaddressUimage_#http://likethought.com/opacity/web/_,http://likethought.com/opacity/web/image.pngef"oTh=L XhotspotXXhotspotY##ef"ohT !"=!!#L$%&' UrectXUrectHUrectWUrectYTleftStop#@4#@F#@i#@4f"wY z{WPCImage~WPCImage_PCMetadataObjectZPCDrawableXPCObject_NSKeyedArchiverTroot"+5:?`hptz%,2;AFNS[ahov{       % - 8 ? A C E L N P R T a p   - 6 ? A C E G I Z ^ b d m o q z      - 2 8 > @ B D M P S ` g i k m t v x z |         1 7 < > @ B D F S V X [ ] _ h u w    $ , 5 : < > @ m q s t v x   *7DFHJLNP]_acegikw   "+8=JS[`irst})*,./1356?AVXZ\^`mpruwy   chls{HOS[afnuy} (*38:<>SZ^bdfoqs+29Uq!!#%:<>GIK`bdmoq~  #,GRm   %.02;=>GHUXZ]_ao}$&(*,.02468:<>@BCP]_hmoqsBDEGPRTVXZ\^`acenprtvx#0?LYmv "%')` 357@BDY[]fhjsvxz   !#0=?HMOQShjluwy&/:C ) + , 5 7 9 ; = ? A C E G I K M O Q S T a !!! !!#!%!@!\!w!!!!!!"" "!"#","."0"2"4"6"8":"<"="?"A"J"L"N"P"R"T"a"n"p"y"~""""""""""""""""""####>#Z#c#h#j#l#n#w################$$$$ $$$$$'$*$,$/$1$3$A$O$e$$$$$$$$$$$$$$$$$$$$%% %%%%%!%#%8%:%<%E%G%I%^%`%b%k%m%o%x%{%}%%%%%&&&&&& & &&&&&&& &"&$&&&(&5&B&D&M&R&T&V&X&m&o&q&z&|&~&&&&&&&&&&&&&'''''''"'#'$'-'6'8':'C'E'F'O'P']'`'b'e'g'i''''''''''''((((( ( ( ((((*(,(5(:(<(>(@(U(W(Y(b(d(f({(}(((((((()))))))!)#)%)')))+)-).)0)2);)=)?)A)C)E)R)_)a)j)o)q)s)u)))))))))))))))))))*.*5*<*C*E*G*H*K*L*N*W*X*Y*\*^*`*i*k*l*u*v******++++++ + +++++++++(+O+Q+^+++++++++++++++,,,,,,&,(,*,?,A,C,L,N,P,],,,,,,,----x-z-{-}-----------------------------.......&.(.*.3.8.:.<.>.G.P.}.....................///// / / ////B/C/E/G/I/K/M/N/O/Q/S/T////////////////////////0 0 00000000000>0?0@0B0C0E0F0H0Q0_0h0v000000000000011 11 1)121;1D1S1U1W1Y1[1]1_1a1c1l1{111111122!2$2%2(2)2,2526272:2=2@2I2K2L2U2V2l222222222222222222333393;3H3U3W3`3g3j3m3p3r333333333333333442444I4K4N4W4Z4\4i44444455 55555555555555555555555555555555666 6666+6-60696<6>6G6L6O6R6T6]6f666666666666666666666667"7#7&7(7+7.71727376797:7k7l7o7q7t7w7z7{7|77777777777777777778888"8+86898<8?8B8E8G88888888888888888889@9B9C9L9N9P9R9T9V9Y9[9]9`9c9e9g9i9l9n9o9|9999999999: ::::::3:5:8:A:D:F:S:`:b:k:n:q:s::::::::::;;;;; ; ;;;;;; ;-;:;<;E;J;M;P;R;g;i;l;u;w;y;;;;;;;;;;;;;;;;;;;<<<< < <<<=<@>>>> > >>>>">#>9>>>>>>>>>>>>>>>>>>>>>????;?=?F?K?N?Q?S?h?j?m?v?x?z?????????????@B@D@E@G@P@R@T@V@X@Z@\@_@b@c@e@g@p@r@t@w@y@|@@@@@@@@@@@@@@@@@@@@AA AAAAA%ARASATAUAXA[A^A_AbAeAgAAAAAAAAAAAAAAAAAAAAAAAAB*B+B.B0B3B6B9B:B;B>BABBBcBdBeBhBiBkBlBoBxBBBBBBBBBBBBBBBBBBCCGCJCMCNCQCRCUC^C_C`CcCfCiCrCtCuC~CCCCCDD D DDDDDDDDD!D#D%D(D*D+D8DbDdDqDDDDDDDDDDDDDDDDEEEEEE!E*E-E0E2EEEEEEEEEEEEEEEEEEEEEEEEEFF F FFF&F(F+F4F6F8FMFOFRF[F^F`FiFnFqFtFvFFFFFFFFFFFFFFFFGGGG G G GGGGDGEGHGJGMGPGSGTGUGXG[G\GGGGGGGGGGGGGGGGGGGGGGGHHH H-H:HGHTHaHnHwHHHHHHHHHHHHHHHHHHHHIIIIII(IIIIIIIIIIIIIIIIIIIIIIIJJ-J/J8J=J@JCJEJZJ\J_JhJjJlJJJJJJJJJJJJJK4K6K7K9KBKDKFKHKJKLKNKQKTKUKWKYKbKdKfKiKkKnK{KKKKKKKKKKKKKKKKKKKKKLLLLLLDLELFLGLJLMLPLQLTLWLYLLLLLLLLLLLLLLLLLLLLLLLLMMM M"M%M(M+M,M-M0M3M4MUMVMWMZM[M]M^MaMjMsM|MMMMMMMMMMMMMMMMMNANENINLNMNPNQNSN\N]N^NaNdNgNpNrNsN|N}NNNNNOOOOO"O$O&O(O*O,O.O1O4O5O7O9OBOEOGOJOLOOO\OOOOOOOOOOOOOOOOOOOPPP PPPPPP(P1P9PCPLPYPhPuPPPPPPPQQQQQQQQQ"Q$Q'Q0Q2Q3QSGSISKSMSOSQSSSVSYSZS\S^SgSiSkSnSpSsSSSSSSSSSSSSSSSSSSSSSTTTT TTTUT\T_T`TaTjTkTnToTrT{T}T~TTTTTTTTTTUDUKUNUQURUSUVU_U`UaUdUfUiUrUuUvUUUUUUUUUUUVFVIVJVSVUVWVYV[V^VaVdVfViVlVoVqVsVvVyVzVVVVVVVVVVVVVVVVVWWWWWWW!W.W0WJWdW~WWWWWWX$X'X(X*X3X5X7X9XXAXDXGXHXKXMXVXXXZX]X`XcXpX}XXXXXXXXXXXXXXXXXXXXYYY4YNYhYqYvYyY|Y~YYYYYYYYYYYYYZZZZ ZZZZ#Z&Z'Z0Z1Z>ZAZDZGZJZLZZZhZ["[$[%[.[0[2[4[6[8[:[<[>[A[D[F[H[J[M[P[Q[^[k[m[v[{[~[[[[[[[[[[[[[[[[[[\V\X\Y\[\d\f\h\j\l\n\p\s\v\w\y\{\\\\\\\\\\\\\\\\\\\\\]]] ]]]] ]#]&](]1]:]]]]]]]]]]]]]]]]]]]]]]]]^7^^^^^^^^^^^^^^^^^^^^^^^^^^^^_____ _"_7_9_<_E_H_J_S_V_Y_[__________________```` ``#`%`.`3`6`9`;`P`R`U`^```b`w`y`|`````````````aaaa aaaaaa a#a$a-a.a7aabbiblbmbvbxbzb|b~bbbbbbbbbbbbbbbbc c ccccc!c6c8c;cDcFcHc]c_cbckcncpc}cccccccddddxd{d|d~ddddddddddddddddddddddddddddee e ee$e&e)e2e5e7eDeQeSemeeeeeeeeeeeeeeef@fCfFfGfHfKfTfUfVf_fhfjfmfvfyfzfffffffffg7g9g:gCgEgGgIgKgMgOgQgSgVgYg[g]g_gbgdgegrggggggggggggggggggggggghjhlhmhohxhzh|h~hhhhhhhhhhhhhhhhhhhhhhhhhhhhiiii i#i%i.i3i6i9i;iDiMiiiiiiiiiiiiiiiiiiiiiiiij(jjjjjjjjjjjjjjjjjjjjjjjjjjjjkkkkkkk'k)k,k5k8k:kCkFkIkKkkkkkkkkkkkkkkkkkkkkkklllll"l%l(l*l?lAlDlMlOlQlflhlkltlwlyllllllllllllllmmmm mmmm#m&m'm0m3m@mCmEmHmJmLmUmlmommmmnnnn n nnnnnnnnn!n$n&n'n4nSnUnbnnnnnnnnnnnnnnnnnnnnoooooooooooooooooooooooooooooooooopppp p p"p$p'p0p2p4pIpKpNpWpZp\pepjpmppprp{pppppq q!q*q5q>qGqUq`qnqvqqqqqqqqqqqqqqqqqqqrrr rrrrr)r,r5r7rBrOrRrUrXr[r]rfrsrvrrrrrrrrrrrrrrrrrsss ssss!s"s/s2s5s8s;s=sKsYspsssssssssssssssssstttttt't,t/t2t4tItKtNtWtYt[tptrtut~tttttttuuuuuuu!u#u%u'u)u,u/u0u2u4u=u?uAuDuGuJuWudufuoutuwuzu|uuuuuuuuuuuuuuuuuuuv:v?vHvMvTvWv`vavbvcvlvuvvvwvzv}vvvvvvvvvvvvvvvvvvwww w wwww.w5wBwMwYw[w^wgwwwwwwwwwwwwxx xxxx#x,xAxFx[xhxmxoxxxxxxxxxxxxxxxxyyy#y,y5y8y;y=y|yyyyyyyyyyyyyyyyyyyyyyyyyyyzLzRzXz_zczjzqzwz|zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz{{{{ {{{{ {#{&{){+{2{8{]{c{j{{{{{{{{{{{{{{{{{{{{{||| |!|"|$|1|>|@|D|J|P|W|^|g||||||||||||||||} }}}+}z}}}~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}~~~~~~~ ~!~"~$~1~4~7~:~=~?~H~j~w~x~y~{~~~~~~~~~~~~~~~~~~~~~~~~~)>LWao "$'*-0258:SanπԀـހ %(+.147:ILORUX[^`ނ 5BILORY[^aciu~Ƃ͂Ђӂւ݂߂ &,Rƒ˃ԃ݃ $'),/258;=CIOUZ^gpȳׄippsample/server/DESIGN.md0000644000175000017500000001150113240604116014336 0ustar tilltill# IPP Server Design Overview This version of ippserver is much more complete than the one provided in the original CUPS sources while being simpler and easier to modify than the CUPS scheduler (cupsd). It supports: - "Baked in" or file-based configuration; - Multiple persistent print services/queues, both direct print (to IPP/IPPS URI) and printing via proxies (IPP Shared Infrastructure Extensions); - Retained Jobs and Documents; - Authentication using Pluggable Authentication Modules (PAM); - Basic web interface (status monitoring only); - Basic Document transforms (JPEG and PDF to PWG Raster); - Hold/release; - Release printing/fan-out; - Local overrides of printer capabilities (ready media, duplex, color, etc.); and - Operation as an on-demand service via launchd, systemd, etc. The following are planned to be added as the corresponding specifications reach prototype quality: - IPP System Service - IPP 3D Printing Extensions ## Source Organization The server is composed of several source files roughly organized by object or function: - "ippserver.h": Common header file - "client.c": IPP Client request processing - "conf.c": Configuration file support - "device.c": Output device support - "ipp.c": IPP Printer request processing - "job.c": Job object and processing - "log.c": Logging - "main.c": Main entry - "printer.c": Printer object - "subscription.c": Subscription object and event processing - "transform.c": Document (format) transforms ## Configuration Files Configuration files are placed in a directory specified on the command-line. The "system.conf" configuration file specifies server-wide settings, for example: "system.conf": DefaultPrinter foo LogLevel debug LogFile stderr Print services (queues) are placed in a subdirectory called "print", for example: "print/foo.conf": DeviceURI ipp://foo.example.com/ipp/print Attr collection media-col-ready {media-size={x-dimension=21590 y-dimension=27940}},{media-size={x-dimension=21000 y-dimension=29700}} Attr keyword media-ready na_letter_8.5x11in,iso_a4_210x297mm "print/bar.conf": ProxyUser bar Attr keyword job-hold-until-default indefinite The first example ("print/foo.conf") creates a direct print queue at "ipp://servername:port/ipp/print/foo" that overrides the "media-col-ready" and "media-ready" attributes reported by the printer with US Letter and ISO A4 media. The second example ("print/bar.conf") creates a proxy print queue at "ipp://servername:port/ipp/print/bar" that overrides the "job-hold-until-default" attribute so that all jobs are held by default. Any Proxy that authenticates using user "bar" can register to pull print jobs from this queue. ## Job Commands Commands are used both to process (print) a job and to transform/filter a job into a printable format. Each command receives the source (print) file on the command-line, for example: mycommand /tmp/ippserver.12345/foo/1-mydocument.pdf The standard input is redirected from /dev/null. The standard output is directed to either /dev/null for printer commands or the destination file for transforms performed by ippserver. The standard error is directed back to ippserver over a pipe which allows the command to send messages that affect the printer and job state as well as messages for the server log. The environment is inherited from ippserver with the following additional variables: - "CONTENT_TYPE": The source file's MIME media type, for example "application/pdf". - "DEVICE_URI": The destination device URI such as "ipp://foo.example.com/ipp/print" or "socket://bar.example.com". For printer commands only. - "DOCUMENT_CHARSET": The source file's character set, if specified. - "DOCUMENT_LANGUAGE": The source file's natural language, if specified. - "DOCUMENT_NAME": The source file's name, if specified. - "DOCUMENT_PASSWORD": The source file's password, if any. - "IPP_name": Job attributes converted from "foo-bar" to "IPP_FOO_BAR". The value is a string version of the IPP attribute. - "JOB_PASSWORD": The password to use when submitting the job, if any. For printer commands only. - "JOB_PASSWORD_ENCRYPTION": The named hash to use when submitting the job, if any. For printer commands only. - "OUTPUT_ORDER": The order of output pages, either "first-to-last" or "last-to-first". - "OUTPUT_TYPE": The destination MIME media type, for example "image/pwg-raster". - "PRINTER_MEDIA_DEFAULT": The default media size. - "PRINTER_SIDES_DEFAULT": The default duplex setting. - "PWG_RASTER_DOCUMENT_RESOLUTION_SUPPORTED": The list of comma-delimited resolutions that are supported by the output device. - "PWG_RASTER_DOCUMENT_SHEET_BACK": The transform to apply to the back size image when producing duplex output. - "PWG_RASTER_DOCUMENT_TYPE_SUPPORTED": The color spaces and bit depths that are supported by the output device. - "SERVER_LOGLEVEL": The configured log level of the server. ippsample/server/subscription.c0000644000175000017500000002177213240604116015746 0ustar tilltill/* * Subscription object code for sample IPP server implementation. * * Copyright © 2014-2018 by the IEEE-ISTO Printer Working Group * Copyright © 2010-2018 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ #include "ippserver.h" /* * 'serverAddEvent()' - Add an event to a subscription. */ void serverAddEvent(server_printer_t *printer, /* I - Printer */ server_job_t *job, /* I - Job, if any */ server_event_t event, /* I - Event */ const char *message, /* I - Printf-style notify-text message */ ...) /* I - Additional printf arguments */ { server_subscription_t *sub; /* Current subscription */ ipp_t *n; /* Notify attributes */ char text[1024]; /* notify-text value */ va_list ap; /* Argument pointer */ if (message) { va_start(ap, message); vsnprintf(text, sizeof(text), message, ap); va_end(ap); } else text[0] = '\0'; for (sub = (server_subscription_t *)cupsArrayFirst(printer->subscriptions); sub; sub = (server_subscription_t *)cupsArrayNext(printer->subscriptions)) { if (sub->mask & event && (!sub->job || job == sub->job)) { _cupsRWLockWrite(&sub->rwlock); n = ippNew(); ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_CHARSET, "notify-charset", NULL, "utf-8"); ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_LANGUAGE, "notify-natural-language", NULL, "en"); ippAddInteger(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "notify-printer-up-time", (int)(time(NULL) - printer->start_time)); ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_URI, "notify-printer-uri", NULL, printer->default_uri); if (job) ippAddInteger(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "notify-job-id", job->id); ippAddInteger(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "notify-subcription-id", sub->id); ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_URI, "notify-subscription-uuid", NULL, sub->uuid); ippAddInteger(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, "notify-sequence-number", ++ sub->last_sequence); ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, "notify-subscribed-event", NULL, serverGetNotifySubscribedEvent(event)); ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_TEXT, "notify-text", NULL, text); if (printer && (event & SERVER_EVENT_PRINTER_ALL)) { ippAddInteger(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_ENUM, "printer-state", printer->state); serverCopyPrinterStateReasons(n, IPP_TAG_EVENT_NOTIFICATION, printer); } if (job && (event & SERVER_EVENT_JOB_ALL)) { ippAddInteger(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_ENUM, "job-state", job->state); serverCopyJobStateReasons(n, IPP_TAG_EVENT_NOTIFICATION, job); if (event == SERVER_EVENT_JOB_CREATED) { ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME, "job-name", NULL, job->name); ippAddString(n, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME, "job-originating-user-name", NULL, job->username); } } cupsArrayAdd(sub->events, n); if (cupsArrayCount(sub->events) > 100) { n = (ipp_t *)cupsArrayFirst(sub->events); cupsArrayRemove(sub->events, n); ippDelete(n); sub->first_sequence ++; } _cupsRWUnlock(&sub->rwlock); _cupsCondBroadcast(&SubscriptionCondition); } } } /* * 'serverCreateSubcription()' - Create a new subscription object from a * Print-Job, Create-Job, or Create-xxx-Subscription * request. */ server_subscription_t * /* O - Subscription object */ serverCreateSubcription( server_printer_t *printer, /* I - Printer */ server_job_t *job, /* I - Job, if any */ int interval, /* I - Interval for progress events */ int lease, /* I - Lease duration */ const char *username, /* I - User creating the subscription */ ipp_attribute_t *notify_events, /* I - Events to monitor */ ipp_attribute_t *notify_attributes, /* I - Attributes to report */ ipp_attribute_t *notify_user_data) /* I - User data, if any */ { server_listener_t *lis = (server_listener_t *)cupsArrayFirst(Listeners); /* First listener */ server_subscription_t *sub; /* Subscription */ ipp_attribute_t *attr; /* Subscription attribute */ char uuid[64]; /* notify-subscription-uuid value */ /* * Allocate and initialize the subscription object... */ if ((sub = calloc(1, sizeof(server_subscription_t))) == NULL) { perror("Unable to allocate memory for subscription"); return (NULL); } _cupsRWLockWrite(&(printer->rwlock)); sub->id = printer->next_sub_id ++; sub->mask = notify_events ? serverGetNotifyEventsBits(notify_events) : SERVER_EVENT_DEFAULT; sub->printer = printer; sub->job = job; sub->interval = interval; sub->lease = lease; sub->attrs = ippNew(); if (lease) sub->expire = time(NULL) + sub->lease; else sub->expire = INT_MAX; _cupsRWInit(&(sub->rwlock)); /* * Add subscription description attributes and add to the subscriptions * array... */ ippAddInteger(sub->attrs, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-subscription-id", sub->id); httpAssembleUUID(lis->host, lis->port, printer->name, -sub->id, uuid, sizeof(uuid)); attr = ippAddString(sub->attrs, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, "notify-subscription-uuid", NULL, uuid); sub->uuid = ippGetString(attr, 0, NULL); ippAddString(sub->attrs, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, "notify-printer-uri", NULL, printer->default_uri); if (job) ippAddInteger(sub->attrs, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-job-id", job->id); else ippAddInteger(sub->attrs, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-lease-duration", sub->lease); attr = ippAddString(sub->attrs, IPP_TAG_SUBSCRIPTION, IPP_TAG_NAME, "notify-subscriber-user-name", NULL, username); sub->username = ippGetString(attr, 0, NULL); if (notify_events) ippCopyAttribute(sub->attrs, notify_events, 0); else ippAddString(sub->attrs, IPP_TAG_SUBSCRIPTION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "notify-events", NULL, SERVER_EVENT_DEFAULT_STRING); ippAddString(sub->attrs, IPP_TAG_SUBSCRIPTION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "notify-pull-method", NULL, "ippget"); if (notify_attributes) ippCopyAttribute(sub->attrs, notify_attributes, 0); if (notify_user_data) ippCopyAttribute(sub->attrs, notify_user_data, 0); sub->events = cupsArrayNew3(NULL, NULL, NULL, 0, NULL, (cups_afree_func_t)ippDelete); cupsArrayAdd(printer->subscriptions, sub); _cupsRWUnlock(&(printer->rwlock)); return (sub); } /* * 'serverDeleteSubscription()' - Delete a subscription. */ void serverDeleteSubscription( server_subscription_t *sub) /* I - Subscription */ { sub->pending_delete = 1; _cupsCondBroadcast(&SubscriptionCondition); _cupsRWLockWrite(&sub->rwlock); ippDelete(sub->attrs); cupsArrayDelete(sub->events); _cupsRWDeinit(&sub->rwlock); free(sub); } /* * 'serverFindSubscription()' - Find a subcription. */ server_subscription_t * /* O - Subscription */ serverFindSubscription( server_client_t *client, /* I - Client */ int sub_id) /* I - Subscription ID or 0 */ { ipp_attribute_t *notify_subscription_id; /* notify-subscription-id */ server_subscription_t key, /* Search key */ *sub; /* Matching subscription */ if (sub_id > 0) key.id = sub_id; else if ((notify_subscription_id = ippFindAttribute(client->request, "notify-subscription-id", IPP_TAG_INTEGER)) == NULL) return (NULL); else key.id = ippGetInteger(notify_subscription_id, 0); _cupsRWLockRead(&client->printer->rwlock); sub = (server_subscription_t *)cupsArrayFind(client->printer->subscriptions, &key); _cupsRWUnlock(&client->printer->rwlock); return (sub); } /* * 'serverGetNotifyEventsBits()' - Get the bits associated with "notify-events" values. */ server_event_t /* O - Bits */ serverGetNotifyEventsBits( ipp_attribute_t *attr) /* I - "notify-events" attribute */ { int i, j, /* Looping vars */ count; /* Number of "notify-events" values */ const char *keyword; /* "notify-events" value */ server_event_t events = SERVER_EVENT_NONE; /* Bits for "notify-events" values */ count = ippGetCount(attr); for (i = 0; i < count; i ++) { keyword = ippGetString(attr, i, NULL); for (j = 0; j < (int)(sizeof(server_events) / sizeof(server_events[0])); j ++) { if (!strcmp(keyword, server_jreasons[j])) { events |= (server_event_t)(1 << j); break; } } } return (events); } /* * 'serverGetNotifySubscribedEvent()' - Get the event name. */ const char * /* O - Event name */ serverGetNotifySubscribedEvent( server_event_t event) /* I - Event bit */ { int i; /* Looping var */ server_event_t mask; /* Current mask */ for (i = 0, mask = 1; i < (int)(sizeof(server_events) / sizeof(server_events[0])); i ++, mask <<= 1) if (event & mask) return (server_events[i]); return ("none"); } ippsample/server/conf.c0000644000175000017500000005564413240604116014154 0ustar tilltill/* * Configuration file support for sample IPP server implementation. * * Copyright © 2015-2018 by the IEEE-ISTO Printer Working Group * Copyright © 2015-2018 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ #include "ippserver.h" #include #include #include #include /* * Local globals... */ static _cups_mutex_t printer_mutex = _CUPS_MUTEX_INITIALIZER; /* * Local functions... */ static int attr_cb(_ipp_file_t *f, server_pinfo_t *pinfo, const char *attr); static int compare_lang(server_lang_t *a, server_lang_t *b); static int compare_printers(server_printer_t *a, server_printer_t *b); static server_lang_t *copy_lang(server_lang_t *a); #ifdef HAVE_AVAHI static void dnssd_client_cb(AvahiClient *c, AvahiClientState state, void *userdata); #endif /* HAVE_AVAHI */ static int error_cb(_ipp_file_t *f, server_pinfo_t *pinfo, const char *error); static void free_lang(server_lang_t *a); static int load_system(const char *conf); static int token_cb(_ipp_file_t *f, _ipp_vars_t *vars, server_pinfo_t *pinfo, const char *token); /* * 'serverCleanAllJobs()' - Clean old jobs for all printers... */ void serverCleanAllJobs(void) { server_printer_t *printer; /* Current printer */ serverLog(SERVER_LOGLEVEL_DEBUG, "Cleaning old jobs."); _cupsMutexLock(&printer_mutex); for (printer = (server_printer_t *)cupsArrayFirst(Printers); printer; printer = (server_printer_t *)cupsArrayNext(Printers)) serverCleanJobs(printer); _cupsMutexUnlock(&printer_mutex); } /* * 'serverDNSSDInit()' - Initialize DNS-SD registrations. */ void serverDNSSDInit(void) { #ifdef HAVE_DNSSD if (DNSServiceCreateConnection(&DNSSDMaster) != kDNSServiceErr_NoError) { fputs("Error: Unable to initialize Bonjour.\n", stderr); exit(1); } #elif defined(HAVE_AVAHI) int error; /* Error code, if any */ if ((DNSSDMaster = avahi_threaded_poll_new()) == NULL) { fputs("Error: Unable to initialize Bonjour.\n", stderr); exit(1); } if ((DNSSDClient = avahi_client_new(avahi_threaded_poll_get(DNSSDMaster), AVAHI_CLIENT_NO_FAIL, dnssd_client_cb, NULL, &error)) == NULL) { fputs("Error: Unable to initialize Bonjour.\n", stderr); exit(1); } avahi_threaded_poll_start(DNSSDMaster); #endif /* HAVE_DNSSD */ } /* * 'serverFinalizeConfiguration()' - Make final configuration choices. */ int /* O - 1 on success, 0 on failure */ serverFinalizeConfiguration(void) { char local[1024]; /* Local hostname */ /* * Default hostname... */ if (!ServerName && httpGetHostname(NULL, local, sizeof(local))) ServerName = strdup(local); if (!ServerName) ServerName = strdup("localhost"); #ifdef HAVE_SSL /* * Setup TLS certificate for server... */ cupsSetServerCredentials(KeychainPath, ServerName, 1); #endif /* HAVE_SSL */ /* * Default directories... */ if (!DataDirectory) { char directory[1024]; /* New directory */ const char *tmpdir; /* Temporary directory */ #ifdef WIN32 if ((tmpdir = getenv("TEMP")) == NULL) tmpdir = "C:/TEMP"; #elif defined(__APPLE__) if ((tmpdir = getenv("TMPDIR")) == NULL) tmpdir = "/private/tmp"; #else if ((tmpdir = getenv("TMPDIR")) == NULL) tmpdir = "/tmp"; #endif /* WIN32 */ snprintf(directory, sizeof(directory), "%s/ippserver.%d", tmpdir, (int)getpid()); if (mkdir(directory, 0755) && errno != EEXIST) { serverLog(SERVER_LOGLEVEL_ERROR, "Unable to create default data directory \"%s\": %s", directory, strerror(errno)); return (0); } serverLog(SERVER_LOGLEVEL_INFO, "Using default data directory \"%s\".", directory); DataDirectory = strdup(directory); } if (!SpoolDirectory) { SpoolDirectory = strdup(DataDirectory); serverLog(SERVER_LOGLEVEL_INFO, "Using default spool directory \"%s\".", DataDirectory); } /* * Initialize Bonjour... */ serverDNSSDInit(); /* * Apply default listeners if none are specified... */ if (!Listeners) { #ifdef WIN32 /* * Windows is almost always used as a single user system, so use a default port * number of 8631. */ if (!DefaultPort) DefaultPort = 8631; #else /* * Use 8000 + UID mod 1000 for the default port number... */ if (!DefaultPort) DefaultPort = 8000 + ((int)getuid() % 1000); #endif /* WIN32 */ serverLog(SERVER_LOGLEVEL_INFO, "Using default listeners for %s:%d.", ServerName, DefaultPort); if (!serverCreateListeners(strcmp(ServerName, "localhost") ? NULL : "localhost", DefaultPort)) return (0); } return (1); } /* * 'serverFindPrinter()' - Find a printer by resource... */ server_printer_t * /* O - Printer or NULL */ serverFindPrinter(const char *resource) /* I - Resource path */ { server_printer_t key, /* Search key */ *match = NULL; /* Matching printer */ _cupsMutexLock(&printer_mutex); if (cupsArrayCount(Printers) == 1 || !strcmp(resource, "/ipp/print")) { /* * Just use the first printer... */ match = cupsArrayFirst(Printers); if (strcmp(match->resource, resource) && strcmp(resource, "/ipp/print")) match = NULL; } else { key.resource = (char *)resource; match = (server_printer_t *)cupsArrayFind(Printers, &key); } _cupsMutexUnlock(&printer_mutex); return (match); } /* * 'serverLoadAttributes()' - Load printer attributes from a file. * * Syntax is based on ipptool format: * * ATTR value-tag name value * ATTR value-tag name value,value,... * AUTHTYPE "scheme" * COMMAND "/path/to/command" * DEVICE-URI "uri" * MAKE "manufacturer" * MODEL "model name" * PROXY-USER "username" * STRINGS lang filename.strings * * AUTH schemes are "none" for no authentication or "basic" for HTTP Basic * authentication. * * DEVICE-URI values can be "socket", "ipp", or "ipps" URIs. */ int /* O - 1 on success, 0 on failure */ serverLoadAttributes( const char *filename, /* I - File to load */ server_pinfo_t *pinfo) /* I - Printer information */ { _ipp_vars_t vars; /* IPP variables */ _ippVarsInit(&vars, (_ipp_fattr_cb_t)attr_cb, (_ipp_ferror_cb_t)error_cb, (_ipp_ftoken_cb_t)token_cb); pinfo->attrs = _ippFileParse(&vars, filename, (void *)pinfo); _ippVarsDeinit(&vars); return (pinfo->attrs != NULL); } /* * 'serverLoadConfiguration()' - Load the server configuration file. */ int /* O - 1 if successful, 0 on error */ serverLoadConfiguration( const char *directory) /* I - Configuration directory */ { cups_dir_t *dir; /* Directory pointer */ cups_dentry_t *dent; /* Directory entry */ char filename[1024], /* Configuration file/directory */ iconname[1024], /* Icon file */ resource[1024], /* Resource path */ *ptr; /* Pointer into filename */ server_printer_t *printer; /* Printer */ server_pinfo_t pinfo; /* Printer information */ /* * First read the system configuration file, if any... */ snprintf(filename, sizeof(filename), "%s/system.conf", directory); if (!load_system(filename)) return (0); if (!serverFinalizeConfiguration()) return (0); /* * Then see if there are any print queues... */ snprintf(filename, sizeof(filename), "%s/print", directory); if ((dir = cupsDirOpen(filename)) != NULL) { serverLog(SERVER_LOGLEVEL_INFO, "Loading printers from \"%s\".", filename); while ((dent = cupsDirRead(dir)) != NULL) { if ((ptr = dent->filename + strlen(dent->filename) - 5) >= dent->filename && !strcmp(ptr, ".conf")) { /* * Load the conf file, with any associated icon image. */ serverLog(SERVER_LOGLEVEL_INFO, "Loading printer from \"%s\".", dent->filename); snprintf(filename, sizeof(filename), "%s/print/%s", directory, dent->filename); *ptr = '\0'; memset(&pinfo, 0, sizeof(pinfo)); snprintf(iconname, sizeof(iconname), "%s/print/%s.png", directory, dent->filename); if (!access(iconname, R_OK)) pinfo.icon = strdup(iconname); if (serverLoadAttributes(filename, &pinfo)) { snprintf(resource, sizeof(resource), "/ipp/print/%s", dent->filename); if ((printer = serverCreatePrinter(resource, dent->filename, &pinfo)) == NULL) continue; if (!Printers) Printers = cupsArrayNew((cups_array_func_t)compare_printers, NULL); cupsArrayAdd(Printers, printer); } } else if (!strstr(dent->filename, ".png")) serverLog(SERVER_LOGLEVEL_INFO, "Skipping \"%s\".", dent->filename); } cupsDirClose(dir); } /* * Finally, see if there are any 3D print queues... */ snprintf(filename, sizeof(filename), "%s/print3d", directory); if ((dir = cupsDirOpen(filename)) != NULL) { serverLog(SERVER_LOGLEVEL_INFO, "Loading 3D printers from \"%s\".", filename); while ((dent = cupsDirRead(dir)) != NULL) { if ((ptr = dent->filename + strlen(dent->filename) - 5) >= dent->filename && !strcmp(ptr, ".conf")) { /* * Load the conf file, with any associated icon image. */ serverLog(SERVER_LOGLEVEL_INFO, "Loading 3D printer from \"%s\".", dent->filename); snprintf(filename, sizeof(filename), "%s/print3d/%s", directory, dent->filename); *ptr = '\0'; memset(&pinfo, 0, sizeof(pinfo)); snprintf(iconname, sizeof(iconname), "%s/print3d/%s.png", directory, dent->filename); if (!access(iconname, R_OK)) pinfo.icon = strdup(iconname); if (serverLoadAttributes(filename, &pinfo)) { snprintf(resource, sizeof(resource), "/ipp/print3d/%s", dent->filename); if ((printer = serverCreatePrinter(resource, dent->filename, &pinfo)) == NULL) continue; if (!Printers) Printers = cupsArrayNew((cups_array_func_t)compare_printers, NULL); cupsArrayAdd(Printers, printer); } } else if (!strstr(dent->filename, ".png")) serverLog(SERVER_LOGLEVEL_INFO, "Skipping \"%s\".", dent->filename); } cupsDirClose(dir); } return (1); } /* * 'attr_cb()' - Determine whether an attribute should be loaded. */ static int /* O - 1 to use, 0 to ignore */ attr_cb(_ipp_file_t *f, /* I - IPP file */ server_pinfo_t *pinfo, /* I - Printer information */ const char *attr) /* I - Attribute name */ { int i, /* Current element */ result; /* Result of comparison */ static const char * const ignored[] = { /* Ignored attributes */ "attributes-charset", "attributes-natural-language", "charset-configured", "charset-supported", "device-service-count", "device-uuid", "document-format-varying-attributes", "job-settable-attributes-supported", "pages-per-minute", "pages-per-minute-color", "printer-alert", "printer-alert-description", "printer-camera-image-uri", "printer-charge-info", "printer-charge-info-uri", "printer-config-change-date-time", "printer-config-change-time", "printer-current-time", "printer-detailed-status-messages", "printer-dns-sd-name", "printer-fax-log-uri", "printer-finisher", "printer-finisher-description", "printer-finisher-supplies", "printer-finisher-supplies-description", "printer-get-attributes-supported", "printer-icons", "printer-id", "printer-input-tray", "printer-is-accepting-jobs", "printer-message-date-time", "printer-message-from-operator", "printer-message-time", "printer-more-info", "printer-output-tray", "printer-service-type", "printer-settable-attributes-supported", "printer-state", "printer-state-message", "printer-state-reasons", "printer-static-resource-directory-uri", "printer-static-resource-k-octets-free", "printer-static-resource-k-octets-supported", "printer-strings-languages-supported", "printer-strings-uri", "printer-supply", "printer-supply-description", "printer-supply-info-uri", "printer-up-time", "printer-uri-supported", "printer-uuid", "printer-xri-supported", "queued-job-count", "uri-authentication-supported", "uri-security-supported", "xri-authentication-supported", "xri-security-supported", "xri-uri-scheme-supported" }; (void)f; (void)pinfo; for (i = 0, result = 1; i < (int)(sizeof(ignored) / sizeof(ignored[0])); i ++) { if ((result = strcmp(attr, ignored[i])) <= 0) break; } return (result != 0); } /* * 'compare_lang()' - Compare two languages. */ static int /* O - Result of comparison */ compare_lang(server_lang_t *a, /* I - First localization */ server_lang_t *b) /* I - Second localization */ { return (strcmp(a->lang, b->lang)); } /* * 'compare_printers()' - Compare two printers. */ static int /* O - Result of comparison */ compare_printers(server_printer_t *a, /* I - First printer */ server_printer_t *b) /* I - Second printer */ { return (strcmp(a->resource, b->resource)); } /* * 'copy_lang()' - Copy a localization. */ static server_lang_t * /* O - New localization */ copy_lang(server_lang_t *a) /* I - Localization to copy */ { server_lang_t *b; /* New localization */ if ((b = calloc(1, sizeof(server_lang_t))) != NULL) { b->lang = strdup(a->lang); b->filename = strdup(a->filename); } return (b); } #ifdef HAVE_AVAHI /* * 'dnssd_client_cb()' - Client callback for Avahi. * * Called whenever the client or server state changes... */ static void dnssd_client_cb( AvahiClient *c, /* I - Client */ AvahiClientState state, /* I - Current state */ void *userdata) /* I - User data (unused) */ { (void)userdata; if (!c) return; switch (state) { default : fprintf(stderr, "Ignore Avahi state %d.\n", state); break; case AVAHI_CLIENT_FAILURE: if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) { fputs("Avahi server crashed, exiting.\n", stderr); exit(1); } break; } } #endif /* HAVE_AVAHI */ /* * 'error_cb()' - Log an error message. */ static int /* O - 1 to continue, 0 to stop */ error_cb(_ipp_file_t *f, /* I - IPP file data */ server_pinfo_t *pinfo, /* I - Printer information */ const char *error) /* I - Error message */ { (void)f; (void)pinfo; serverLog(SERVER_LOGLEVEL_ERROR, "%s", error); return (1); } /* * 'free_lang()' - Free a localization. */ static void free_lang(server_lang_t *a) /* I - Localization */ { free(a->lang); free(a->filename); free(a); } /* * 'load_system()' - Load the system configuration file. */ static int /* O - 1 on success, 0 on failure */ load_system(const char *conf) /* I - Configuration file */ { cups_file_t *fp; /* File pointer */ int status = 1, /* Return value */ linenum = 0; /* Current line number */ char line[1024], /* Line from file */ *value; /* Pointer to value on line */ if ((fp = cupsFileOpen(conf, "r")) == NULL) return (errno == ENOENT); while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) { if (!value) { fprintf(stderr, "ippserver: Missing value on line %d of \"%s\".\n", linenum, conf); status = 0; break; } if (!_cups_strcasecmp(line, "DataDirectory")) { if (access(value, R_OK)) { fprintf(stderr, "ippserver: Unable to access DataDirectory \"%s\": %s\n", value, strerror(errno)); status = 0; break; } DataDirectory = strdup(value); } else if (!_cups_strcasecmp(line, "DefaultPrinter")) { if (DefaultPrinter) { fprintf(stderr, "ippserver: Extra DefaultPrinter seen on line %d of \"%s\".\n", linenum, conf); status = 0; break; } DefaultPrinter = strdup(value); } else if (!_cups_strcasecmp(line, "Encryption")) { if (!_cups_strcasecmp(value, "always")) Encryption = HTTP_ENCRYPTION_ALWAYS; else if (!_cups_strcasecmp(value, "ifrequested")) Encryption = HTTP_ENCRYPTION_IF_REQUESTED; else if (!_cups_strcasecmp(value, "never")) Encryption = HTTP_ENCRYPTION_NEVER; else if (!_cups_strcasecmp(value, "required")) Encryption = HTTP_ENCRYPTION_REQUIRED; else { fprintf(stderr, "ippserver: Bad Encryption value \"%s\" on line %d of \"%s\".\n", value, linenum, conf); status = 0; break; } } else if (!_cups_strcasecmp(line, "KeepFiles")) { KeepFiles = !strcasecmp(value, "yes") || !strcasecmp(value, "true") || !strcasecmp(value, "on"); } else if (!_cups_strcasecmp(line, "Listen")) { char *ptr; /* Pointer into host value */ int port; /* Port number */ if ((ptr = strrchr(value, ':')) != NULL && !isdigit(ptr[1] & 255)) { fprintf(stderr, "ippserver: Bad Listen value \"%s\" on line %d of \"%s\".\n", value, linenum, conf); status = 0; break; } if (ptr) { *ptr++ = '\0'; port = atoi(ptr); } else port = 8000 + ((int)getuid() % 1000); if (!serverCreateListeners(value, port)) { status = 0; break; } } else if (!_cups_strcasecmp(line, "LogFile")) { if (!_cups_strcasecmp(value, "stderr")) LogFile = NULL; else LogFile = strdup(value); } else if (!_cups_strcasecmp(line, "LogLevel")) { if (!_cups_strcasecmp(value, "error")) LogLevel = SERVER_LOGLEVEL_ERROR; else if (!_cups_strcasecmp(value, "info")) LogLevel = SERVER_LOGLEVEL_INFO; else if (!_cups_strcasecmp(value, "debug")) LogLevel = SERVER_LOGLEVEL_DEBUG; else { fprintf(stderr, "ippserver: Bad LogLevel value \"%s\" on line %d of \"%s\".\n", value, linenum, conf); status = 0; break; } } else if (!_cups_strcasecmp(line, "MaxCompletedJobs")) { if (!isdigit(*value & 255)) { fprintf(stderr, "ippserver: Bad MaxCompletedJobs value \"%s\" on line %d of \"%s\".\n", value, linenum, conf); status = 0; break; } MaxCompletedJobs = atoi(value); } else if (!_cups_strcasecmp(line, "MaxJobs")) { if (!isdigit(*value & 255)) { fprintf(stderr, "ippserver: Bad MaxJobs value \"%s\" on line %d of \"%s\".\n", value, linenum, conf); status = 0; break; } MaxJobs = atoi(value); } else if (!_cups_strcasecmp(line, "SpoolDirectory")) { if (access(value, R_OK)) { fprintf(stderr, "ippserver: Unable to access SpoolDirectory \"%s\": %s\n", value, strerror(errno)); status = 0; break; } SpoolDirectory = strdup(value); } else { fprintf(stderr, "ippserver: Unknown directive \"%s\" on line %d.\n", line, linenum); } } cupsFileClose(fp); return (status); } /* * 'token_cb()' - Process ippserver-specific config file tokens. */ static int /* O - 1 to continue, 0 to stop */ token_cb(_ipp_file_t *f, /* I - IPP file data */ _ipp_vars_t *vars, /* I - IPP variables */ server_pinfo_t *pinfo, /* I - Printer information */ const char *token) /* I - Current token */ { char temp[1024], /* Temporary string */ value[1024]; /* Value string */ if (!token) { /* * NULL token means do the initial setup - create an empty IPP message and * return... */ f->attrs = ippNew(); return (1); } else if (!_cups_strcasecmp(token, "AUTHTYPE")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { serverLog(SERVER_LOGLEVEL_ERROR, "Missing AuthType value on line %d of \"%s\".", f->linenum, f->filename); return (0); } _ippVarsExpand(vars, value, temp, sizeof(value)); pinfo->auth_type = strdup(value); } else if (!_cups_strcasecmp(token, "COMMAND")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { serverLog(SERVER_LOGLEVEL_ERROR, "Missing Command value on line %d of \"%s\".", f->linenum, f->filename); return (0); } _ippVarsExpand(vars, value, temp, sizeof(value)); pinfo->command = strdup(value); } else if (!_cups_strcasecmp(token, "DEVICEURI")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { serverLog(SERVER_LOGLEVEL_ERROR, "Missing DeviceURI value on line %d of \"%s\".", f->linenum, f->filename); return (0); } _ippVarsExpand(vars, value, temp, sizeof(value)); pinfo->device_uri = strdup(value); } else if (!_cups_strcasecmp(token, "OUTPUTFORMAT")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { serverLog(SERVER_LOGLEVEL_ERROR, "Missing OutputFormat value on line %d of \"%s\".", f->linenum, f->filename); return (0); } _ippVarsExpand(vars, value, temp, sizeof(value)); pinfo->output_format = strdup(value); } else if (!_cups_strcasecmp(token, "MAKE")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { serverLog(SERVER_LOGLEVEL_ERROR, "Missing Make value on line %d of \"%s\".", f->linenum, f->filename); return (0); } _ippVarsExpand(vars, value, temp, sizeof(value)); pinfo->make = strdup(value); } else if (!_cups_strcasecmp(token, "MODEL")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { serverLog(SERVER_LOGLEVEL_ERROR, "Missing Model value on line %d of \"%s\".", f->linenum, f->filename); return (0); } _ippVarsExpand(vars, value, temp, sizeof(value)); pinfo->model = strdup(value); } else if (!_cups_strcasecmp(token, "PROXYUSER")) { if (!_ippFileReadToken(f, temp, sizeof(temp))) { serverLog(SERVER_LOGLEVEL_ERROR, "Missing ProxyUser value on line %d of \"%s\".", f->linenum, f->filename); return (0); } _ippVarsExpand(vars, value, temp, sizeof(value)); pinfo->proxy_user = strdup(value); } else if (!_cups_strcasecmp(token, "STRINGS")) { server_lang_t lang; /* New localization */ char stringsfile[1024]; /* Strings filename */ if (!_ippFileReadToken(f, temp, sizeof(temp))) { serverLog(SERVER_LOGLEVEL_ERROR, "Missing STRINGS language on line %d of \"%s\".", f->linenum, f->filename); return (0); } _ippVarsExpand(vars, value, temp, sizeof(value)); if (!_ippFileReadToken(f, temp, sizeof(temp))) { serverLog(SERVER_LOGLEVEL_ERROR, "Missing STRINGS filename on line %d of \"%s\".", f->linenum, f->filename); return (0); } _ippVarsExpand(vars, stringsfile, temp, sizeof(stringsfile)); lang.lang = value; lang.filename = stringsfile; if (!pinfo->strings) pinfo->strings = cupsArrayNew3((cups_array_func_t)compare_lang, NULL, NULL, 0, (cups_acopy_func_t)copy_lang, (cups_afree_func_t)free_lang); cupsArrayAdd(pinfo->strings, &lang); serverLog(SERVER_LOGLEVEL_DEBUG, "Added strings file \"%s\" for language \"%s\".", stringsfile, value); } else { serverLog(SERVER_LOGLEVEL_ERROR, "Unknown directive \"%s\" on line %d of \"%s\".", token, f->linenum, f->filename); return (0); } return (1); } ippsample/server/client.c0000644000175000017500000017257413240604116014507 0ustar tilltill/* * Client code for sample IPP server implementation. * * Copyright © 2014-2018 by the IEEE-ISTO Printer Working Group * Copyright © 2010-2018 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ #include "ippserver.h" #include "printer-png.h" #include "printer3d-png.h" /* * Local functions... */ static void html_escape(server_client_t *client, const char *s, size_t slen); static void html_footer(server_client_t *client); static void html_header(server_client_t *client, const char *title); static void html_printf(server_client_t *client, const char *format, ...) __attribute__((__format__(__printf__, 2, 3))); static int parse_options(server_client_t *client, cups_option_t **options); static int show_materials(server_client_t *client, server_printer_t *printer, const char *encoding); static int show_media(server_client_t *client, server_printer_t *printer, const char *encoding); static int show_status(server_client_t *client, server_printer_t *printer, const char *encoding); static int show_supplies(server_client_t *client, server_printer_t *printer, const char *encoding); /* * 'serverCreateClient()' - Accept a new network connection and create a client object. */ server_client_t * /* O - Client */ serverCreateClient(int sock) /* I - Listen socket */ { server_client_t *client; /* Client */ static int next_client_number = 1; /* Next client number */ if ((client = calloc(1, sizeof(server_client_t))) == NULL) { perror("Unable to allocate memory for client"); return (NULL); } client->number = next_client_number ++; client->fetch_file = -1; /* * Accept the client and get the remote address... */ if ((client->http = httpAcceptConnection(sock, 1)) == NULL) { serverLogClient(SERVER_LOGLEVEL_ERROR, client, "Unable to accept client connection: %s", cupsLastErrorString()); free(client); return (NULL); } httpGetHostname(client->http, client->hostname, sizeof(client->hostname)); serverLogClient(SERVER_LOGLEVEL_INFO, client, "Accepted connection from \"%s\".", client->hostname); return (client); } /* * 'serverCreateListener()' - Create a listener socket. */ int /* O - 1 on success, 0 on error */ serverCreateListeners(const char *host, /* I - Hostname, IP address, or NULL for any address */ int port) /* I - Port number */ { int sock; /* Listener socket */ http_addrlist_t *addrlist, /* Listen address(es) */ *addr; /* Current address */ char service[32], /* Service port */ local[256]; /* Local hostname */ server_listener_t *lis; /* New listener */ if (host && !strcmp(host, "*")) host = NULL; snprintf(service, sizeof(service), "%d", port); if ((addrlist = httpAddrGetList(host, AF_UNSPEC, service)) == NULL) { serverLog(SERVER_LOGLEVEL_ERROR, "Unable to resolve Listen address \"%s\": %s", host ? host : "*", cupsLastErrorString()); return (0); } if (!host) { httpGetHostname(NULL, local, sizeof(local)); host = local; } for (addr = addrlist; addr; addr = addr->next) { if ((sock = httpAddrListen(&(addr->addr), port)) < 0) { char temp[256]; /* Numeric address */ serverLog(SERVER_LOGLEVEL_ERROR, "Unable to listen on address \"%s\": %s", httpAddrString(&(addr->addr), temp, sizeof(temp)), cupsLastErrorString()); continue; } lis = calloc(1, sizeof(server_listener_t)); lis->fd = sock; strlcpy(lis->host, host, sizeof(lis->host)); lis->port = port; if (!Listeners) Listeners = cupsArrayNew(NULL, NULL); cupsArrayAdd(Listeners, lis); } httpAddrFreeList(addrlist); return (1); } /* * 'serverDeleteClient()' - Close the socket and free all memory used by a client object. */ void serverDeleteClient(server_client_t *client) /* I - Client */ { serverLogClient(SERVER_LOGLEVEL_INFO, client, "Closing connection from \"%s\".", client->hostname); /* * Flush pending writes before closing... */ httpFlushWrite(client->http); /* * Free memory... */ httpClose(client->http); ippDelete(client->request); ippDelete(client->response); free(client); } /* * 'serverProcessClient()' - Process client requests on a thread. */ void * /* O - Exit status */ serverProcessClient( server_client_t *client) /* I - Client */ { /* * Loop until we are out of requests or timeout (30 seconds)... */ #ifdef HAVE_SSL int first_time = 1; /* First time request? */ #endif /* HAVE_SSL */ while (httpWait(client->http, 30000)) { #ifdef HAVE_SSL if (first_time && Encryption != HTTP_ENCRYPTION_NEVER) { /* * See if we need to negotiate a TLS connection... */ char buf[1]; /* First byte from client */ if (Encryption == HTTP_ENCRYPTION_ALWAYS || (recv(httpGetFd(client->http), buf, 1, MSG_PEEK) == 1 && (!buf[0] || !strchr("DGHOPT", buf[0])))) { serverLogClient(SERVER_LOGLEVEL_INFO, client, "Starting HTTPS session."); if (httpEncryption(client->http, HTTP_ENCRYPTION_ALWAYS)) { serverLogClient(SERVER_LOGLEVEL_ERROR, client, "Unable to encrypt connection: %s", cupsLastErrorString()); break; } serverLogClient(SERVER_LOGLEVEL_INFO, client, "Connection now encrypted."); } first_time = 0; } #endif /* HAVE_SSL */ if (!serverProcessHTTP(client)) break; } /* * Close the conection to the client and return... */ serverDeleteClient(client); return (NULL); } /* * 'serverProcessHTTP()' - Process a HTTP request. */ int /* O - 1 on success, 0 on failure */ serverProcessHTTP( server_client_t *client) /* I - Client connection */ { char uri[1024], /* URI */ *uriptr; /* Pointer into URI */ http_state_t http_state; /* HTTP state */ http_status_t http_status; /* HTTP status */ ipp_state_t ipp_state; /* State of IPP transfer */ char scheme[32], /* Method/scheme */ userpass[128], /* Username:password */ hostname[HTTP_MAX_HOST]; /* Hostname */ int port; /* Port number */ const char *encoding; /* Content-Encoding value */ static const char * const http_states[] = { /* Strings for logging HTTP method */ "WAITING", "OPTIONS", "GET", "GET_SEND", "HEAD", "POST", "POST_RECV", "POST_SEND", "PUT", "PUT_RECV", "DELETE", "TRACE", "CONNECT", "STATUS", "UNKNOWN_METHOD", "UNKNOWN_VERSION" }; /* * Clear state variables... */ ippDelete(client->request); ippDelete(client->response); client->request = NULL; client->response = NULL; client->operation = HTTP_STATE_WAITING; /* * Read a request from the connection... */ while ((http_state = httpReadRequest(client->http, uri, sizeof(uri))) == HTTP_STATE_WAITING) usleep(1); /* * Parse the request line... */ if (http_state == HTTP_STATE_ERROR) { if (httpError(client->http) == EPIPE || httpError(client->http) == ETIMEDOUT || httpError(client->http) == 0) serverLogClient(SERVER_LOGLEVEL_INFO, client, "Client closed connection."); else serverLogClient(SERVER_LOGLEVEL_ERROR, client, "Bad request line (%s).", strerror(httpError(client->http))); return (0); } else if (http_state == HTTP_STATE_UNKNOWN_METHOD) { serverLogClient(SERVER_LOGLEVEL_ERROR, client, "Bad/unknown operation."); serverRespondHTTP(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); return (0); } else if (http_state == HTTP_STATE_UNKNOWN_VERSION) { serverLogClient(SERVER_LOGLEVEL_ERROR, client, "Bad HTTP version."); serverRespondHTTP(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); return (0); } serverLogClient(SERVER_LOGLEVEL_INFO, client, "%s %s", http_states[http_state], uri); /* * Separate the URI into its components... */ if (httpSeparateURI(HTTP_URI_CODING_MOST, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, client->uri, sizeof(client->uri)) < HTTP_URI_STATUS_OK && (http_state != HTTP_STATE_OPTIONS || strcmp(uri, "*"))) { serverLogClient(SERVER_LOGLEVEL_ERROR, client, "Bad URI \"%s\".", uri); serverRespondHTTP(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); return (0); } if ((client->options = strchr(client->uri, '?')) != NULL) *(client->options)++ = '\0'; /* * Process the request... */ client->start = time(NULL); client->operation = httpGetState(client->http); /* * Parse incoming parameters until the status changes... */ while ((http_status = httpUpdate(client->http)) == HTTP_STATUS_CONTINUE); if (http_status != HTTP_STATUS_OK) { serverRespondHTTP(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); return (0); } if (!httpGetField(client->http, HTTP_FIELD_HOST)[0] && httpGetVersion(client->http) >= HTTP_VERSION_1_1) { /* * HTTP/1.1 and higher require the "Host:" field... */ serverRespondHTTP(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); return (0); } /* * Handle HTTP Upgrade... */ if (!strcasecmp(httpGetField(client->http, HTTP_FIELD_CONNECTION), "Upgrade")) { #ifdef HAVE_SSL if (strstr(httpGetField(client->http, HTTP_FIELD_UPGRADE), "TLS/") != NULL && !httpIsEncrypted(client->http) && Encryption != HTTP_ENCRYPTION_NEVER) { if (!serverRespondHTTP(client, HTTP_STATUS_SWITCHING_PROTOCOLS, NULL, NULL, 0)) return (0); serverLogClient(SERVER_LOGLEVEL_INFO, client, "Upgrading to encrypted connection."); if (httpEncryption(client->http, HTTP_ENCRYPTION_REQUIRED)) { serverLogClient(SERVER_LOGLEVEL_ERROR, client, "Unable to encrypt connection: %s", cupsLastErrorString()); return (0); } serverLogClient(SERVER_LOGLEVEL_INFO, client, "Connection now encrypted."); } else #endif /* HAVE_SSL */ if (!serverRespondHTTP(client, HTTP_STATUS_NOT_IMPLEMENTED, NULL, NULL, 0)) return (0); } #ifdef HAVE_SSL if (Encryption == HTTP_ENCRYPTION_REQUIRED && !httpIsEncrypted(client->http)) { serverLogClient(SERVER_LOGLEVEL_ERROR, client, "Forcing encryption of connection."); serverRespondHTTP(client, HTTP_STATUS_UPGRADE_REQUIRED, NULL, NULL, 0); return (0); } #endif /* HAVE_SSL */ /* * Handle HTTP Expect... */ if (httpGetExpect(client->http) && (client->operation == HTTP_STATE_POST || client->operation == HTTP_STATE_PUT)) { if (httpGetExpect(client->http) == HTTP_STATUS_CONTINUE) { /* * Send 100-continue header... */ if (!serverRespondHTTP(client, HTTP_STATUS_CONTINUE, NULL, NULL, 0)) return (0); } else { /* * Send 417-expectation-failed header... */ if (!serverRespondHTTP(client, HTTP_STATUS_EXPECTATION_FAILED, NULL, NULL, 0)) return (0); } } /* * Handle new transfers... */ encoding = httpGetContentEncoding(client->http); switch (client->operation) { case HTTP_STATE_OPTIONS : /* * Do OPTIONS command... */ return (serverRespondHTTP(client, HTTP_STATUS_OK, NULL, NULL, 0)); case HTTP_STATE_HEAD : if (!strncmp(client->uri, "/ipp/print/", 11)) { if ((uriptr = strchr(client->uri + 11, '/')) != NULL) *uriptr++ = '\0'; else uriptr = client->uri + strlen(client->uri); } else if (!strncmp(client->uri, "/ipp/print3d/", 13)) { if ((uriptr = strchr(client->uri + 13, '/')) != NULL) *uriptr++ = '\0'; else uriptr = client->uri + strlen(client->uri); } else if (!strcmp(client->uri, "/ipp/print")) uriptr = client->uri + strlen(client->uri); else uriptr = NULL; if (uriptr) { server_printer_t *printer; /* Printer */ if ((printer = serverFindPrinter(client->uri)) == NULL) printer = (server_printer_t *)cupsArrayFirst(Printers); if (printer) { char *ext = strrchr(uriptr, '.'); if (!strcmp(uriptr, "icon.png")) return (serverRespondHTTP(client, HTTP_STATUS_OK, NULL, "image/png", 0)); else if (!*uriptr || !strcmp(uriptr, "materials") || !strcmp(uriptr, "media") || !strcmp(uriptr, "supplies")) return (serverRespondHTTP(client, HTTP_STATUS_OK, NULL, "text/html", 0)); else if (ext && !strcmp(ext, ".strings")) { server_lang_t key; *ext = '\0'; key.lang = uriptr; if (cupsArrayFind(printer->pinfo.strings, &key)) return (serverRespondHTTP(client, HTTP_STATUS_OK, NULL, "text/strings", 0)); } } } else if (!strcmp(client->uri, "/")) return (serverRespondHTTP(client, HTTP_STATUS_OK, NULL, "text/html", 0)); return (serverRespondHTTP(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0)); case HTTP_STATE_GET : if (!strncmp(client->uri, "/ipp/print/", 11)) { if ((uriptr = strchr(client->uri + 11, '/')) != NULL) *uriptr++ = '\0'; else uriptr = client->uri + strlen(client->uri); } else if (!strncmp(client->uri, "/ipp/print3d/", 13)) { if ((uriptr = strchr(client->uri + 13, '/')) != NULL) *uriptr++ = '\0'; else uriptr = client->uri + strlen(client->uri); } else if (!strcmp(client->uri, "/ipp/print")) uriptr = client->uri + strlen(client->uri); else uriptr = NULL; if (uriptr) { server_printer_t *printer; /* Printer */ if ((printer = serverFindPrinter(client->uri)) == NULL) printer = (server_printer_t *)cupsArrayFirst(Printers); if (printer) { char *ext = strrchr(uriptr, '.'); if (!strcmp(uriptr, "icon.png")) { /* * Send PNG icon file. */ int fd; /* Icon file */ struct stat fileinfo; /* Icon file information */ char buffer[4096]; /* Copy buffer */ ssize_t bytes; /* Bytes */ if (printer->pinfo.icon) { serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "Icon file is \"%s\".", printer->pinfo.icon); if (!stat(printer->pinfo.icon, &fileinfo) && (fd = open(printer->pinfo.icon, O_RDONLY)) >= 0) { if (!serverRespondHTTP(client, HTTP_STATUS_OK, NULL, "image/png", (size_t)fileinfo.st_size)) { close(fd); return (0); } while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) httpWrite2(client->http, buffer, (size_t)bytes); httpFlushWrite(client->http); close(fd); return (1); } } else if (printer) { serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "Icon file is internal."); if (!strncmp(printer->resource, "/ipp/print3d", 12)) { if (!serverRespondHTTP(client, HTTP_STATUS_OK, NULL, "image/png", sizeof(printer3d_png))) return (0); httpWrite2(client->http, (void *)printer3d_png, sizeof(printer3d_png)); } else { if (!serverRespondHTTP(client, HTTP_STATUS_OK, NULL, "image/png", sizeof(printer_png))) return (0); httpWrite2(client->http, (void *)printer_png, sizeof(printer_png)); } httpFlushWrite(client->http); return (1); } } else if (!*uriptr) { return (show_status(client, printer, encoding)); } else if (!strcmp(uriptr, "materials")) { return (show_materials(client, printer, encoding)); } else if (!strcmp(uriptr, "media")) { return (show_media(client, printer, encoding)); } else if (!strcmp(uriptr, "supplies")) { return (show_supplies(client, printer, encoding)); } else if (ext && !strcmp(ext, ".strings")) { server_lang_t key, *match; *ext = '\0'; key.lang = uriptr; if ((match = (server_lang_t *)cupsArrayFind(printer->pinfo.strings, &key)) != NULL) { int fd; /* Icon file */ struct stat fileinfo; /* Icon file information */ char buffer[4096]; /* Copy buffer */ ssize_t bytes; /* Bytes */ serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "Strings file is \"%s\".", match->filename); if (!stat(match->filename, &fileinfo) && (fd = open(match->filename, O_RDONLY)) >= 0) { if (!serverRespondHTTP(client, HTTP_STATUS_OK, NULL, "text/strings", (size_t)fileinfo.st_size)) { close(fd); return (0); } while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) httpWrite2(client->http, buffer, (size_t)bytes); httpFlushWrite(client->http); close(fd); return (1); } } } } } else if (!strcmp(client->uri, "/")) { return (show_status(client, NULL, encoding)); } return (serverRespondHTTP(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0)); case HTTP_STATE_POST : if (strcmp(httpGetField(client->http, HTTP_FIELD_CONTENT_TYPE), "application/ipp")) { /* * Not an IPP request... */ return (serverRespondHTTP(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0)); } /* * Read the IPP request... */ client->request = ippNew(); while ((ipp_state = ippRead(client->http, client->request)) != IPP_STATE_DATA) { if (ipp_state == IPP_STATE_ERROR) { serverLogClient(SERVER_LOGLEVEL_ERROR, client, "IPP read error (%s).", cupsLastErrorString()); serverRespondHTTP(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); return (0); } } /* * Now that we have the IPP request, process the request... */ return (serverProcessIPP(client)); default : break; /* Anti-compiler-warning-code */ } return (1); } /* * 'serverRespondHTTP()' - Send a HTTP response. */ int /* O - 1 on success, 0 on failure */ serverRespondHTTP( server_client_t *client, /* I - Client */ http_status_t code, /* I - HTTP status of response */ const char *content_encoding, /* I - Content-Encoding of response */ const char *type, /* I - MIME media type of response */ size_t length) /* I - Length of response */ { char message[1024]; /* Text message */ serverLogClient(SERVER_LOGLEVEL_INFO, client, "%s", httpStatus(code)); if (code == HTTP_STATUS_CONTINUE) { /* * 100-continue doesn't send any headers... */ return (httpWriteResponse(client->http, HTTP_STATUS_CONTINUE) == 0); } /* * Format an error message... */ if (!type && !length && code != HTTP_STATUS_OK && code != HTTP_STATUS_SWITCHING_PROTOCOLS) { snprintf(message, sizeof(message), "%d - %s\n", code, httpStatus(code)); type = "text/plain"; length = strlen(message); } else message[0] = '\0'; /* * Send the HTTP response header... */ httpClearFields(client->http); if (code == HTTP_STATUS_METHOD_NOT_ALLOWED || client->operation == HTTP_STATE_OPTIONS) httpSetField(client->http, HTTP_FIELD_ALLOW, "GET, HEAD, OPTIONS, POST"); if (type) { if (!strcmp(type, "text/html")) httpSetField(client->http, HTTP_FIELD_CONTENT_TYPE, "text/html; charset=utf-8"); else httpSetField(client->http, HTTP_FIELD_CONTENT_TYPE, type); if (content_encoding) httpSetField(client->http, HTTP_FIELD_CONTENT_ENCODING, content_encoding); } httpSetLength(client->http, length); if (httpWriteResponse(client->http, code) < 0) return (0); /* * Send the response data... */ if (message[0]) { /* * Send a plain text message. */ if (httpPrintf(client->http, "%s", message) < 0) return (0); } else if (client->response) { /* * Send an IPP response... */ serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "serverRespondHTTP: Sending %d bytes of IPP response (Content-Length=%d)", (int)ippLength(client->response), (int)length); ippSetState(client->response, IPP_STATE_IDLE); if (ippWrite(client->http, client->response) != IPP_STATE_DATA) { serverLogClient(SERVER_LOGLEVEL_ERROR, client, "Unable to write IPP response."); return (0); } serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "serverRespondHTTP: Sent IPP response."); if (client->fetch_file >= 0) { ssize_t bytes; /* Bytes read */ char buffer[32768]; /* Buffer */ serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "serverRespondHTTP: Sending file."); if (client->fetch_compression) httpSetField(client->http, HTTP_FIELD_CONTENT_ENCODING, "gzip"); while ((bytes = read(client->fetch_file, buffer, sizeof(buffer))) > 0) httpWrite2(client->http, buffer, (size_t)bytes); serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "serverRespondHTTP: Sent file."); close(client->fetch_file); client->fetch_file = -1; } if (length == 0) { serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "serverRespondHTTP: Sending 0-length chunk."); httpWrite2(client->http, "", 0); } } serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "serverRespondHTTP: Flushing write buffer."); httpFlushWrite(client->http); return (1); } /* * 'serverRun()' - Run the server. */ void serverRun(void) { #ifdef HAVE_DNSSD int fd; /* File descriptor */ #endif /* HAVE_DNSSD */ int max_fd; /* Number of file descriptors */ fd_set input; /* select() input set */ struct timeval timeout; /* Timeout for poll() */ server_listener_t *lis; /* Listener */ server_client_t *client; /* New client */ time_t next_clean = 0; /* Next time to clean old jobs */ serverLog(SERVER_LOGLEVEL_DEBUG, "serverRun: %d printers configured.", cupsArrayCount(Printers)); serverLog(SERVER_LOGLEVEL_DEBUG, "serverRun: %d listeners configured.", cupsArrayCount(Listeners)); /* * Loop until we are killed or have a hard error... */ for (;;) { /* * Setup select() data for the Bonjour service socket and listeners... */ FD_ZERO(&input); max_fd = 0; for (lis = (server_listener_t *)cupsArrayFirst(Listeners); lis; lis = (server_listener_t *)cupsArrayNext(Listeners)) { FD_SET(lis->fd, &input); if (max_fd < lis->fd) max_fd = lis->fd; } #ifdef HAVE_DNSSD fd = DNSServiceRefSockFD(DNSSDMaster); FD_SET(fd, &input); if (max_fd < fd) max_fd = fd; #endif /* HAVE_DNSSD */ timeout.tv_sec = 86400; timeout.tv_usec = 0; if (select(max_fd + 1, &input, NULL, NULL, &timeout) < 0 && errno != EINTR) { serverLog(SERVER_LOGLEVEL_ERROR, "Main loop failed (%s)", strerror(errno)); break; } for (lis = (server_listener_t *)cupsArrayFirst(Listeners); lis; lis = (server_listener_t *)cupsArrayNext(Listeners)) { if (FD_ISSET(lis->fd, &input)) { serverLog(SERVER_LOGLEVEL_DEBUG, "serverRun: Incoming connection on listener %s:%d.", lis->host, lis->port); if ((client = serverCreateClient(lis->fd)) != NULL) { _cups_thread_t t = _cupsThreadCreate((_cups_thread_func_t)serverProcessClient, client); if (t) { _cupsThreadDetach(t); } else { serverLog(SERVER_LOGLEVEL_ERROR, "Unable to create client thread (%s)", strerror(errno)); serverDeleteClient(client); } } } } #ifdef HAVE_DNSSD if (FD_ISSET(DNSServiceRefSockFD(DNSSDMaster), &input)) { serverLog(SERVER_LOGLEVEL_DEBUG, "serverRun: Input on DNS-SD socket."); DNSServiceProcessResult(DNSSDMaster); } #endif /* HAVE_DNSSD */ if (time(NULL) >= next_clean) { serverCleanAllJobs(); next_clean = time(NULL) + 30; } } } /* * 'html_escape()' - Write a HTML-safe string. */ static void html_escape(server_client_t *client, /* I - Client */ const char *s, /* I - String to write */ size_t slen) /* I - Number of characters to write */ { const char *start, /* Start of segment */ *end; /* End of string */ start = s; end = s + (slen > 0 ? slen : strlen(s)); while (*s && s < end) { if (*s == '&' || *s == '<') { if (s > start) httpWrite2(client->http, start, (size_t)(s - start)); if (*s == '&') httpWrite2(client->http, "&", 5); else httpWrite2(client->http, "<", 4); start = s + 1; } s ++; } if (s > start) httpWrite2(client->http, start, (size_t)(s - start)); } /* * 'html_footer()' - Show the web interface footer. * * This function also writes the trailing 0-length chunk. */ static void html_footer(server_client_t *client) /* I - Client */ { html_printf(client, "
\n" "\n" "\n"); httpWrite2(client->http, "", 0); } /* * 'html_header()' - Show the web interface header and title. */ static void html_header(server_client_t *client, /* I - Client */ const char *title) /* I - Title */ { html_printf(client, "\n" "\n" "\n" "%s\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "
\n", title); } /* * 'html_printf()' - Send formatted text to the client, quoting as needed. */ static void html_printf(server_client_t *client, /* I - Client */ const char *format, /* I - Printf-style format string */ ...) /* I - Additional arguments as needed */ { va_list ap; /* Pointer to arguments */ const char *start; /* Start of string */ char size, /* Size character (h, l, L) */ type; /* Format type character */ int width, /* Width of field */ prec; /* Number of characters of precision */ char tformat[100], /* Temporary format string for sprintf() */ *tptr, /* Pointer into temporary format */ temp[1024]; /* Buffer for formatted numbers */ char *s; /* Pointer to string */ /* * Loop through the format string, formatting as needed... */ va_start(ap, format); start = format; while (*format) { if (*format == '%') { if (format > start) httpWrite2(client->http, start, (size_t)(format - start)); tptr = tformat; *tptr++ = *format++; if (*format == '%') { httpWrite2(client->http, "%", 1); format ++; start = format; continue; } else if (strchr(" -+#\'", *format)) *tptr++ = *format++; if (*format == '*') { /* * Get width from argument... */ format ++; width = va_arg(ap, int); snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", width); tptr += strlen(tptr); } else { width = 0; while (isdigit(*format & 255)) { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; width = width * 10 + *format++ - '0'; } } if (*format == '.') { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; format ++; if (*format == '*') { /* * Get precision from argument... */ format ++; prec = va_arg(ap, int); snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", prec); tptr += strlen(tptr); } else { prec = 0; while (isdigit(*format & 255)) { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; prec = prec * 10 + *format++ - '0'; } } } if (*format == 'l' && format[1] == 'l') { size = 'L'; if (tptr < (tformat + sizeof(tformat) - 2)) { *tptr++ = 'l'; *tptr++ = 'l'; } format += 2; } else if (*format == 'h' || *format == 'l' || *format == 'L') { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; size = *format++; } else size = 0; if (!*format) { start = format; break; } if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; type = *format++; *tptr = '\0'; start = format; switch (type) { case 'E' : /* Floating point formats */ case 'G' : case 'e' : case 'f' : case 'g' : if ((size_t)(width + 2) > sizeof(temp)) break; sprintf(temp, tformat, va_arg(ap, double)); httpWrite2(client->http, temp, strlen(temp)); break; case 'B' : /* Integer formats */ case 'X' : case 'b' : case 'd' : case 'i' : case 'o' : case 'u' : case 'x' : if ((size_t)(width + 2) > sizeof(temp)) break; # ifdef HAVE_LONG_LONG if (size == 'L') sprintf(temp, tformat, va_arg(ap, long long)); else # endif /* HAVE_LONG_LONG */ if (size == 'l') sprintf(temp, tformat, va_arg(ap, long)); else sprintf(temp, tformat, va_arg(ap, int)); httpWrite2(client->http, temp, strlen(temp)); break; case 'p' : /* Pointer value */ if ((size_t)(width + 2) > sizeof(temp)) break; sprintf(temp, tformat, va_arg(ap, void *)); httpWrite2(client->http, temp, strlen(temp)); break; case 'c' : /* Character or character array */ if (width <= 1) { temp[0] = (char)va_arg(ap, int); temp[1] = '\0'; html_escape(client, temp, 1); } else html_escape(client, va_arg(ap, char *), (size_t)width); break; case 's' : /* String */ if ((s = va_arg(ap, char *)) == NULL) s = "(null)"; html_escape(client, s, strlen(s)); break; } } else format ++; } if (format > start) httpWrite2(client->http, start, (size_t)(format - start)); va_end(ap); } /* * 'parse_options()' - Parse URL options into CUPS options. * * The client->options string is destroyed by this function. */ static int /* O - Number of options */ parse_options(server_client_t *client, /* I - Client */ cups_option_t **options) /* O - Options */ { char *name, /* Name */ *value, /* Value */ *next; /* Next name=value pair */ int num_options = 0; /* Number of options */ *options = NULL; for (name = client->options; name && *name; name = next) { if ((value = strchr(name, '=')) == NULL) break; *value++ = '\0'; if ((next = strchr(value, '&')) != NULL) *next++ = '\0'; num_options = cupsAddOption(name, value, num_options, options); } return (num_options); } /* * 'show_materials()' - Show material load state. */ static int /* O - 1 on success, 0 on failure */ show_materials( server_client_t *client, /* I - Client connection */ server_printer_t *printer, /* I - Printer to show */ const char *encoding) /* I - Content-Encoding */ { int i, j, /* Looping vars */ count; /* Number of values */ ipp_attribute_t *materials_db, /* materials-col-database attribute */ *materials_ready,/* materials-col-ready attribute */ *attr; /* Other attribute */ ipp_t *materials_col; /* materials-col-xxx value */ const char *material_name, /* materials-col-database material-name value */ *material_key, /* materials-col-database material-key value */ *ready_key; /* materials-col-ready material-key value */ int max_materials; /* max-materials-col-supported value */ int num_options; /* Number of form options */ cups_option_t *options; /* Form options */ /* * Grab the available, ready, and number of materials from the printer. */ if (!serverRespondHTTP(client, HTTP_STATUS_OK, encoding, "text/html", 0)) return (0); html_header(client, printer->dnssd_name); html_printf(client, "

Show Printers Show Jobs

\n", printer->resource); html_printf(client, "

%s Materials

\n", printer->resource, printer->dnssd_name); if ((materials_db = ippFindAttribute(printer->pinfo.attrs, "materials-col-database", IPP_TAG_BEGIN_COLLECTION)) == NULL) { html_printf(client, "

Error: No materials-col-database defined for printer.

\n"); html_footer(client); return (1); } if ((materials_ready = ippFindAttribute(printer->pinfo.attrs, "materials-col-ready", IPP_TAG_ZERO)) == NULL) { html_printf(client, "

Error: No materials-col-ready defined for printer.

\n"); html_footer(client); return (1); } if ((attr = ippFindAttribute(printer->pinfo.attrs, "max-materials-col-supported", IPP_TAG_INTEGER)) == NULL) { html_printf(client, "

Error: No max-materials-col-supported defined for printer.

\n"); html_footer(client); return (1); } max_materials = ippGetInteger(attr, 0); /* * Process form data if present... */ if ((num_options = parse_options(client, &options)) > 0) { /* * WARNING: A real printer/server implementation MUST NOT implement * material updates via a GET request - GET requests are supposed to be * idempotent (without side-effects) and we obviously are not * authenticating access here. This form is provided solely to * enable testing and development! */ char name[255]; /* Form name */ const char *val; /* Form value */ _cupsRWLockWrite(&printer->rwlock); ippDeleteAttribute(printer->pinfo.attrs, materials_ready); materials_ready = NULL; for (i = 0; i < max_materials; i ++) { snprintf(name, sizeof(name), "material%d", i); if ((val = cupsGetOption(name, num_options, options)) == NULL || !*val) continue; for (j = 0, count = ippGetCount(materials_db); j < count; j ++) { materials_col = ippGetCollection(materials_db, j); material_key = ippGetString(ippFindAttribute(materials_col, "material-key", IPP_TAG_ZERO), 0, NULL); if (!strcmp(material_key, val)) { if (!materials_ready) materials_ready = ippAddCollection(printer->pinfo.attrs, IPP_TAG_PRINTER, "materials-col-ready", materials_col); else ippSetCollection(printer->pinfo.attrs, &materials_ready, ippGetCount(materials_ready), materials_col); break; } } } if (!materials_ready) materials_ready = ippAddOutOfBand(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "materials-col-ready"); _cupsRWUnlock(&printer->rwlock); html_printf(client, "
Materials updated.
\n"); } /* * Show the currently loaded materials and allow the user to make selections... */ html_printf(client, "
\n", printer->resource); html_printf(client, "\n"); for (i = 0; i < max_materials; i ++) { materials_col = ippGetCollection(materials_ready, i); ready_key = ippGetString(ippFindAttribute(materials_col, "material-key", IPP_TAG_ZERO), 0, NULL); html_printf(client, "\n"); } html_printf(client, "
Material %d:
\n"); html_footer(client); return (1); } /* * 'show_media()' - Show media load state. */ static int /* O - 1 on success, 0 on failure */ show_media(server_client_t *client, /* I - Client connection */ server_printer_t *printer, /* I - Printer to show */ const char *encoding) /* I - Content-Encoding */ { int i, j, /* Looping vars */ num_ready, /* Number of ready media */ num_sizes, /* Number of media sizes */ num_sources, /* Number of media sources */ num_types; /* Number of media types */ ipp_attribute_t *media_col_ready,/* media-col-ready attribute */ *media_ready, /* media-ready attribute */ *media_sizes, /* media-supported attribute */ *media_sources, /* media-source-supported attribute */ *media_types, /* media-type-supported attribute */ *input_tray; /* printer-input-tray attribute */ // *attr; /* Other attribute */ ipp_t *media_col; /* media-col value */ const char *media_size, /* media value */ *media_source, /* media-source value */ *media_type, /* media-type value */ *ready_size, /* media-col-ready media-size[-name] value */ *ready_source, /* media-col-ready media-source value */ *ready_tray, /* printer-input-tray value */ *ready_type; /* media-col-ready media-type value */ char tray_str[1024], /* printer-input-tray string value */ *tray_ptr; /* Pointer into value */ int tray_len; /* Length of printer-input-tray value */ int ready_sheets; /* printer-input-tray sheets value */ int num_options; /* Number of form options */ cups_option_t *options; /* Form options */ static const int sheets[] = /* Number of sheets */ { 250, 100, 25, 5, 0 }; if (!serverRespondHTTP(client, HTTP_STATUS_OK, encoding, "text/html", 0)) return (0); html_header(client, printer->name); html_printf(client, "

Show Printers Show Jobs Show Supplies

\n", printer->resource, printer->resource); html_printf(client, "

%s Media

\n", printer->resource, printer->dnssd_name); if ((media_col_ready = ippFindAttribute(printer->pinfo.attrs, "media-col-ready", IPP_TAG_BEGIN_COLLECTION)) == NULL) { html_printf(client, "

Error: No media-col-ready defined for printer.

\n"); html_footer(client); return (1); } media_ready = ippFindAttribute(printer->pinfo.attrs, "media-ready", IPP_TAG_ZERO); if ((media_sizes = ippFindAttribute(printer->pinfo.attrs, "media-supported", IPP_TAG_ZERO)) == NULL) { html_printf(client, "

Error: No media-supported defined for printer.

\n"); html_footer(client); return (1); } if ((media_sources = ippFindAttribute(printer->pinfo.attrs, "media-source-supported", IPP_TAG_ZERO)) == NULL) { html_printf(client, "

Error: No media-source-supported defined for printer.

\n"); html_footer(client); return (1); } if ((media_types = ippFindAttribute(printer->pinfo.attrs, "media-type-supported", IPP_TAG_ZERO)) == NULL) { html_printf(client, "

Error: No media-type-supported defined for printer.

\n"); html_footer(client); return (1); } if ((input_tray = ippFindAttribute(printer->pinfo.attrs, "printer-input-tray", IPP_TAG_STRING)) == NULL) { html_printf(client, "

Error: No printer-input-tray defined for printer.

\n"); html_footer(client); return (1); } num_ready = ippGetCount(media_col_ready); num_sizes = ippGetCount(media_sizes); num_sources = ippGetCount(media_sources); num_types = ippGetCount(media_types); if (num_sources != ippGetCount(input_tray)) { html_printf(client, "

Error: Different number of trays in media-source-supported and printer-input-tray defined for printer.

\n"); html_footer(client); return (1); } /* * Process form data if present... */ if ((num_options = parse_options(client, &options)) > 0) { /* * WARNING: A real printer/server implementation MUST NOT implement * media updates via a GET request - GET requests are supposed to be * idempotent (without side-effects) and we obviously are not * authenticating access here. This form is provided solely to * enable testing and development! */ char name[255]; /* Form name */ const char *val; /* Form value */ pwg_media_t *media; /* Media info */ _cupsRWLockWrite(&printer->rwlock); ippDeleteAttribute(printer->pinfo.attrs, input_tray); input_tray = NULL; ippDeleteAttribute(printer->pinfo.attrs, media_col_ready); media_col_ready = NULL; if (media_ready) { ippDeleteAttribute(printer->pinfo.attrs, media_ready); media_ready = NULL; } printer->state_reasons &= (server_preason_t)~(SERVER_PREASON_MEDIA_LOW | SERVER_PREASON_MEDIA_EMPTY | SERVER_PREASON_MEDIA_NEEDED); for (i = 0; i < num_sources; i ++) { media_source = ippGetString(media_sources, i, NULL); snprintf(name, sizeof(name), "size%d", i); if ((media_size = cupsGetOption(name, num_options, options)) != NULL && (media = pwgMediaForPWG(media_size)) != NULL) { char media_key[128]; /* media-key value */ ipp_t *media_size_col; /* media-size collection */ snprintf(name, sizeof(name), "type%d", i); media_type = cupsGetOption(name, num_options, options); if (media_ready) ippSetString(printer->pinfo.attrs, &media_ready, ippGetCount(media_ready), media_size); else media_ready = ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-ready", NULL, media_size); if (media_type && *media_type) snprintf(media_key, sizeof(media_key), "%s_%s_%s", media_size, media_source, media_type); else snprintf(media_key, sizeof(media_key), "%s_%s", media_size, media_source); media_size_col = ippNew(); ippAddInteger(media_size_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "x-dimension", media->width); ippAddInteger(media_size_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "y-dimension", media->length); media_col = ippNew(); ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-key", NULL, media_key); ippAddCollection(media_col, IPP_TAG_PRINTER, "media-size", media_size_col); ippDelete(media_size_col); ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-size-name", NULL, media_size); ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-source", NULL, media_source); if (media_type && *media_type) ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-type", NULL, media_type); if (media_col_ready) ippSetCollection(printer->pinfo.attrs, &media_col_ready, ippGetCount(media_col_ready), media_col); else media_col_ready = ippAddCollection(printer->pinfo.attrs, IPP_TAG_PRINTER, "media-col-ready", media_col); ippDelete(media_col); } else media = NULL; snprintf(name, sizeof(name), "level%d", i); if ((val = cupsGetOption(name, num_options, options)) != NULL) ready_sheets = atoi(val); else ready_sheets = 0; snprintf(tray_str, sizeof(tray_str), "type=sheetFeedAutoRemovableTray;mediafeed=%d;mediaxfeed=%d;maxcapacity=250;level=%d;status=0;name=%s;", media ? media->length : 0, media ? media->width : 0, ready_sheets, media_source); if (input_tray) ippSetOctetString(printer->pinfo.attrs, &input_tray, ippGetCount(input_tray), tray_str, (int)strlen(tray_str)); else input_tray = ippAddOctetString(printer->pinfo.attrs, IPP_TAG_PRINTER, "printer-input-tray", tray_str, (int)strlen(tray_str)); if (ready_sheets == 0) { printer->state_reasons |= SERVER_PREASON_MEDIA_EMPTY; if (printer->processing_job) printer->state_reasons |= SERVER_PREASON_MEDIA_NEEDED; } else if (ready_sheets < 25) printer->state_reasons |= SERVER_PREASON_MEDIA_LOW; } if (!media_col_ready) media_col_ready = ippAddOutOfBand(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "media-col-ready"); if (!media_ready) media_ready = ippAddOutOfBand(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "media-ready"); _cupsRWUnlock(&printer->rwlock); html_printf(client, "
Media updated.
\n"); } html_printf(client, "
\n", printer->resource); html_printf(client, "\n"); for (i = 0; i < num_sources; i ++) { media_source = ippGetString(media_sources, i, NULL); for (j = 0, ready_size = NULL, ready_type = NULL; j < num_ready; j ++) { media_col = ippGetCollection(media_col_ready, j); ready_size = ippGetString(ippFindAttribute(media_col, "media-size-name", IPP_TAG_ZERO), 0, NULL); ready_source = ippGetString(ippFindAttribute(media_col, "media-source", IPP_TAG_ZERO), 0, NULL); ready_type = ippGetString(ippFindAttribute(media_col, "media-type", IPP_TAG_ZERO), 0, NULL); if (ready_source && !strcmp(ready_source, media_source)) break; ready_source = NULL; ready_size = NULL; ready_type = NULL; } /* * Media size... */ html_printf(client, "\n"); } html_printf(client, "
%s:\n"); /* * Media type... */ html_printf(client, "\n"); /* * Level/sheets loaded... */ if ((ready_tray = ippGetOctetString(input_tray, i, &tray_len)) != NULL) { if (tray_len > (sizeof(tray_str) - 1)) tray_len = sizeof(tray_str) - 1; memcpy(tray_str, ready_tray, (size_t)tray_len); tray_str[tray_len] = '\0'; if ((tray_ptr = strstr(tray_str, "level=")) != NULL) ready_sheets = atoi(tray_ptr + 6); else ready_sheets = 0; } else ready_sheets = 0; html_printf(client, "
\n"); html_footer(client); return (1); } /* * 'show_status()' - Show printer/system state. */ static int /* O - 1 on success, 0 on failure */ show_status(server_client_t *client, /* I - Client connection */ server_printer_t *printer, /* I - Printer to show or NULL for system */ const char *encoding) /* I - Content-Encoding to use */ { server_job_t *job; /* Current job */ int i, j; /* Looping vars */ server_preason_t reason; /* Current reason */ static const char * const reasons[] = /* Reason strings */ { "Other", "Cover Open", "Input Tray Missing", "Marker Supply Empty", "Marker Supply Low", "Marker Waste Almost Full", "Marker Waste Full", "Media Empty", "Media Jam", "Media Low", "Media Needed", "Moving to Paused", "Paused", "Spool Area Full", "Toner Empty", "Toner Low" }; if (!serverRespondHTTP(client, HTTP_STATUS_OK, encoding, "text/html", 0)) return (0); if (printer) { html_header(client, printer->dnssd_name); if (!strncmp(printer->resource, "/ipp/print3d", 12)) html_printf(client, "

Show Printers Show Materials\n", printer->resource); else html_printf(client, "

Show Printers Show Media Show Supplies

\n", printer->resource, printer->resource); html_printf(client, "

%s Jobs

\n", printer->resource, printer->dnssd_name); html_printf(client, "

%s, %d job(s).", printer->state == IPP_PSTATE_IDLE ? "Idle" : printer->state == IPP_PSTATE_PROCESSING ? "Printing" : "Stopped", cupsArrayCount(printer->jobs)); for (i = 0, reason = 1; i < (int)(sizeof(reasons) / sizeof(reasons[0])); i ++, reason <<= 1) if (printer->state_reasons & reason) html_printf(client, "\n
    %s", reasons[i]); html_printf(client, "

\n"); if (cupsArrayCount(printer->jobs) > 0) { _cupsRWLockRead(&(printer->rwlock)); html_printf(client, "\n"); for (job = (server_job_t *)cupsArrayFirst(printer->jobs); job; job = (server_job_t *)cupsArrayNext(printer->jobs)) { char when[256], /* When job queued/started/finished */ hhmmss[64]; /* Time HH:MM:SS */ switch (job->state) { case IPP_JSTATE_PENDING : case IPP_JSTATE_HELD : snprintf(when, sizeof(when), "Queued at %s", serverTimeString(job->created, hhmmss, sizeof(hhmmss))); break; case IPP_JSTATE_PROCESSING : case IPP_JSTATE_STOPPED : snprintf(when, sizeof(when), "Started at %s", serverTimeString(job->processing, hhmmss, sizeof(hhmmss))); break; case IPP_JSTATE_ABORTED : snprintf(when, sizeof(when), "Aborted at %s", serverTimeString(job->completed, hhmmss, sizeof(hhmmss))); break; case IPP_JSTATE_CANCELED : snprintf(when, sizeof(when), "Canceled at %s", serverTimeString(job->completed, hhmmss, sizeof(hhmmss))); break; case IPP_JSTATE_COMPLETED : snprintf(when, sizeof(when), "Completed at %s", serverTimeString(job->completed, hhmmss, sizeof(hhmmss))); break; } html_printf(client, "\n", job->id, job->name, job->username, when); } html_printf(client, "
Job #NameOwnerWhen
%d%s%s%s
\n"); _cupsRWUnlock(&(printer->rwlock)); } } else { html_header(client, CUPS_SVERSION); for (i = 0, printer = (server_printer_t *)cupsArrayFirst(Printers); printer; i ++, printer = (server_printer_t *)cupsArrayNext(Printers)) { html_printf(client, "
\n", (i & 1) ? "odd" : "even"); html_printf(client, "

%s

\n", printer->resource, printer->dnssd_name); html_printf(client, "

%s, %d job(s).", printer->state == IPP_PSTATE_IDLE ? "Idle" : printer->state == IPP_PSTATE_PROCESSING ? "Printing" : "Stopped", cupsArrayCount(printer->jobs)); for (j = 0, reason = 1; j < (int)(sizeof(reasons) / sizeof(reasons[0])); j ++, reason <<= 1) if (printer->state_reasons & reason) html_printf(client, "\n
    %s", reasons[j]); html_printf(client, "

\n"); if (!strncmp(printer->resource, "/ipp/print3d", 12)) html_printf(client, "

Show Jobs Show Materials

\n", printer->resource, printer->resource); else html_printf(client, "

Show Jobs Show Media Show Supplies

\n", printer->resource, printer->resource, printer->resource); html_printf(client, "
\n"); } } html_footer(client); return (1); } /* * 'show_supplies()' - Show printer supplies. */ static int /* O - 1 on success, 0 on failure */ show_supplies( server_client_t *client, /* I - Client connection */ server_printer_t *printer, /* I - Printer to show */ const char *encoding) /* I - Content-Encoding to use */ { int i, /* Looping var */ num_supply; /* Number of supplies */ ipp_attribute_t *supply, /* printer-supply attribute */ *supply_desc; /* printer-supply-description attribute */ int num_options; /* Number of form options */ cups_option_t *options; /* Form options */ int supply_len, /* Length of supply value */ level; /* Supply level */ const char *supply_value; /* Supply value */ char supply_text[1024], /* Supply string */ *supply_ptr; /* Pointer into supply string */ static const char * const printer_supply[] = { /* printer-supply values */ "index=1;class=receptacleThatIsFilled;type=wasteToner;unit=percent;" "maxcapacity=100;level=%d;colorantname=unknown;", "index=2;class=supplyThatIsConsumed;type=toner;unit=percent;" "maxcapacity=100;level=%d;colorantname=black;", "index=3;class=supplyThatIsConsumed;type=toner;unit=percent;" "maxcapacity=100;level=%d;colorantname=cyan;", "index=4;class=supplyThatIsConsumed;type=toner;unit=percent;" "maxcapacity=100;level=%d;colorantname=magenta;", "index=5;class=supplyThatIsConsumed;type=toner;unit=percent;" "maxcapacity=100;level=%d;colorantname=yellow;" }; static const char * const colors[] = /* Colors for the supply-level bars */ { "#777 linear-gradient(#333,#777)", "#000 linear-gradient(#666,#000)", "#0FF linear-gradient(#6FF,#0FF)", "#F0F linear-gradient(#F6F,#F0F)", "#CC0 linear-gradient(#EE6,#EE0)" }; if (!serverRespondHTTP(client, HTTP_STATUS_OK, encoding, "text/html", 0)) return (0); html_header(client, printer->name); html_printf(client, "

Show Printers Show Jobs Show Media

\n", printer->resource, printer->resource); html_printf(client, "

%s Media

\n", printer->resource, printer->dnssd_name); if ((supply = ippFindAttribute(printer->pinfo.attrs, "printer-supply", IPP_TAG_STRING)) == NULL) { html_printf(client, "

Error: No printer-supply defined for printer.

\n"); html_footer(client); return (1); } num_supply = ippGetCount(supply); if ((supply_desc = ippFindAttribute(printer->pinfo.attrs, "printer-supply-description", IPP_TAG_TEXT)) == NULL) { html_printf(client, "

Error: No printer-supply-description defined for printer.

\n"); html_footer(client); return (1); } if (num_supply != ippGetCount(supply_desc)) { html_printf(client, "

Error: Different number of values for printer-supply and printer-supply-description defined for printer.

\n"); html_footer(client); return (1); } if ((num_options = parse_options(client, &options)) > 0) { /* * WARNING: A real printer/server implementation MUST NOT implement * supply updates via a GET request - GET requests are supposed to be * idempotent (without side-effects) and we obviously are not * authenticating access here. This form is provided solely to * enable testing and development! */ char name[64]; /* Form field */ const char *val; /* Form value */ _cupsRWLockWrite(&printer->rwlock); ippDeleteAttribute(printer->pinfo.attrs, supply); supply = NULL; printer->state_reasons &= (server_preason_t)~(SERVER_PREASON_MARKER_SUPPLY_EMPTY | SERVER_PREASON_MARKER_SUPPLY_LOW | SERVER_PREASON_MARKER_WASTE_ALMOST_FULL | SERVER_PREASON_MARKER_WASTE_FULL | SERVER_PREASON_TONER_EMPTY | SERVER_PREASON_TONER_LOW); for (i = 0; i < num_supply; i ++) { snprintf(name, sizeof(name), "supply%d", i); if ((val = cupsGetOption(name, num_options, options)) != NULL) { level = atoi(val); /* New level */ snprintf(supply_text, sizeof(supply_text), printer_supply[i], level); if (supply) ippSetOctetString(printer->pinfo.attrs, &supply, ippGetCount(supply), supply_text, (int)strlen(supply_text)); else supply = ippAddOctetString(printer->pinfo.attrs, IPP_TAG_PRINTER, "printer-supply", supply_text, (int)strlen(supply_text)); if (i == 0) { if (level == 100) printer->state_reasons |= SERVER_PREASON_MARKER_WASTE_FULL; else if (level > 90) printer->state_reasons |= SERVER_PREASON_MARKER_WASTE_ALMOST_FULL; } else { if (level == 0) printer->state_reasons |= SERVER_PREASON_TONER_EMPTY; else if (level < 10) printer->state_reasons |= SERVER_PREASON_TONER_LOW; } } } _cupsRWUnlock(&printer->rwlock); html_printf(client, "
Supplies updated.
\n"); } html_printf(client, "
\n", printer->resource); html_printf(client, "\n"); for (i = 0; i < num_supply; i ++) { supply_value = ippGetOctetString(supply, i, &supply_len); if (supply_len > (sizeof(supply_text) - 1)) supply_len = sizeof(supply_text) - 1; memcpy(supply_text, supply_value, (size_t)supply_len); supply_text[supply_len] = '\0'; if ((supply_ptr = strstr(supply_text, "level=")) != NULL) level = atoi(supply_ptr + 6); else level = 50; html_printf(client, "\n", ippGetString(supply_desc, i, NULL), i, level, colors[i], level * 2); } html_printf(client, "\n
%s:
\n
\n"); html_footer(client); return (1); } ippsample/server/main.c0000644000175000017500000001763513240604116014151 0ustar tilltill/* * Main entry for IPP Infrastructure Printer sample implementation. * * Copyright © 2014-2018 by the IEEE-ISTO Printer Working Group * Copyright © 2010-2018 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ #define _MAIN_C_ #include "ippserver.h" /* * Local functions... */ static void usage(int status) __attribute__((noreturn)); /* * 'main()' - Main entry to the sample infrastructure server. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ char *opt, /* Current option character */ *confdir = NULL, /* Configuration directory */ *name = NULL; /* Printer name */ server_pinfo_t pinfo; /* Printer information */ server_printer_t *printer; /* Printer object */ /* * Parse command-line arguments... */ memset(&pinfo, 0, sizeof(pinfo)); for (i = 1; i < argc; i ++) { if (argv[i][0] == '-') { for (opt = argv[i] + 1; *opt; opt ++) { switch (*opt) { case '2' : /* -2 (enable 2-sided printing) */ pinfo.duplex = 1; break; case 'C' : /* -C config-directory */ i ++; if (i >= argc) usage(1); confdir = argv[i]; break; #ifdef HAVE_SSL case 'K' : /* -K keypath */ i ++; if (i >= argc) usage(1); KeychainPath = strdup(argv[i]); break; #endif /* HAVE_SSL */ case 'M' : /* -M manufacturer */ i ++; if (i >= argc) usage(1); if (pinfo.make) free(pinfo.make); pinfo.make = strdup(argv[i]); break; case 'P' : /* -P (PIN printing mode) */ pinfo.pin = 1; break; case 'a' : /* -a attributes-file */ i ++; if (i >= argc) usage(1); if (!serverLoadAttributes(argv[i], &pinfo)) return (1); break; case 'c' : /* -c command */ i ++; if (i >= argc) usage(1); if (pinfo.command) free(pinfo.command); pinfo.command = argv[i]; break; case 'd' : /* -d data-directory */ i ++; if (i >= argc) usage(1); DataDirectory = strdup(argv[i]); break; case 'f' : /* -f type/subtype[,...] */ i ++; if (i >= argc) usage(1); if (pinfo.document_formats) free(pinfo.document_formats); pinfo.document_formats = strdup(argv[i]); break; case 'h' : /* -h (show help) */ usage(0); case 'i' : /* -i icon.png */ i ++; if (i >= argc) usage(1); if (pinfo.icon) free(pinfo.icon); pinfo.icon = strdup(argv[i]); break; case 'k' : /* -k (keep files) */ KeepFiles = 1; break; case 'l' : /* -l location */ i ++; if (i >= argc) usage(1); if (pinfo.location) free(pinfo.location); pinfo.location = strdup(argv[i]); break; case 'm' : /* -m model */ i ++; if (i >= argc) usage(1); if (pinfo.model) free(pinfo.model); pinfo.model = strdup(argv[i]); break; case 'n' : /* -n hostname */ i ++; if (i >= argc) usage(1); ServerName = strdup(argv[i]); break; case 'p' : /* -p port */ i ++; if (i >= argc || !isdigit(argv[i][0] & 255)) usage(1); DefaultPort = atoi(argv[i]); break; case 'r' : /* -r subtype */ i ++; if (i >= argc) usage(1); DNSSDSubType = strdup(argv[i]); break; case 's' : /* -s speed[,color-speed] */ i ++; if (i >= argc) usage(1); if (sscanf(argv[i], "%d,%d", &pinfo.ppm, &pinfo.ppm_color) < 1) usage(1); break; case 'u' : /* -u user:pass */ i ++; if (i >= argc) usage(1); if (pinfo.proxy_user) free(pinfo.proxy_user); pinfo.proxy_user = strdup(argv[i]); break; case 'v' : /* -v (be verbose) */ LogLevel ++; break; default : /* Unknown */ fprintf(stderr, "ippserver: Unknown option \"-%c\".\n", *opt); usage(1); } } } else if (!name) { name = argv[i]; } else { fprintf(stderr, "ippserver: Unexpected command-line argument \"%s\"\n", argv[i]); usage(1); } } if (!DNSSDSubType) DNSSDSubType = strdup("_print"); if (confdir && (name || pinfo.make || pinfo.model || pinfo.location || pinfo.attrs || pinfo.command || pinfo.icon || pinfo.document_formats || pinfo.duplex || pinfo.pin || pinfo.ppm || pinfo.ppm_color)) { fputs("ippserver: Cannot specify configuration directory with printer options (-2, -M, -P, -a, -c, -f, -i, -l, -m, -s)\n", stderr); usage(1); } if (!confdir) { /* * Apply defaults for some of the other options... */ if (!pinfo.location) pinfo.location = strdup(""); if (!pinfo.make) pinfo.make = strdup("Test"); if (!pinfo.model) pinfo.model = strdup("Printer"); if (!pinfo.document_formats) pinfo.document_formats = strdup("application/pdf,image/jpeg,image/pwg-raster"); } if (!name && !confdir) usage(1); else if (confdir) { /* * Load the configuration from the specified directory... */ if (!serverLoadConfiguration(confdir)) return (1); } else { /* * Create a single printer (backwards-compatibility mode)... */ serverLog(SERVER_LOGLEVEL_INFO, "Using default configuration with a single printer."); if (!serverFinalizeConfiguration()) return (1); if ((printer = serverCreatePrinter("/ipp/print", name, &pinfo)) == NULL) return (1); Printers = cupsArrayNew(NULL, NULL); cupsArrayAdd(Printers, printer); } /* * Enter the server main loop... */ serverRun(); return (0); } /* * 'usage()' - Show program usage. */ static void usage(int status) /* O - Exit status */ { if (!status) { puts(CUPS_SVERSION " - Copyright 2010-2017 by Apple Inc. All rights reserved."); puts(""); } puts("Usage: ippserver [options] \"name\""); puts(""); puts("Options:"); puts("-2 Supports 2-sided printing (default=1-sided)"); puts("-C config-directory Load settings and printers from the specified directory."); #ifdef HAVE_SSL puts("-K keypath Specifies the location of certificates and keys"); #endif /* HAVE_SSL */ puts("-M manufacturer Manufacturer name (default=Test)"); puts("-P PIN printing mode"); puts("-a attributes-file Load printer attributes from file"); puts("-c command Run command for every print job"); printf("-d data-directory Data/spool directory " "(default=$TMPDIR/ippserver.%d)\n", (int)getpid()); puts("-f type/subtype[,...] List of supported types " "(default=application/pdf,image/jpeg)"); puts("-h Show program help"); puts("-i iconfile.png PNG icon file (default=printer.png)"); puts("-k Keep job spool files"); puts("-l location Location of printer (default=empty string)"); puts("-m model Model name (default=Printer)"); puts("-n hostname Hostname for printer"); puts("-p port Port number (default=auto)"); puts("-r subtype Bonjour service subtype (default=_print)"); puts("-s speed[,color-speed] Speed in pages per minute (default=10,0)"); puts("-u username:password Specifies a username and password to require."); puts("-v[v] Be (very) verbose"); exit(status); } ippsample/server/printer3d.png0000644000175000017500000001347613240604116015500 0ustar tilltillPNG  IHDRi7@ iCCPICC Profile8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|UP`oiTXtXML:com.adobe.xmp Michael Sweet Copyright 2010 Apple Inc. New Image タ IDATx{՝?5/fn4QՃ, rXrPl'dz'.9Qϼ4 Yc6q 08@t[ꞞpLOUnW V83)&Uzayl.-Sүe*xݟ#t0Uoq=9-q\z@F6=N"GHNޯMG }@"4ۗ*^Lkm5Vh$i.stP ,Ng hvuX:Qw- ;]$T$mθCBH6D-kvjn:׶NroIҷ>ժݦ-:xܣBYuv~DI9BB\oN-7\ ( }OԭxqB+V7ʦ`}еVM>=BItw J(\s=I:W+6e6I]B7V=[!G^f6Oth˜d>6{g8:"^,Oq qޫfUU*#=eKr?Wqmڥ\f53{㛁=!8`'0,D?.N=,p#gpڹXu&2=>8ca@7pBYcPa=`;0qU\osn3D?5\K9p{(Q|.r?!btr@^Y?p>{tW)#$G Bh$iTP|EYBz<݃:Ji/k1z%PwZ5O7kBK\uin'"4j:Vrǎfk?aݯO%]sԤCŀZB9/}]Qօht+Ԣtr.m游!YB]w˻™Q}`Re~]Ez^>m:o]SR5*Dqf .X 2.aќw$p e:K=E@둜 ZZZ knﳇ_3pkϿr:y)Ҭz T tNy ŭ wq+o1bSe/Sdɒs kk)B/}Ȓ#I@<}OY, }!K+9R4l>҇ K;4ȑ#K idȐIz0CYީ5lB5F8d>jmF-QsDhVC4]6hZ5|s^+Äݠxo 0 e!].L@1<.&ZUNlF 5}@ $qC@r9 x&qWp\bA<0nY`\ (x'ɠQzjL:8 :HT験XV>nX+-qrF .Mr<"zA&RXpӸ(k]dJ,3VG%#9#TQ 4+jpyI)TAx pB} v(2GvP]$McaR]7p},,P>htΖ:N 59F$1%Ys*(5K@&,<E7"/NB./Ao9U_Px2+ta<6C ؁X)@#%=hrGU/!ŀ%'( G_.rxp9![udB7h^?aEBxw2 Rt1~Q*Q wTHM$mJgǝP>r5H#RTpl ne8kN T]q % Xk DDbt%D]~/`B@lNյ.vBHx]w XF Xи*ڎ~@x6*Q"`gL@iyOz %3!\e= - /Zcpv'U(N勉 ^Z!;2eMud5X)w8UyLC!q٣:Trc*߭zx83y*Ty8 @r/r ִVh 7$•/N|0`[XwVuf8->%׳nk* 7 rŢAcdh"ƕ8e;@}l3'7CT/I:;|MҔYx>tTm@8#¹8P(L S)j6y,e!qIzKc>H48V^ ,F`B_4p^(ӨNL6i@& h)_>@r}@&RJx>6$x6x \CMeu{1"g:Z#P*PQr֢(.61[w DS=50hzCb{=UawO4'JVTǍ 5ndq}#SeK) ^YYa Pp߾_4K:Hh_EL\i&7U3⁧Bqbcb hь-pO J&N& \F'YhQb$-aa?Yy#~ xG2&iv:褝fH&~߆JIFыM2>AN;#hfr+sGhnΤ_1ާiP8hKϛ.c9ZAt]ϒ.k*2`ݼKM7;:kBqM9MpYSO7ɓs|R|q,ʹFkh"x}v}z@4eQ>e+C 9Zi&<@w 0i( irf߸^͛l7ح`gemkv]]my iVaHFkbgvL0Y!MZis}kSVWxb>}?'`یtMy3)m!> 2*bF7囹response, job->attrs, ra, IPP_TAG_JOB, 0); if (!ra || cupsArrayFind(ra, "date-time-at-completed")) { if (job->completed) ippAddDate(client->response, IPP_TAG_JOB, "date-time-at-completed", ippTimeToDate(job->completed)); else ippAddOutOfBand(client->response, IPP_TAG_JOB, IPP_TAG_NOVALUE, "date-time-at-completed"); } if (!ra || cupsArrayFind(ra, "date-time-at-processing")) { if (job->processing) ippAddDate(client->response, IPP_TAG_JOB, "date-time-at-processing", ippTimeToDate(job->processing)); else ippAddOutOfBand(client->response, IPP_TAG_JOB, IPP_TAG_NOVALUE, "date-time-at-processing"); } if (!ra || cupsArrayFind(ra, "job-impressions")) ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-impressions", job->impressions); if (!ra || cupsArrayFind(ra, "job-impressions-completed")) ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-impressions-completed", job->impcompleted); if (!ra || cupsArrayFind(ra, "job-printer-up-time")) ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-printer-up-time", (int)(time(NULL) - client->printer->start_time)); if (!ra || cupsArrayFind(ra, "job-state")) ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", job->state); if (!ra || cupsArrayFind(ra, "job-state-message")) { if (job->dev_state_message) { ippAddString(client->response, IPP_TAG_JOB, IPP_TAG_TEXT, "job-state-message", NULL, job->dev_state_message); } else { const char *message = ""; /* Message string */ switch (job->state) { case IPP_JSTATE_PENDING : message = "Job pending."; break; case IPP_JSTATE_HELD : if (job->state_reasons & SERVER_JREASON_JOB_INCOMING) message = "Job incoming."; else if (ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_ZERO)) message = "Job held."; else message = "Job created."; break; case IPP_JSTATE_PROCESSING : if (job->state_reasons & SERVER_JREASON_PROCESSING_TO_STOP_POINT) { if (job->cancel) message = "Cancel in progress."; else message = "Abort in progress."; } else message = "Job printing."; break; case IPP_JSTATE_STOPPED : message = "Job stopped."; break; case IPP_JSTATE_CANCELED : message = "Job canceled."; break; case IPP_JSTATE_ABORTED : message = "Job aborted."; break; case IPP_JSTATE_COMPLETED : message = "Job completed."; break; } ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_TEXT), "job-state-message", NULL, message); } } if (!ra || cupsArrayFind(ra, "job-state-reasons")) serverCopyJobStateReasons(client->response, IPP_TAG_JOB, job); /* switch (job->state) { case IPP_JSTATE_PENDING : ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "none"); break; case IPP_JSTATE_HELD : if (job->fd >= 0) ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "job-incoming"); else if (ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_ZERO)) ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "job-hold-until-specified"); else ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "job-data-insufficient"); break; case IPP_JSTATE_PROCESSING : if (job->cancel) ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "processing-to-stop-point"); else ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "job-printing"); break; case IPP_JSTATE_STOPPED : ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "job-stopped"); break; case IPP_JSTATE_CANCELED : ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "job-canceled-by-user"); break; case IPP_JSTATE_ABORTED : ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "aborted-by-system"); break; case IPP_JSTATE_COMPLETED : ippAddString(client->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons", NULL, "job-completed-successfully"); break; } */ if (!ra || cupsArrayFind(ra, "time-at-completed")) ippAddInteger(client->response, IPP_TAG_JOB, job->completed ? IPP_TAG_INTEGER : IPP_TAG_NOVALUE, "time-at-completed", (int)(job->completed - client->printer->start_time)); if (!ra || cupsArrayFind(ra, "time-at-processing")) ippAddInteger(client->response, IPP_TAG_JOB, job->processing ? IPP_TAG_INTEGER : IPP_TAG_NOVALUE, "time-at-processing", (int)(job->processing - client->printer->start_time)); } /* * 'copy_sub_attrs()' - Copy job attributes to the response. */ static void copy_subscription_attributes( server_client_t *client, /* I - Client */ server_subscription_t *sub, /* I - Subscription */ cups_array_t *ra) /* I - requested-attributes */ { serverCopyAttributes(client->response, sub->attrs, ra, IPP_TAG_SUBSCRIPTION, 0); if (!ra || cupsArrayFind(ra, "notify-lease-expiration-time")) ippAddInteger(client->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-lease-expiration-time", (int)(sub->expire - client->printer->start_time)); if (!ra || cupsArrayFind(ra, "notify-printer-up-time")) ippAddInteger(client->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-printer-up-time", (int)(time(NULL) - client->printer->start_time)); if (!ra || cupsArrayFind(ra, "notify-sequence-number")) ippAddInteger(client->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-sequence-number", sub->last_sequence); } /* * 'filter_cb()' - Filter printer attributes based on the requested array. */ static int /* O - 1 to copy, 0 to ignore */ filter_cb(server_filter_t *filter, /* I - Filter parameters */ ipp_t *dst, /* I - Destination (unused) */ ipp_attribute_t *attr) /* I - Source attribute */ { /* * Filter attributes as needed... */ #ifndef WIN32 /* Avoid MS compiler bug */ (void)dst; #endif /* !WIN32 */ ipp_tag_t group = ippGetGroupTag(attr); const char *name = ippGetName(attr); if ((filter->group_tag != IPP_TAG_ZERO && group != filter->group_tag && group != IPP_TAG_ZERO) || !name || (!strcmp(name, "media-col-database") && !cupsArrayFind(filter->ra, (void *)name))) return (0); return (!filter->ra || cupsArrayFind(filter->ra, (void *)name) != NULL); } /* * 'ipp_acknowledge_document()' - Acknowledge receipt of a document. */ static void ipp_acknowledge_document( server_client_t *client) /* I - Client */ { server_device_t *device; /* Device */ server_job_t *job; /* Job */ ipp_attribute_t *attr; /* Attribute */ if ((device = serverFindDevice(client)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Device was not found."); return; } if ((job = serverFindJob(client, 0)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Job was not found."); return; } if (!job->dev_uuid || strcmp(job->dev_uuid, device->uuid)) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job not assigned to device."); return; } if ((attr = ippFindAttribute(client->request, "document-number", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(attr) != IPP_TAG_OPERATION || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetCount(attr) != 1 || ippGetInteger(attr, 0) != 1) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, attr ? "Bad document-number attribute." : "Missing document-number attribute."); return; } serverRespondIPP(client, IPP_STATUS_OK, NULL); } /* * 'ipp_acknowledge_identify_printer()' - Acknowledge an identify command. */ static void ipp_acknowledge_identify_printer( server_client_t *client) /* I - Client */ { // TODO: Implement this! serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Need to implement this."); } /* * 'ipp_acknowledge_job()' - Acknowledge receipt of a job. */ static void ipp_acknowledge_job( server_client_t *client) /* I - Client */ { server_device_t *device; /* Device */ server_job_t *job; /* Job */ if ((device = serverFindDevice(client)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Device was not found."); return; } if ((job = serverFindJob(client, 0)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Job was not found."); return; } if (job->dev_uuid && strcmp(job->dev_uuid, device->uuid)) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_AUTHORIZED, "Job not assigned to device."); return; } if (!(job->state_reasons & SERVER_JREASON_JOB_FETCHABLE)) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FETCHABLE, "Job not fetchable."); return; } if (!job->dev_uuid) job->dev_uuid = strdup(device->uuid); job->state_reasons &= (server_jreason_t)~SERVER_JREASON_JOB_FETCHABLE; serverAddEvent(client->printer, job, SERVER_EVENT_JOB_STATE_CHANGED, "Job acknowledged."); serverRespondIPP(client, IPP_STATUS_OK, NULL); } /* * 'ipp_cancel_job()' - Cancel a job. */ static void ipp_cancel_job(server_client_t *client) /* I - Client */ { server_job_t *job; /* Job information */ /* * Get the job... */ if ((job = serverFindJob(client, 0)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); return; } /* * See if the job is already completed, canceled, or aborted; if so, * we can't cancel... */ switch (job->state) { case IPP_JSTATE_CANCELED : serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job #%d is already canceled - can\'t cancel.", job->id); break; case IPP_JSTATE_ABORTED : serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job #%d is already aborted - can\'t cancel.", job->id); break; case IPP_JSTATE_COMPLETED : serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job #%d is already completed - can\'t cancel.", job->id); break; default : /* * Cancel the job... */ _cupsRWLockWrite(&(client->printer->rwlock)); if (job->state == IPP_JSTATE_PROCESSING || (job->state == IPP_JSTATE_HELD && job->fd >= 0)) job->cancel = 1; else { job->state = IPP_JSTATE_CANCELED; job->completed = time(NULL); } _cupsRWUnlock(&(client->printer->rwlock)); serverAddEvent(client->printer, job, SERVER_EVENT_JOB_COMPLETED, NULL); serverRespondIPP(client, IPP_STATUS_OK, NULL); break; } } /* * 'ipp_cancel_my_jobs()' - Cancel a user's jobs. */ static void ipp_cancel_my_jobs( server_client_t *client) /* I - Client */ { // TODO: Implement this! serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Need to implement this."); } /* * 'ipp_cancel_subscription()' - Cancel a subscription. */ static void ipp_cancel_subscription( server_client_t *client) /* I - Client */ { server_subscription_t *sub; /* Subscription */ if ((sub = serverFindSubscription(client, 0)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Subscription was not found."); return; } _cupsRWLockWrite(&client->printer->rwlock); cupsArrayRemove(client->printer->subscriptions, sub); serverDeleteSubscription(sub); _cupsRWUnlock(&client->printer->rwlock); serverRespondIPP(client, IPP_STATUS_OK, NULL); } /* * 'ipp_close_job()' - Close an open job. */ static void ipp_close_job(server_client_t *client) /* I - Client */ { server_job_t *job; /* Job information */ /* * Get the job... */ if ((job = serverFindJob(client, 0)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); return; } /* * See if the job is already completed, canceled, or aborted; if so, * we can't cancel... */ switch (job->state) { case IPP_JSTATE_CANCELED : serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job #%d is canceled - can\'t close.", job->id); break; case IPP_JSTATE_ABORTED : serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job #%d is aborted - can\'t close.", job->id); break; case IPP_JSTATE_COMPLETED : serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job #%d is completed - can\'t close.", job->id); break; case IPP_JSTATE_PROCESSING : case IPP_JSTATE_STOPPED : serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job #%d is already closed.", job->id); break; default : serverRespondIPP(client, IPP_STATUS_OK, NULL); break; } } /* * 'ipp_create_job()' - Create a job object. */ static void ipp_create_job(server_client_t *client) /* I - Client */ { server_job_t *job; /* New job */ cups_array_t *ra; /* Attributes to send in response */ /* * Validate print job attributes... */ if (!valid_job_attributes(client)) return; /* * Do we have a file to print? */ if (httpGetState(client->http) == HTTP_STATE_POST_RECV) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Unexpected document data following request."); return; } /* * Create the job... */ if ((job = serverCreateJob(client)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_TOO_MANY_JOBS, "Too many jobs are queued."); return; } /* * Return the job info... */ serverRespondIPP(client, IPP_STATUS_OK, NULL); ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); cupsArrayAdd(ra, "job-id"); cupsArrayAdd(ra, "job-state"); cupsArrayAdd(ra, "job-state-message"); cupsArrayAdd(ra, "job-state-reasons"); cupsArrayAdd(ra, "job-uri"); copy_job_attributes(client, job, ra); cupsArrayDelete(ra); /* * Add any subscriptions... */ client->job = job; ipp_create_xxx_subscriptions(client); } /* * 'ipp_create_xxx_subscriptions()' - Create job and printer subscriptions. */ static void ipp_create_xxx_subscriptions( server_client_t *client) { server_subscription_t *sub; /* Subscription */ ipp_attribute_t *attr; /* Subscription attribute */ const char *username; /* requesting-user-name or authenticated username */ int num_subs = 0, /* Number of subscriptions */ ok_subs = 0; /* Number of good subscriptions */ /* * For the Create-xxx-Subscriptions operations, queue up a successful-ok * response... */ if (ippGetOperation(client->request) == IPP_OP_CREATE_JOB_SUBSCRIPTIONS || ippGetOperation(client->request) == IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS) serverRespondIPP(client, IPP_STATUS_OK, NULL); /* * Get the authenticated user name, if any... */ if (client->username[0]) username = client->username; else if ((attr = ippFindAttribute(client->request, "requesting-user-name", IPP_TAG_NAME)) != NULL && ippGetGroupTag(attr) == IPP_TAG_OPERATION && ippGetCount(attr) == 1) username = ippGetString(attr, 0, NULL); else username = "guest"; /* * Skip past the initial attributes to the first subscription group. */ attr = ippFirstAttribute(client->request); while (attr && ippGetGroupTag(attr) != IPP_TAG_SUBSCRIPTION) attr = ippNextAttribute(client->request); while (attr) { server_job_t *job = NULL; /* Job */ const char *attrname, /* Attribute name */ *pullmethod = NULL; /* notify-pull-method */ ipp_attribute_t *notify_attributes = NULL, /* notify-attributes */ *notify_events = NULL, /* notify-events */ *notify_user_data = NULL; /* notify-user-data */ int interval = 0, /* notify-time-interval */ lease = SERVER_NOTIFY_LEASE_DURATION_DEFAULT; /* notify-lease-duration */ ipp_status_t status = IPP_STATUS_OK; /* notify-status-code */ num_subs ++; while (attr) { if ((attrname = ippGetName(attr)) == NULL) break; if (!strcmp(attrname, "notify-recipient-uri")) { /* * Push notifications not supported. */ status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; ippCopyAttribute(client->response, attr, 0); } else if (!strcmp(attrname, "notify-pull-method")) { pullmethod = ippGetString(attr, 0, NULL); if (ippGetValueTag(attr) != IPP_TAG_KEYWORD || ippGetCount(attr) != 1 || !pullmethod || strcmp(pullmethod, "ippget")) { ippCopyAttribute(client->response, attr, 0); pullmethod = NULL; status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; } } else if (!strcmp(attrname, "notify-attributes")) { if (ippGetValueTag(attr) != IPP_TAG_KEYWORD) { status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; ippCopyAttribute(client->response, attr, 0); } notify_attributes = attr; } else if (!strcmp(attrname, "notify-charset")) { if (ippGetValueTag(attr) != IPP_TAG_CHARSET || ippGetCount(attr) != 1 || (strcmp(ippGetString(attr, 0, NULL), "us-ascii") && strcmp(ippGetString(attr, 0, NULL), "utf-8"))) { status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; ippCopyAttribute(client->response, attr, 0); } } else if (!strcmp(attrname, "notify-natural-language")) { if (ippGetValueTag(attr) != IPP_TAG_LANGUAGE || ippGetCount(attr) != 1 || strcmp(ippGetString(attr, 0, NULL), "en")) { status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; ippCopyAttribute(client->response, attr, 0); } } else if (!strcmp(attrname, "notify-user-data")) { int datalen; /* Length of data */ if (ippGetValueTag(attr) != IPP_TAG_STRING || ippGetCount(attr) != 1 || !ippGetOctetString(attr, 0, &datalen) || datalen > 63) { status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; ippCopyAttribute(client->response, attr, 0); } else notify_user_data = attr; } else if (!strcmp(attrname, "notify-events")) { if (ippGetValueTag(attr) != IPP_TAG_KEYWORD) { status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; ippCopyAttribute(client->response, attr, 0); } else notify_events = attr; } else if (!strcmp(attrname, "notify-lease-duration")) { if (ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetCount(attr) != 1 || ippGetInteger(attr, 0) < 0) { status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; ippCopyAttribute(client->response, attr, 0); } else lease = ippGetInteger(attr, 0); } else if (!strcmp(attrname, "notify-time-interval")) { if (ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetCount(attr) != 1 || ippGetInteger(attr, 0) < 0) { status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; ippCopyAttribute(client->response, attr, 0); } else interval = ippGetInteger(attr, 0); } else if (!strcmp(attrname, "notify-job-id")) { if (ippGetOperation(client->request) != IPP_OP_CREATE_JOB_SUBSCRIPTIONS || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetInteger(attr, 0) < 1) { status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; ippCopyAttribute(client->response, attr, 0); } else if ((job = serverFindJob(client, ippGetInteger(attr, 0))) == NULL) { status = IPP_STATUS_ERROR_NOT_FOUND; ippCopyAttribute(client->response, attr, 0); } } attr = ippNextAttribute(client->request); } if (status) { ippAddInteger(client->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", status); } else if (!pullmethod) { ippAddInteger(client->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_STATUS_ERROR_BAD_REQUEST); } else { switch (ippGetOperation(client->request)) { case IPP_OP_PRINT_JOB : case IPP_OP_PRINT_URI : case IPP_OP_CREATE_JOB : job = client->job; break; default : break; } if ((sub = serverCreateSubcription(client->printer, job, interval, lease, username, notify_events, notify_attributes, notify_user_data)) != NULL) { ippAddInteger(client->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-subscription-id", sub->id); ok_subs ++; } else ippAddInteger(client->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_STATUS_ERROR_INTERNAL); } } if (ok_subs == 0 && num_subs != 0) ippSetStatusCode(client->response, IPP_STATUS_ERROR_IGNORED_ALL_SUBSCRIPTIONS); else if (ok_subs != num_subs) ippSetStatusCode(client->response, IPP_STATUS_OK_IGNORED_SUBSCRIPTIONS); } /* * 'ipp_deregister_output_device()' - Unregister an output device. */ static void ipp_deregister_output_device( server_client_t *client) /* I - Client */ { server_device_t *device; /* Device */ /* * Find the device... */ if ((device = serverFindDevice(client)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Output device not found."); return; } /* * Remove the device from the printer... */ _cupsRWLockWrite(&client->printer->rwlock); cupsArrayRemove(client->printer->devices, device); serverUpdateDeviceAttributesNoLock(client->printer); serverUpdateDeviceStateNoLock(client->printer); _cupsRWUnlock(&client->printer->rwlock); /* * Delete the device... */ serverDeleteDevice(device); serverRespondIPP(client, IPP_STATUS_OK, NULL); } /* * 'ipp_fetch_document()' - Download a document. */ static void ipp_fetch_document( server_client_t *client) /* I - Client */ { server_device_t *device; /* Device */ server_job_t *job; /* Job */ ipp_attribute_t *attr; /* Attribute */ int compression; /* compression */ char filename[1024]; /* Job filename */ const char *format = NULL; /* document-format */ if ((device = serverFindDevice(client)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Device was not found."); return; } if ((job = serverFindJob(client, 0)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Job was not found."); return; } if (!job->dev_uuid || strcmp(job->dev_uuid, device->uuid)) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job not assigned to device."); return; } if ((attr = ippFindAttribute(client->request, "document-number", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(attr) != IPP_TAG_OPERATION || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetCount(attr) != 1 || ippGetInteger(attr, 0) != 1) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, attr ? "Bad document-number attribute." : "Missing document-number attribute."); return; } if ((attr = ippFindAttribute(client->request, "compression-accepted", IPP_TAG_KEYWORD)) != NULL) compression = !strcmp(ippGetString(attr, 0, NULL), "gzip"); else compression = 0; if ((attr = ippFindAttribute(client->request, "document-format-accepted", IPP_TAG_MIMETYPE)) != NULL) { int i, /* Looping var */ count = ippGetCount(attr); /* Number of values */ for (i = 0; i < count; i ++) { format = ippGetString(attr, i, NULL); serverCreateJobFilename(client->printer, job, format, filename, sizeof(filename)); if (!access(filename, R_OK)) break; } if (i >= count) { if (ippContainsString(attr, "image/pwg-raster")) { /* * Transform and stream document as PWG Raster... */ serverRespondIPP(client, IPP_STATUS_OK, NULL); ippAddString(client->response, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, "image/pwg-raster"); ippAddString(client->response, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "compression", NULL, compression ? "gzip" : "none"); if (httpGetState(client->http) != HTTP_STATE_POST_SEND) httpFlush(client->http); /* Flush trailing (junk) data */ serverLogAttributes(client, "Response:", client->response, 2); serverLogClient(SERVER_LOGLEVEL_INFO, client, "%s", httpStatus(HTTP_STATUS_OK)); httpClearFields(client->http); httpSetField(client->http, HTTP_FIELD_CONTENT_TYPE, "application/ipp"); if (compression) httpSetField(client->http, HTTP_FIELD_CONTENT_ENCODING, "gzip"); httpSetLength(client->http, 0); if (httpWriteResponse(client->http, HTTP_STATUS_OK) < 0) return; serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "ipp_fetch_document: Sending %d bytes of IPP response.", (int)ippLength(client->response)); ippSetState(client->response, IPP_STATE_IDLE); if (ippWrite(client->http, client->response) != IPP_STATE_DATA) { serverLogClient(SERVER_LOGLEVEL_ERROR, client, "Unable to write IPP response."); return; } serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "ipp_fetch_document: Sent IPP response."); serverTransformJob(client, job, "ipptransform", "image/pwg-raster", SERVER_TRANSFORM_TO_CLIENT); serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "ipp_fetch_document: Sending 0-length chunk."); httpWrite2(client->http, "", 0); serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "ipp_fetch_document: Flushing write buffer."); httpFlushWrite(client->http); return; } else { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FETCHABLE, "Document not available in requested format."); return; } } } else if ((attr = ippFindAttribute(job->attrs, "document-format", IPP_TAG_MIMETYPE)) != NULL) { format = ippGetString(attr, 0, NULL); serverCreateJobFilename(client->printer, job, format, filename, sizeof(filename)); if (access(filename, R_OK)) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FETCHABLE, "Document not available in requested format."); return; } } else { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FETCHABLE, "Document format unknown."); return; } serverRespondIPP(client, IPP_STATUS_OK, NULL); ippAddString(client->response, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, format); ippAddString(client->response, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "compression", NULL, compression ? "gzip" : "none"); client->fetch_file = open(filename, O_RDONLY); } /* * 'ipp_fetch_job()' - Download a job. */ static void ipp_fetch_job(server_client_t *client) /* I - Client */ { server_device_t *device; /* Device */ server_job_t *job; /* Job */ if ((device = serverFindDevice(client)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Device was not found."); return; } if ((job = serverFindJob(client, 0)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Job was not found."); return; } if (job->dev_uuid && strcmp(job->dev_uuid, device->uuid)) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job not assigned to device."); return; } if (!(job->state_reasons & SERVER_JREASON_JOB_FETCHABLE)) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FETCHABLE, "Job not fetchable."); return; } serverRespondIPP(client, IPP_STATUS_OK, NULL); serverCopyAttributes(client->response, job->attrs, NULL, IPP_TAG_JOB, 0); } /* * 'ipp_get_document_attributes()' - Get the attributes for a document object. * * Note: This implementation only supports single document jobs so we * synthesize the information for a single document from the job. */ static void ipp_get_document_attributes( server_client_t *client) /* I - Client */ { // TODO: Implement this! serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Need to implement this."); } /* * 'ipp_get_documents()' - Get the list of documents in a job. * * Note: This implementation only supports single document jobs so we * synthesize the information for a single document from the job. */ static void ipp_get_documents(server_client_t *client)/* I - Client */ { // TODO: Implement this! serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Need to implement this."); } /* * 'ipp_get_job_attributes()' - Get the attributes for a job object. */ static void ipp_get_job_attributes( server_client_t *client) /* I - Client */ { server_job_t *job; /* Job */ cups_array_t *ra; /* requested-attributes */ if ((job = serverFindJob(client, 0)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Job not found."); return; } serverRespondIPP(client, IPP_STATUS_OK, NULL); ra = ippCreateRequestedArray(client->request); copy_job_attributes(client, job, ra); cupsArrayDelete(ra); } /* * 'ipp_get_jobs()' - Get a list of job objects. */ static void ipp_get_jobs(server_client_t *client) /* I - Client */ { ipp_attribute_t *attr; /* Current attribute */ const char *which_jobs = NULL; /* which-jobs values */ int job_comparison; /* Job comparison */ ipp_jstate_t job_state; /* job-state value */ int first_job_id, /* First job ID */ limit, /* Maximum number of jobs to return */ count; /* Number of jobs that match */ const char *username; /* Username */ server_job_t *job; /* Current job pointer */ cups_array_t *ra; /* Requested attributes array */ /* * See if the "which-jobs" attribute have been specified... */ if ((attr = ippFindAttribute(client->request, "which-jobs", IPP_TAG_KEYWORD)) != NULL) { which_jobs = ippGetString(attr, 0, NULL); serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "Get-Jobs which-jobs='%s'", which_jobs); } if (!which_jobs || !strcmp(which_jobs, "not-completed")) { job_comparison = -1; job_state = IPP_JSTATE_STOPPED; } else if (!strcmp(which_jobs, "completed")) { job_comparison = 1; job_state = IPP_JSTATE_CANCELED; } else if (!strcmp(which_jobs, "aborted")) { job_comparison = 0; job_state = IPP_JSTATE_ABORTED; } else if (!strcmp(which_jobs, "all")) { job_comparison = 1; job_state = IPP_JSTATE_PENDING; } else if (!strcmp(which_jobs, "canceled")) { job_comparison = 0; job_state = IPP_JSTATE_CANCELED; } else if (!strcmp(which_jobs, "pending")) { job_comparison = 0; job_state = IPP_JSTATE_PENDING; } else if (!strcmp(which_jobs, "pending-held")) { job_comparison = 0; job_state = IPP_JSTATE_HELD; } else if (!strcmp(which_jobs, "processing")) { job_comparison = 0; job_state = IPP_JSTATE_PROCESSING; } else if (!strcmp(which_jobs, "processing-stopped")) { job_comparison = 0; job_state = IPP_JSTATE_STOPPED; } else { serverRespondIPP(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, "The which-jobs value \"%s\" is not supported.", which_jobs); ippAddString(client->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, "which-jobs", NULL, which_jobs); return; } /* * See if they want to limit the number of jobs reported... */ if ((attr = ippFindAttribute(client->request, "limit", IPP_TAG_INTEGER)) != NULL) { limit = ippGetInteger(attr, 0); serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "Get-Jobs limit=%d", limit); } else limit = 0; if ((attr = ippFindAttribute(client->request, "first-job-id", IPP_TAG_INTEGER)) != NULL) { first_job_id = ippGetInteger(attr, 0); serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "Get-Jobs first-job-id=%d", first_job_id); } else first_job_id = 1; /* * See if we only want to see jobs for a specific user... */ username = NULL; if ((attr = ippFindAttribute(client->request, "my-jobs", IPP_TAG_BOOLEAN)) != NULL) { int my_jobs = ippGetBoolean(attr, 0); serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "Get-Jobs my-jobs=%s", my_jobs ? "true" : "false"); if (my_jobs) { if ((attr = ippFindAttribute(client->request, "requesting-user-name", IPP_TAG_NAME)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Need requesting-user-name with my-jobs."); return; } username = ippGetString(attr, 0, NULL); serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "Get-Jobs requesting-user-name='%s'", username); } } /* * OK, build a list of jobs for this printer... */ ra = ippCreateRequestedArray(client->request); serverRespondIPP(client, IPP_STATUS_OK, NULL); _cupsRWLockRead(&(client->printer->rwlock)); for (count = 0, job = (server_job_t *)cupsArrayFirst(client->printer->jobs); (limit <= 0 || count < limit) && job; job = (server_job_t *)cupsArrayNext(client->printer->jobs)) { /* * Filter out jobs that don't match... */ if ((job_comparison < 0 && job->state > job_state) || (job_comparison == 0 && job->state != job_state) || (job_comparison > 0 && job->state < job_state) || job->id < first_job_id || (username && job->username && strcasecmp(username, job->username))) continue; if (count > 0) ippAddSeparator(client->response); count ++; copy_job_attributes(client, job, ra); } cupsArrayDelete(ra); _cupsRWUnlock(&(client->printer->rwlock)); } /* * 'ipp_get_notifications()' - Get notification events for one or more subscriptions. */ static void ipp_get_notifications( server_client_t *client) /* I - Client */ { ipp_attribute_t *sub_ids, /* notify-subscription-ids */ *seq_nums; /* notify-sequence-numbers */ // ipp_attribute_t *notify_wait; /* Wait for events? */ int i, /* Looping vars */ count, /* Number of IDs */ first = 1, /* First event? */ seq_num; /* Sequence number */ server_subscription_t *sub; /* Current subscription */ ipp_t *event; /* Current event */ if ((sub_ids = ippFindAttribute(client->request, "notify-subscription-ids", IPP_TAG_INTEGER)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing notify-subscription-ids attribute."); return; } count = ippGetCount(sub_ids); seq_nums = ippFindAttribute(client->request, "notify-sequence-numbers", IPP_TAG_INTEGER); // notify_wait = ippFindAttribute(client->request, "notify-wait", IPP_TAG_BOOLEAN); if (seq_nums && count != ippGetCount(seq_nums)) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "The notify-subscription-ids and notify-sequence-numbers attributes are different lengths."); return; } serverRespondIPP(client, IPP_STATUS_OK, NULL); ippAddInteger(client->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "notify-get-interval", 30); for (i = 0; i < count; i ++) { if ((sub = serverFindSubscription(client, ippGetInteger(sub_ids, i))) == NULL) continue; seq_num = ippGetInteger(seq_nums, i); if (seq_num < sub->first_sequence) seq_num = sub->first_sequence; if (seq_num > sub->last_sequence) continue; for (event = (ipp_t *)cupsArrayIndex(sub->events, seq_num - sub->first_sequence); event; event = (ipp_t *)cupsArrayNext(sub->events)) { if (first) first = 0; else ippAddSeparator(client->response); ippCopyAttributes(client->response, event, 0, NULL, NULL); } } } /* * 'ipp_get_output_device_attributes()' - Get attributes for an output device. */ static void ipp_get_output_device_attributes( server_client_t *client) /* I - Client */ { // TODO: Implement this! serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Need to implement this."); } /* * 'ipp_get_printer_attributes()' - Get the attributes for a printer object. */ static void ipp_get_printer_attributes( server_client_t *client) /* I - Client */ { cups_array_t *ra; /* Requested attributes array */ server_printer_t *printer; /* Printer */ /* * Send the attributes... */ ra = ippCreateRequestedArray(client->request); printer = client->printer; serverRespondIPP(client, IPP_STATUS_OK, NULL); _cupsRWLockRead(&(printer->rwlock)); serverCopyAttributes(client->response, printer->pinfo.attrs, ra, IPP_TAG_ZERO, IPP_TAG_CUPS_CONST); serverCopyAttributes(client->response, printer->dev_attrs, ra, IPP_TAG_ZERO, IPP_TAG_ZERO); if (!ra || cupsArrayFind(ra, "printer-config-change-date-time")) ippAddDate(client->response, IPP_TAG_PRINTER, "printer-config-change-date-time", ippTimeToDate(printer->config_time)); if (!ra || cupsArrayFind(ra, "printer-config-change-time")) ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-config-change-time", (int)(printer->config_time - printer->start_time)); if (!ra || cupsArrayFind(ra, "printer-current-time")) ippAddDate(client->response, IPP_TAG_PRINTER, "printer-current-time", ippTimeToDate(time(NULL))); if (!ra || cupsArrayFind(ra, "printer-state")) ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", printer->state > printer->dev_state ? (int)printer->state : (int)printer->dev_state); if (!ra || cupsArrayFind(ra, "printer-state-change-date-time")) ippAddDate(client->response, IPP_TAG_PRINTER, "printer-state-change-date-time", ippTimeToDate(printer->state_time)); if (!ra || cupsArrayFind(ra, "printer-state-change-time")) ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-state-change-time", (int)(printer->state_time - printer->start_time)); if (!ra || cupsArrayFind(ra, "printer-state-message")) { static const char * const messages[] = { "Idle.", "Printing.", "Stopped." }; if (printer->state > printer->dev_state) ippAddString(client->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-state-message", NULL, messages[printer->state - IPP_PSTATE_IDLE]); else ippAddString(client->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-state-message", NULL, messages[printer->dev_state - IPP_PSTATE_IDLE]); } if (!ra || cupsArrayFind(ra, "printer-state-reasons")) serverCopyPrinterStateReasons(client->response, IPP_TAG_PRINTER, printer); if (printer->pinfo.strings && (!ra || cupsArrayFind(ra, "printer-strings-uri"))) { /* * See if we have a localization that matches the request language. */ ipp_attribute_t *attr; /* attributes-natural-language attribute */ char lang[32]; /* Copy of language string */ server_lang_t key, *match; /* Localization key and match */ ippFirstAttribute(client->request); attr = ippNextAttribute(client->request); strlcpy(lang, ippGetString(attr, 0, NULL), sizeof(lang)); key.lang = lang; if ((match = cupsArrayFind(printer->pinfo.strings, &key)) == NULL && lang[2]) { /* * Try base language... */ lang[2] = '\0'; match = cupsArrayFind(printer->pinfo.strings, &key); } if (match) { char uri[1024]; /* printer-strings-uri value */ server_listener_t *lis = cupsArrayFirst(Listeners); /* Default listener */ const char *scheme = "http"; /* URL scheme */ #ifdef HAVE_SSL if (Encryption != HTTP_ENCRYPTION_NEVER) scheme = "https"; #endif /* HAVE_SSL */ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), scheme, NULL, lis->host, lis->port, "%s/%s.strings", printer->resource, match->lang); ippAddString(client->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-strings-uri", NULL, uri); } } if (!ra || cupsArrayFind(ra, "printer-up-time")) ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-up-time", (int)(time(NULL) - printer->start_time)); if (!ra || cupsArrayFind(ra, "queued-job-count")) ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "queued-job-count", cupsArrayCount(printer->active_jobs)); _cupsRWUnlock(&(printer->rwlock)); cupsArrayDelete(ra); } /* * 'ipp_get_printer_supported_values()' - Return the supported values for * the infrastructure printer. */ static void ipp_get_printer_supported_values( server_client_t *client) /* I - Client */ { cups_array_t *ra = ippCreateRequestedArray(client->request); /* Requested attributes */ serverRespondIPP(client, IPP_STATUS_OK, NULL); serverCopyAttributes(client->response, client->printer->pinfo.attrs, ra, IPP_TAG_PRINTER, 1); cupsArrayDelete(ra); } /* * 'ipp_get_subscription_attributes()' - Get attributes for a subscription. */ static void ipp_get_subscription_attributes( server_client_t *client) /* I - Client */ { server_subscription_t *sub; /* Subscription */ cups_array_t *ra = ippCreateRequestedArray(client->request); /* Requested attributes */ if ((sub = serverFindSubscription(client, 0)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Subscription was not found."); } else { serverRespondIPP(client, IPP_STATUS_OK, NULL); copy_subscription_attributes(client, sub, ra); } cupsArrayDelete(ra); } /* * 'ipp_get_subscriptions()' - Get attributes for all subscriptions. */ static void ipp_get_subscriptions( server_client_t *client) /* I - Client */ { server_subscription_t *sub; /* Current subscription */ cups_array_t *ra = ippCreateRequestedArray(client->request); /* Requested attributes */ int first = 1; /* First time? */ serverRespondIPP(client, IPP_STATUS_OK, NULL); _cupsRWLockRead(&client->printer->rwlock); for (sub = (server_subscription_t *)cupsArrayFirst(client->printer->subscriptions); sub; sub = (server_subscription_t *)cupsArrayNext(client->printer->subscriptions)) { if (first) first = 0; else ippAddSeparator(client->response); copy_subscription_attributes(client, sub, ra); } cupsArrayDelete(ra); } /* * 'ipp_identify_printer()' - Beep or display a message. */ static void ipp_identify_printer( server_client_t *client) /* I - Client */ { ipp_attribute_t *actions, /* identify-actions */ *message; /* message */ actions = ippFindAttribute(client->request, "identify-actions", IPP_TAG_KEYWORD); message = ippFindAttribute(client->request, "message", IPP_TAG_TEXT); if (!actions || ippContainsString(actions, "sound")) { putchar(0x07); fflush(stdout); } if (ippContainsString(actions, "display")) printf("IDENTIFY from %s: %s\n", client->hostname, message ? ippGetString(message, 0, NULL) : "No message supplied"); serverRespondIPP(client, IPP_STATUS_OK, NULL); } /* * 'ipp_print_job()' - Create a job object with an attached document. */ static void ipp_print_job(server_client_t *client) /* I - Client */ { server_job_t *job; /* New job */ char filename[1024], /* Filename buffer */ buffer[4096]; /* Copy buffer */ ssize_t bytes; /* Bytes read */ cups_array_t *ra; /* Attributes to send in response */ /* * Validate print job attributes... */ if (!valid_job_attributes(client)) return; /* * Do we have a file to print? */ if (httpGetState(client->http) == HTTP_STATE_POST_SEND) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "No file in request."); return; } /* * Print the job... */ if ((job = serverCreateJob(client)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_TOO_MANY_JOBS, "Too many jobs are queued."); return; } /* * Create a file for the request data... */ serverCreateJobFilename(client->printer, job, NULL, filename, sizeof(filename)); serverLogJob(SERVER_LOGLEVEL_INFO, job, "Creating job file \"%s\", format \"%s\".", filename, job->format); if ((job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { job->state = IPP_JSTATE_ABORTED; serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to create print file: %s", strerror(errno)); return; } while ((bytes = httpRead2(client->http, buffer, sizeof(buffer))) > 0) { if (write(job->fd, buffer, (size_t)bytes) < bytes) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } } if (bytes < 0) { /* * Got an error while reading the print data, so abort this job. */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to read print file."); return; } if (close(job->fd)) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; job->fd = -1; unlink(filename); serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } job->fd = -1; job->filename = strdup(filename); job->state = IPP_JSTATE_PENDING; /* * Process the job, if possible... */ serverCheckJobs(client->printer); /* * Return the job info... */ serverRespondIPP(client, IPP_STATUS_OK, NULL); ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); cupsArrayAdd(ra, "job-id"); cupsArrayAdd(ra, "job-state"); cupsArrayAdd(ra, "job-state-message"); cupsArrayAdd(ra, "job-state-reasons"); cupsArrayAdd(ra, "job-uri"); copy_job_attributes(client, job, ra); cupsArrayDelete(ra); /* * Process any pending subscriptions... */ client->job = job; ipp_create_xxx_subscriptions(client); } /* * 'ipp_print_uri()' - Create a job object with a referenced document. */ static void ipp_print_uri(server_client_t *client) /* I - Client */ { server_job_t *job; /* New job */ ipp_attribute_t *uri; /* document-uri */ char scheme[256], /* URI scheme */ userpass[256], /* Username and password info */ hostname[256], /* Hostname */ resource[1024]; /* Resource path */ int port; /* Port number */ http_uri_status_t uri_status; /* URI decode status */ http_encryption_t encryption; /* Encryption to use, if any */ http_t *http; /* Connection for http/https URIs */ http_status_t status; /* Access status for http/https URIs */ int infile; /* Input file for local file URIs */ char filename[1024], /* Filename buffer */ buffer[4096]; /* Copy buffer */ ssize_t bytes; /* Bytes read */ cups_array_t *ra; /* Attributes to send in response */ static const char * const uri_status_strings[] = { /* URI decode errors */ "URI too large.", "Bad arguments to function.", "Bad resource in URI.", "Bad port number in URI.", "Bad hostname in URI.", "Bad username in URI.", "Bad scheme in URI.", "Bad/empty URI." }; /* * Validate print job attributes... */ if (!valid_job_attributes(client)) return; /* * Do we have a file to print? */ if (httpGetState(client->http) == HTTP_STATE_POST_RECV) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Unexpected document data following request."); return; } /* * Do we have a document URI? */ if ((uri = ippFindAttribute(client->request, "document-uri", IPP_TAG_URI)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing document-uri."); return; } if (ippGetCount(uri) != 1) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Too many document-uri values."); return; } uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL), scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)); if (uri_status < HTTP_URI_STATUS_OK) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad document-uri: %s", uri_status_strings[uri_status - HTTP_URI_STATUS_OVERFLOW]); return; } if (strcmp(scheme, "file") && #ifdef HAVE_SSL strcmp(scheme, "https") && #endif /* HAVE_SSL */ strcmp(scheme, "http")) { serverRespondIPP(client, IPP_STATUS_ERROR_URI_SCHEME, "URI scheme \"%s\" not supported.", scheme); return; } if (!strcmp(scheme, "file") && access(resource, R_OK)) { serverRespondIPP(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to access URI: %s", strerror(errno)); return; } /* * Print the job... */ if ((job = serverCreateJob(client)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_TOO_MANY_JOBS, "Too many jobs are queued."); return; } /* * Create a file for the request data... */ if (!strcasecmp(job->format, "image/jpeg")) snprintf(filename, sizeof(filename), "%s/%d.jpg", SpoolDirectory, job->id); else if (!strcasecmp(job->format, "image/png")) snprintf(filename, sizeof(filename), "%s/%d.png", SpoolDirectory, job->id); else if (!strcasecmp(job->format, "application/pdf")) snprintf(filename, sizeof(filename), "%s/%d.pdf", SpoolDirectory, job->id); else if (!strcasecmp(job->format, "application/postscript")) snprintf(filename, sizeof(filename), "%s/%d.ps", SpoolDirectory, job->id); else snprintf(filename, sizeof(filename), "%s/%d.prn", SpoolDirectory, job->id); if ((job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { job->state = IPP_JSTATE_ABORTED; serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to create print file: %s", strerror(errno)); return; } if (!strcmp(scheme, "file")) { if ((infile = open(resource, O_RDONLY)) < 0) { serverRespondIPP(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to access URI: %s", strerror(errno)); return; } do { if ((bytes = read(infile, buffer, sizeof(buffer))) < 0 && (errno == EAGAIN || errno == EINTR)) bytes = 1; else if (bytes > 0 && write(job->fd, buffer, (size_t)bytes) < bytes) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); close(infile); serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } } while (bytes > 0); close(infile); } else { #ifdef HAVE_SSL if (port == 443 || !strcmp(scheme, "https")) encryption = HTTP_ENCRYPTION_ALWAYS; else #endif /* HAVE_SSL */ encryption = HTTP_ENCRYPTION_IF_REQUESTED; if ((http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to connect to %s: %s", hostname, cupsLastErrorString()); job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); return; } httpClearFields(http); httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); if (httpGet(http, resource)) { serverRespondIPP(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to GET URI: %s", strerror(errno)); job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); httpClose(http); return; } while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); if (status != HTTP_STATUS_OK) { serverRespondIPP(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to GET URI: %s", httpStatus(status)); job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); httpClose(http); return; } while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) { if (write(job->fd, buffer, (size_t)bytes) < bytes) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); httpClose(http); serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } } httpClose(http); } if (close(job->fd)) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; job->fd = -1; unlink(filename); serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } job->fd = -1; job->filename = strdup(filename); job->state = IPP_JSTATE_PENDING; /* * Process the job... */ serverCheckJobs(client->printer); /* * Return the job info... */ serverRespondIPP(client, IPP_STATUS_OK, NULL); ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); cupsArrayAdd(ra, "job-id"); cupsArrayAdd(ra, "job-state"); cupsArrayAdd(ra, "job-state-reasons"); cupsArrayAdd(ra, "job-uri"); copy_job_attributes(client, job, ra); cupsArrayDelete(ra); /* * Process any pending subscriptions... */ client->job = job; ipp_create_xxx_subscriptions(client); } /* * 'ipp_renew_subscription()' - Renew a subscription. */ static void ipp_renew_subscription( server_client_t *client) /* I - Client */ { server_subscription_t *sub; /* Subscription */ ipp_attribute_t *attr; /* notify-lease-duration */ int lease; /* Lease duration in seconds */ if ((sub = serverFindSubscription(client, 0)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Subscription was not found."); return; } if (sub->job) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Per-job subscriptions cannot be renewed."); return; } if ((attr = ippFindAttribute(client->request, "notify-lease-duration", IPP_TAG_ZERO)) != NULL) { if (ippGetGroupTag(attr) != IPP_TAG_SUBSCRIPTION || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetCount(attr) != 1 || ippGetInteger(attr, 0) < 0) { serverRespondIPP(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, "Bad notify-lease-duration."); return; } lease = ippGetInteger(attr, 0); } else lease = SERVER_NOTIFY_LEASE_DURATION_DEFAULT; sub->lease = lease; if (lease) sub->expire = time(NULL) + sub->lease; else sub->expire = INT_MAX; serverRespondIPP(client, IPP_STATUS_OK, NULL); } /* * 'ipp_send_document()' - Add an attached document to a job object created with * Create-Job. */ static void ipp_send_document(server_client_t *client)/* I - Client */ { server_job_t *job; /* Job information */ char filename[1024], /* Filename buffer */ buffer[4096]; /* Copy buffer */ ssize_t bytes; /* Bytes read */ ipp_attribute_t *attr; /* Current attribute */ cups_array_t *ra; /* Attributes to send in response */ /* * Get the job... */ if ((job = serverFindJob(client, 0)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); httpFlush(client->http); return; } /* * See if we already have a document for this job or the job has already * in a non-pending state... */ if (job->state > IPP_JSTATE_HELD) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job is not in a pending state."); httpFlush(client->http); return; } else if (job->filename || job->fd >= 0) { serverRespondIPP(client, IPP_STATUS_ERROR_MULTIPLE_JOBS_NOT_SUPPORTED, "Multiple document jobs are not supported."); httpFlush(client->http); return; } if ((attr = ippFindAttribute(client->request, "last-document", IPP_TAG_ZERO)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing required last-document attribute."); httpFlush(client->http); return; } else if (ippGetValueTag(attr) != IPP_TAG_BOOLEAN || ippGetCount(attr) != 1 || !ippGetBoolean(attr, 0)) { serverRespondUnsupported(client, attr); httpFlush(client->http); return; } /* * Validate document attributes... */ if (!valid_doc_attributes(client)) { httpFlush(client->http); return; } serverCopyAttributes(job->attrs, client->request, NULL, IPP_TAG_JOB, 0); /* * Get the document format for the job... */ _cupsRWLockWrite(&(client->printer->rwlock)); if ((attr = ippFindAttribute(job->attrs, "document-format-detected", IPP_TAG_MIMETYPE)) != NULL) job->format = ippGetString(attr, 0, NULL); else if ((attr = ippFindAttribute(job->attrs, "document-format-supplied", IPP_TAG_MIMETYPE)) != NULL) job->format = ippGetString(attr, 0, NULL); else job->format = "application/octet-stream"; /* * Create a file for the request data... */ serverCreateJobFilename(client->printer, job, NULL, filename, sizeof(filename)); serverLogJob(SERVER_LOGLEVEL_INFO, job, "Creating job file \"%s\", format \"%s\".", filename, job->format); job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); _cupsRWUnlock(&(client->printer->rwlock)); if (job->fd < 0) { job->state = IPP_JSTATE_ABORTED; serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to create print file: %s", strerror(errno)); return; } while ((bytes = httpRead2(client->http, buffer, sizeof(buffer))) > 0) { if (write(job->fd, buffer, (size_t)bytes) < bytes) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } } if (bytes < 0) { /* * Got an error while reading the print data, so abort this job. */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to read print file."); return; } if (close(job->fd)) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; job->fd = -1; unlink(filename); serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } _cupsRWLockWrite(&(client->printer->rwlock)); job->fd = -1; job->filename = strdup(filename); job->state = IPP_JSTATE_PENDING; _cupsRWUnlock(&(client->printer->rwlock)); /* * Process the job, if possible... */ serverCheckJobs(client->printer); /* * Return the job info... */ serverRespondIPP(client, IPP_STATUS_OK, NULL); ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); cupsArrayAdd(ra, "job-id"); cupsArrayAdd(ra, "job-state"); cupsArrayAdd(ra, "job-state-reasons"); cupsArrayAdd(ra, "job-uri"); copy_job_attributes(client, job, ra); cupsArrayDelete(ra); } /* * 'ipp_send_uri()' - Add a referenced document to a job object created with * Create-Job. */ static void ipp_send_uri(server_client_t *client) /* I - Client */ { server_job_t *job; /* Job information */ ipp_attribute_t *uri; /* document-uri */ char scheme[256], /* URI scheme */ userpass[256], /* Username and password info */ hostname[256], /* Hostname */ resource[1024]; /* Resource path */ int port; /* Port number */ http_uri_status_t uri_status; /* URI decode status */ http_encryption_t encryption; /* Encryption to use, if any */ http_t *http; /* Connection for http/https URIs */ http_status_t status; /* Access status for http/https URIs */ int infile; /* Input file for local file URIs */ char filename[1024], /* Filename buffer */ buffer[4096]; /* Copy buffer */ ssize_t bytes; /* Bytes read */ ipp_attribute_t *attr; /* Current attribute */ cups_array_t *ra; /* Attributes to send in response */ static const char * const uri_status_strings[] = { /* URI decode errors */ "URI too large.", "Bad arguments to function.", "Bad resource in URI.", "Bad port number in URI.", "Bad hostname in URI.", "Bad username in URI.", "Bad scheme in URI.", "Bad/empty URI." }; /* * Get the job... */ if ((job = serverFindJob(client, 0)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); httpFlush(client->http); return; } /* * See if we already have a document for this job or the job has already * in a non-pending state... */ if (job->state > IPP_JSTATE_HELD) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job is not in a pending state."); httpFlush(client->http); return; } else if (job->filename || job->fd >= 0) { serverRespondIPP(client, IPP_STATUS_ERROR_MULTIPLE_JOBS_NOT_SUPPORTED, "Multiple document jobs are not supported."); httpFlush(client->http); return; } if ((attr = ippFindAttribute(client->request, "last-document", IPP_TAG_ZERO)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing required last-document attribute."); httpFlush(client->http); return; } else if (ippGetValueTag(attr) != IPP_TAG_BOOLEAN || ippGetCount(attr) != 1 || !ippGetBoolean(attr, 0)) { serverRespondUnsupported(client, attr); httpFlush(client->http); return; } /* * Validate document attributes... */ if (!valid_doc_attributes(client)) { httpFlush(client->http); return; } /* * Do we have a file to print? */ if (httpGetState(client->http) == HTTP_STATE_POST_RECV) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Unexpected document data following request."); return; } /* * Do we have a document URI? */ if ((uri = ippFindAttribute(client->request, "document-uri", IPP_TAG_URI)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing document-uri."); return; } if (ippGetCount(uri) != 1) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Too many document-uri values."); return; } uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL), scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)); if (uri_status < HTTP_URI_STATUS_OK) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad document-uri: %s", uri_status_strings[uri_status - HTTP_URI_STATUS_OVERFLOW]); return; } if (strcmp(scheme, "file") && #ifdef HAVE_SSL strcmp(scheme, "https") && #endif /* HAVE_SSL */ strcmp(scheme, "http")) { serverRespondIPP(client, IPP_STATUS_ERROR_URI_SCHEME, "URI scheme \"%s\" not supported.", scheme); return; } if (!strcmp(scheme, "file") && access(resource, R_OK)) { serverRespondIPP(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to access URI: %s", strerror(errno)); return; } /* * Get the document format for the job... */ _cupsRWLockWrite(&(client->printer->rwlock)); if ((attr = ippFindAttribute(job->attrs, "document-format", IPP_TAG_MIMETYPE)) != NULL) job->format = ippGetString(attr, 0, NULL); else job->format = "application/octet-stream"; /* * Create a file for the request data... */ if (!strcasecmp(job->format, "image/jpeg")) snprintf(filename, sizeof(filename), "%s/%d.jpg", SpoolDirectory, job->id); else if (!strcasecmp(job->format, "image/png")) snprintf(filename, sizeof(filename), "%s/%d.png", SpoolDirectory, job->id); else if (!strcasecmp(job->format, "application/pdf")) snprintf(filename, sizeof(filename), "%s/%d.pdf", SpoolDirectory, job->id); else if (!strcasecmp(job->format, "application/postscript")) snprintf(filename, sizeof(filename), "%s/%d.ps", SpoolDirectory, job->id); else snprintf(filename, sizeof(filename), "%s/%d.prn", SpoolDirectory, job->id); job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); _cupsRWUnlock(&(client->printer->rwlock)); if (job->fd < 0) { job->state = IPP_JSTATE_ABORTED; serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to create print file: %s", strerror(errno)); return; } if (!strcmp(scheme, "file")) { if ((infile = open(resource, O_RDONLY)) < 0) { serverRespondIPP(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to access URI: %s", strerror(errno)); return; } do { if ((bytes = read(infile, buffer, sizeof(buffer))) < 0 && (errno == EAGAIN || errno == EINTR)) bytes = 1; else if (bytes > 0 && write(job->fd, buffer, (size_t)bytes) < bytes) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); close(infile); serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } } while (bytes > 0); close(infile); } else { #ifdef HAVE_SSL if (port == 443 || !strcmp(scheme, "https")) encryption = HTTP_ENCRYPTION_ALWAYS; else #endif /* HAVE_SSL */ encryption = HTTP_ENCRYPTION_IF_REQUESTED; if ((http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to connect to %s: %s", hostname, cupsLastErrorString()); job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); return; } httpClearFields(http); httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); if (httpGet(http, resource)) { serverRespondIPP(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to GET URI: %s", strerror(errno)); job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); httpClose(http); return; } while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); if (status != HTTP_STATUS_OK) { serverRespondIPP(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to GET URI: %s", httpStatus(status)); job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); httpClose(http); return; } while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) { if (write(job->fd, buffer, (size_t)bytes) < bytes) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; close(job->fd); job->fd = -1; unlink(filename); httpClose(http); serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } } httpClose(http); } if (close(job->fd)) { int error = errno; /* Write error */ job->state = IPP_JSTATE_ABORTED; job->fd = -1; unlink(filename); serverRespondIPP(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error)); return; } _cupsRWLockWrite(&(client->printer->rwlock)); job->fd = -1; job->filename = strdup(filename); job->state = IPP_JSTATE_PENDING; _cupsRWUnlock(&(client->printer->rwlock)); /* * Process the job, if possible... */ serverCheckJobs(client->printer); /* * Return the job info... */ serverRespondIPP(client, IPP_STATUS_OK, NULL); ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); cupsArrayAdd(ra, "job-id"); cupsArrayAdd(ra, "job-state"); cupsArrayAdd(ra, "job-state-reasons"); cupsArrayAdd(ra, "job-uri"); copy_job_attributes(client, job, ra); cupsArrayDelete(ra); } /* * 'ipp_update_active_jobs()' - Update the list of active jobs. */ static void ipp_update_active_jobs( server_client_t *client) /* I - Client */ { server_device_t *device; /* Output device */ server_job_t *job; /* Job */ ipp_attribute_t *job_ids, /* job-ids */ *job_states; /* output-device-job-states */ int i, /* Looping var */ count, /* Number of values */ num_different = 0, /* Number of jobs with different states */ different[1000],/* Jobs with different states */ num_unsupported = 0, /* Number of unsupported job-ids */ unsupported[1000]; /* Unsupported job-ids */ ipp_jstate_t states[1000]; /* Different job state values */ /* * Process the job-ids and output-device-job-states values... */ if ((device = serverFindDevice(client)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Device was not found."); return; } if ((job_ids = ippFindAttribute(client->request, "job-ids", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(job_ids) != IPP_TAG_OPERATION || ippGetValueTag(job_ids) != IPP_TAG_INTEGER) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, job_ids ? "Bad job-ids attribute." : "Missing required job-ids attribute."); return; } if ((job_states = ippFindAttribute(client->request, "output-device-job-states", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(job_states) != IPP_TAG_OPERATION || ippGetValueTag(job_states) != IPP_TAG_ENUM) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, job_ids ? "Bad output-device-job-states attribute." : "Missing required output-device-job-states attribute."); return; } count = ippGetCount(job_ids); if (count != ippGetCount(job_states)) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "The job-ids and output-device-job-states attributes do not have the same number of values."); return; } for (i = 0; i < count; i ++) { if ((job = serverFindJob(client, ippGetInteger(job_ids, i))) == NULL || !job->dev_uuid || strcmp(job->dev_uuid, device->uuid)) { if (num_unsupported < 1000) unsupported[num_unsupported ++] = ippGetInteger(job_ids, i); } else { ipp_jstate_t state = (ipp_jstate_t)ippGetInteger(job_states, i); if (job->state >= IPP_JSTATE_STOPPED && state != job->state) { if (num_different < 1000) { different[num_different] = job->id; states[num_different ++] = job->state; } } else job->dev_state = state; } } /* * Then look for jobs assigned to the device but not listed... */ for (job = (server_job_t *)cupsArrayFirst(client->printer->jobs); job && num_different < 1000; job = (server_job_t *)cupsArrayNext(client->printer->jobs)) { if (job->dev_uuid && !strcmp(job->dev_uuid, device->uuid) && !ippContainsInteger(job_ids, job->id)) { different[num_different] = job->id; states[num_different ++] = job->state; } } serverRespondIPP(client, IPP_STATUS_OK, NULL); if (num_different > 0) { ippAddIntegers(client->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-ids", num_different, different); ippAddIntegers(client->response, IPP_TAG_OPERATION, IPP_TAG_ENUM, "output-device-job-states", num_different, (int *)states); } if (num_unsupported > 0) { ippAddIntegers(client->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER, "job-ids", num_unsupported, unsupported); } } /* * 'ipp_update_document_status()' - Update the state of a document. */ static void ipp_update_document_status( server_client_t *client) /* I - Client */ { server_device_t *device; /* Device */ server_job_t *job; /* Job */ ipp_attribute_t *attr; /* Attribute */ if ((device = serverFindDevice(client)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Device was not found."); return; } if ((job = serverFindJob(client, 0)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Job was not found."); return; } if (!job->dev_uuid || strcmp(job->dev_uuid, device->uuid)) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job not assigned to device."); return; } if ((attr = ippFindAttribute(client->request, "document-number", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(attr) != IPP_TAG_OPERATION || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetCount(attr) != 1 || ippGetInteger(attr, 0) != 1) { serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, attr ? "Bad document-number attribute." : "Missing document-number attribute."); return; } if ((attr = ippFindAttribute(client->request, "impressions-completed", IPP_TAG_INTEGER)) != NULL) { job->impcompleted = ippGetInteger(attr, 0); serverAddEvent(client->printer, job, SERVER_EVENT_JOB_PROGRESS, NULL); } serverRespondIPP(client, IPP_STATUS_OK, NULL); } /* * 'ipp_update_job_status()' - Update the state of a job. */ static void ipp_update_job_status( server_client_t *client) /* I - Client */ { server_device_t *device; /* Device */ server_job_t *job; /* Job */ ipp_attribute_t *attr; /* Attribute */ server_event_t events = SERVER_EVENT_NONE; /* Event(s) */ if ((device = serverFindDevice(client)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Device was not found."); return; } if ((job = serverFindJob(client, 0)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "Job was not found."); return; } if (!job->dev_uuid || strcmp(job->dev_uuid, device->uuid)) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job not assigned to device."); return; } if ((attr = ippFindAttribute(client->request, "job-impressions-completed", IPP_TAG_INTEGER)) != NULL) { job->impcompleted = ippGetInteger(attr, 0); events |= SERVER_EVENT_JOB_PROGRESS; } if ((attr = ippFindAttribute(client->request, "output-device-job-state", IPP_TAG_ENUM)) != NULL) { job->dev_state = (ipp_jstate_t)ippGetInteger(attr, 0); events |= SERVER_EVENT_JOB_STATE_CHANGED; } if ((attr = ippFindAttribute(client->request, "output-device-job-state-reasons", IPP_TAG_KEYWORD)) != NULL) { job->dev_state_reasons = serverGetJobStateReasonsBits(attr); events |= SERVER_EVENT_JOB_STATE_CHANGED; } if (events) serverAddEvent(client->printer, job, events, NULL); serverRespondIPP(client, IPP_STATUS_OK, NULL); } /* * 'ipp_update_output_device_attributes()' - Update the values for an output device. */ static void ipp_update_output_device_attributes( server_client_t *client) /* I - Client */ { server_device_t *device; /* Device */ ipp_attribute_t *attr, /* Current attribute */ *dev_attr; /* Device attribute */ server_event_t events = SERVER_EVENT_NONE; /* Config/state changed? */ if ((device = serverFindDevice(client)) == NULL) { if ((device = serverCreateDevice(client)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Unable to add output device."); return; } } _cupsRWLockWrite(&device->rwlock); attr = ippFirstAttribute(client->request); while (attr && ippGetGroupTag(attr) != IPP_TAG_PRINTER) attr = ippNextAttribute(client->request); for (; attr; attr = ippNextAttribute(client->request)) { const char *attrname = ippGetName(attr), /* Attribute name */ *dotptr; /* Pointer to dot in name */ /* * Skip attributes we don't care about... */ if (!attrname) continue; if (strncmp(attrname, "copies", 6) && strncmp(attrname, "document-format", 15) && strncmp(attrname, "finishings", 10) && strncmp(attrname, "media", 5) && strncmp(attrname, "print-", 6) && strncmp(attrname, "sides", 5) && strncmp(attrname, "printer-alert", 13) && strncmp(attrname, "printer-input", 13) && strncmp(attrname, "printer-output", 14) && strncmp(attrname, "printer-resolution", 18) && strncmp(attrname, "pwg-raster", 10) && strncmp(attrname, "urf-", 4)) continue; if (strncmp(attrname, "printer-alert", 13) || strncmp(attrname, "printer-state", 13)) events |= SERVER_EVENT_PRINTER_CONFIG_CHANGED; else events |= SERVER_EVENT_PRINTER_STATE_CHANGED; if (!strcmp(attrname, "media-col-ready") || !strcmp(attrname, "media-ready")) events |= SERVER_EVENT_PRINTER_MEDIA_CHANGED; if (!strcmp(attrname, "finishings-col-ready") || !strcmp(attrname, "finishings-ready")) events |= SERVER_EVENT_PRINTER_FINISHINGS_CHANGED; if ((dotptr = strrchr(attrname, '.')) != NULL && isdigit(dotptr[1] & 255)) { #if 0 /* * Sparse representation: name.NNN or name.NNN-NNN */ char temp[256], /* Temporary name string */ *tempptr; /* Pointer into temporary string */ int low, high; /* Low and high numbers in range */ low = (int)strtol(dotptr + 1, (char **)&dotptr, 10); if (dotptr && *dotptr == '-') high = (int)strtol(dotptr + 1, NULL, 10); else high = low; strlcpy(temp, attrname, sizeof(temp)); if ((tempptr = strrchr(temp, '.')) != NULL) *tempptr = '\0'; if ((dev_attr = ippFindAttribute(device->attrs, temp, IPP_TAG_ZERO)) != NULL) { } else #endif /* 0 */ serverRespondUnsupported(client, attr); } else { /* * Regular representation - replace or delete current attribute, * if any... */ if ((dev_attr = ippFindAttribute(device->attrs, attrname, IPP_TAG_ZERO)) != NULL) ippDeleteAttribute(device->attrs, dev_attr); if (ippGetValueTag(attr) != IPP_TAG_DELETEATTR) ippCopyAttribute(device->attrs, attr, 0); } } _cupsRWUnlock(&device->rwlock); if (events) { _cupsRWLockWrite(&client->printer->rwlock); if (events & SERVER_EVENT_PRINTER_CONFIG_CHANGED) serverUpdateDeviceAttributesNoLock(client->printer); if (events & SERVER_EVENT_PRINTER_STATE_CHANGED) serverUpdateDeviceStateNoLock(client->printer); _cupsRWUnlock(&client->printer->rwlock); serverAddEvent(client->printer, NULL, events, NULL); } } /* * 'ipp_validate_document()' - Validate document creation attributes. */ static void ipp_validate_document( server_client_t *client) /* I - Client */ { if (valid_doc_attributes(client)) serverRespondIPP(client, IPP_STATUS_OK, NULL); } /* * 'ipp_validate_job()' - Validate job creation attributes. */ static void ipp_validate_job(server_client_t *client) /* I - Client */ { if (valid_job_attributes(client)) serverRespondIPP(client, IPP_STATUS_OK, NULL); } /* * 'serverProcessIPP()' - Process an IPP request. */ int /* O - 1 on success, 0 on error */ serverProcessIPP( server_client_t *client) /* I - Client */ { ipp_tag_t group; /* Current group tag */ ipp_attribute_t *attr; /* Current attribute */ ipp_attribute_t *charset; /* Character set attribute */ ipp_attribute_t *language; /* Language attribute */ ipp_attribute_t *uri; /* Printer URI attribute */ int major, minor; /* Version number */ const char *name; /* Name of attribute */ serverLogAttributes(client, "Request:", client->request, 1); /* * First build an empty response message for this request... */ client->operation_id = ippGetOperation(client->request); client->response = ippNewResponse(client->request); /* * Then validate the request header and required attributes... */ major = ippGetVersion(client->request, &minor); if (major < 1 || major > 2) { /* * Return an error, since we only support IPP 1.x and 2.x. */ serverRespondIPP(client, IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, "Bad request version number %d.%d.", major, minor); } else if (ippGetRequestId(client->request) <= 0) serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad request-id %d.", ippGetRequestId(client->request)); else if (!ippFirstAttribute(client->request)) serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "No attributes in request."); else { /* * Make sure that the attributes are provided in the correct order and * don't repeat groups... */ for (attr = ippFirstAttribute(client->request), group = ippGetGroupTag(attr); attr; attr = ippNextAttribute(client->request)) { if (ippGetGroupTag(attr) < group && ippGetGroupTag(attr) != IPP_TAG_ZERO) { /* * Out of order; return an error... */ serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Attribute groups are out of order (%x < %x).", ippGetGroupTag(attr), group); break; } else group = ippGetGroupTag(attr); } if (!attr) { /* * Then make sure that the first three attributes are: * * attributes-charset * attributes-natural-language * printer-uri/job-uri */ attr = ippFirstAttribute(client->request); name = ippGetName(attr); if (attr && name && !strcmp(name, "attributes-charset") && ippGetValueTag(attr) == IPP_TAG_CHARSET) charset = attr; else charset = NULL; attr = ippNextAttribute(client->request); name = ippGetName(attr); if (attr && name && !strcmp(name, "attributes-natural-language") && ippGetValueTag(attr) == IPP_TAG_LANGUAGE) language = attr; else language = NULL; if ((attr = ippFindAttribute(client->request, "printer-uri", IPP_TAG_URI)) != NULL) uri = attr; else if ((attr = ippFindAttribute(client->request, "job-uri", IPP_TAG_URI)) != NULL) uri = attr; else uri = NULL; if (charset && strcasecmp(ippGetString(charset, 0, NULL), "us-ascii") && strcasecmp(ippGetString(charset, 0, NULL), "utf-8")) { /* * Bad character set... */ serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Unsupported character set \"%s\".", ippGetString(charset, 0, NULL)); } else if (!charset || !language || !uri) { /* * Return an error, since attributes-charset, * attributes-natural-language, and printer-uri/job-uri are required * for all operations. */ serverRespondIPP(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing required attributes."); } else { char scheme[32], /* URI scheme */ userpass[32], /* Username/password in URI */ host[256], /* Host name in URI */ resource[256], /* Resource path in URI */ *resptr; /* Pointer into resource path */ int port; /* Port number in URI */ name = ippGetName(uri); client->printer = NULL; if (httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL), scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) { serverRespondIPP(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, "Bad \"%s\" value '%s'.", name, ippGetString(uri, 0, NULL)); } else if (!strcmp(name, "job-uri")) { /* * Validate job-uri... */ if (strncmp(resource, "/ipp/print/", 11)) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "\"%s\" '%s' not found.", name, ippGetString(uri, 0, NULL)); } else { /* * Strip job-id from resource... */ if ((resptr = strchr(resource + 11, '/')) != NULL) *resptr = '\0'; if ((client->printer = serverFindPrinter(resource)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "\"%s\" '%s' not found.", name, ippGetString(uri, 0, NULL)); } } } else if ((client->printer = serverFindPrinter(resource)) == NULL) { serverRespondIPP(client, IPP_STATUS_ERROR_NOT_FOUND, "\"%s\" '%s' not found.", name, ippGetString(uri, 0, NULL)); } if (client->printer) { /* * Try processing the operation... */ switch ((int)ippGetOperation(client->request)) { case IPP_OP_PRINT_JOB : ipp_print_job(client); break; case IPP_OP_PRINT_URI : ipp_print_uri(client); break; case IPP_OP_VALIDATE_JOB : ipp_validate_job(client); break; case IPP_OP_CREATE_JOB : ipp_create_job(client); break; case IPP_OP_SEND_DOCUMENT : ipp_send_document(client); break; case IPP_OP_SEND_URI : ipp_send_uri(client); break; case IPP_OP_CANCEL_JOB : ipp_cancel_job(client); break; case IPP_OP_CANCEL_MY_JOBS : ipp_cancel_my_jobs(client); break; case IPP_OP_GET_JOB_ATTRIBUTES : ipp_get_job_attributes(client); break; case IPP_OP_GET_JOBS : ipp_get_jobs(client); break; case IPP_OP_GET_PRINTER_ATTRIBUTES : ipp_get_printer_attributes(client); break; case IPP_OP_GET_PRINTER_SUPPORTED_VALUES : ipp_get_printer_supported_values(client); break; case IPP_OP_CLOSE_JOB : ipp_close_job(client); break; case IPP_OP_IDENTIFY_PRINTER : ipp_identify_printer(client); break; case IPP_OP_CANCEL_SUBSCRIPTION : ipp_cancel_subscription(client); break; case IPP_OP_CREATE_JOB_SUBSCRIPTIONS : case IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS : ipp_create_xxx_subscriptions(client); break; case IPP_OP_GET_NOTIFICATIONS : ipp_get_notifications(client); break; case IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES : ipp_get_subscription_attributes(client); break; case IPP_OP_GET_SUBSCRIPTIONS : ipp_get_subscriptions(client); break; case IPP_OP_RENEW_SUBSCRIPTION : ipp_renew_subscription(client); break; case IPP_OP_GET_DOCUMENT_ATTRIBUTES : ipp_get_document_attributes(client); break; case IPP_OP_GET_DOCUMENTS : ipp_get_documents(client); break; case IPP_OP_VALIDATE_DOCUMENT : ipp_validate_document(client); break; case IPP_OP_ACKNOWLEDGE_DOCUMENT : ipp_acknowledge_document(client); break; case IPP_OP_ACKNOWLEDGE_IDENTIFY_PRINTER : ipp_acknowledge_identify_printer(client); break; case IPP_OP_ACKNOWLEDGE_JOB : ipp_acknowledge_job(client); break; case IPP_OP_FETCH_DOCUMENT : ipp_fetch_document(client); break; case IPP_OP_FETCH_JOB : ipp_fetch_job(client); break; case IPP_OP_GET_OUTPUT_DEVICE_ATTRIBUTES : ipp_get_output_device_attributes(client); break; case IPP_OP_UPDATE_ACTIVE_JOBS : ipp_update_active_jobs(client); break; case IPP_OP_UPDATE_DOCUMENT_STATUS : ipp_update_document_status(client); break; case IPP_OP_UPDATE_JOB_STATUS : ipp_update_job_status(client); break; case IPP_OP_UPDATE_OUTPUT_DEVICE_ATTRIBUTES : ipp_update_output_device_attributes(client); break; case IPP_OP_DEREGISTER_OUTPUT_DEVICE : ipp_deregister_output_device(client); break; default : serverRespondIPP(client, IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED, "Operation not supported."); break; } } } } } /* * Send the HTTP header and return... */ if (httpGetState(client->http) != HTTP_STATE_WAITING) { if (httpGetState(client->http) != HTTP_STATE_POST_SEND) httpFlush(client->http); /* Flush trailing (junk) data */ serverLogAttributes(client, "Response:", client->response, 2); return (serverRespondHTTP(client, HTTP_STATUS_OK, NULL, "application/ipp", client->fetch_file >= 0 ? 0 : ippLength(client->response))); } else return (1); } /* * 'serverRespondIPP()' - Send an IPP response. */ void serverRespondIPP( server_client_t *client, /* I - Client */ ipp_status_t status, /* I - status-code */ const char *message, /* I - printf-style status-message */ ...) /* I - Additional args as needed */ { const char *formatted = NULL; /* Formatted message */ ippSetStatusCode(client->response, status); if (message) { va_list ap; /* Pointer to additional args */ ipp_attribute_t *attr; /* New status-message attribute */ va_start(ap, message); if ((attr = ippFindAttribute(client->response, "status-message", IPP_TAG_TEXT)) != NULL) ippSetStringfv(client->response, &attr, 0, message, ap); else attr = ippAddStringfv(client->response, IPP_TAG_OPERATION, IPP_TAG_TEXT, "status-message", NULL, message, ap); va_end(ap); formatted = ippGetString(attr, 0, NULL); } if (formatted) serverLogClient(SERVER_LOGLEVEL_INFO, client, "%s %s (%s)", ippOpString(client->operation_id), ippErrorString(status), formatted); else serverLogClient(SERVER_LOGLEVEL_INFO, client, "%s %s", ippOpString(client->operation_id), ippErrorString(status)); } /* * 'serverRespondUnsupported()' - Respond with an unsupported attribute. */ void serverRespondUnsupported( server_client_t *client, /* I - Client */ ipp_attribute_t *attr) /* I - Atribute */ { ipp_attribute_t *temp; /* Copy of attribute */ serverRespondIPP(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, "Unsupported %s %s%s value.", ippGetName(attr), ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr))); temp = ippCopyAttribute(client->response, attr, 0); ippSetGroupTag(client->response, &temp, IPP_TAG_UNSUPPORTED_GROUP); } /* * 'valid_doc_attributes()' - Determine whether the document attributes are * valid. * * When one or more document attributes are invalid, this function adds a * suitable response and attributes to the unsupported group. */ static int /* O - 1 if valid, 0 if not */ valid_doc_attributes( server_client_t *client) /* I - Client */ { int valid = 1; /* Valid attributes? */ ipp_op_t op = ippGetOperation(client->request); /* IPP operation */ const char *op_name = ippOpString(op); /* IPP operation name */ ipp_attribute_t *attr, /* Current attribute */ *supported; /* xxx-supported attribute */ const char *compression = NULL, /* compression value */ *format = NULL; /* document-format value */ /* * Check operation attributes... */ if ((attr = ippFindAttribute(client->request, "compression", IPP_TAG_ZERO)) != NULL) { /* * If compression is specified, only accept a supported value in a Print-Job * or Send-Document request... */ compression = ippGetString(attr, 0, NULL); supported = ippFindAttribute(client->printer->pinfo.attrs, "compression-supported", IPP_TAG_KEYWORD); if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_KEYWORD || ippGetGroupTag(attr) != IPP_TAG_OPERATION || (op != IPP_OP_PRINT_JOB && op != IPP_OP_SEND_DOCUMENT && op != IPP_OP_VALIDATE_JOB) || !ippContainsString(supported, compression)) { serverRespondUnsupported(client, attr); valid = 0; } else { serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "%s compression='%s'", op_name, compression); ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "compression-supplied", NULL, compression); if (strcmp(compression, "none")) httpSetField(client->http, HTTP_FIELD_CONTENT_ENCODING, compression); } } /* * Is it a format we support? */ if ((attr = ippFindAttribute(client->request, "document-format", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_MIMETYPE || ippGetGroupTag(attr) != IPP_TAG_OPERATION) { serverRespondUnsupported(client, attr); valid = 0; } else { format = ippGetString(attr, 0, NULL); serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "%s document-format='%s'", op_name, format); ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-supplied", NULL, format); } } else { format = ippGetString(ippFindAttribute(client->printer->pinfo.attrs, "document-format-default", IPP_TAG_MIMETYPE), 0, NULL); if (!format) format = "application/octet-stream"; /* Should never happen */ attr = ippAddString(client->request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, format); } if ((!format || !strcmp(format, "application/octet-stream")) && (ippGetOperation(client->request) == IPP_OP_PRINT_JOB || ippGetOperation(client->request) == IPP_OP_SEND_DOCUMENT)) { /* * Auto-type the file using the first 8 bytes of the file... */ unsigned char header[8]; /* First 8 bytes of file */ memset(header, 0, sizeof(header)); httpPeek(client->http, (char *)header, sizeof(header)); if (!memcmp(header, "%PDF", 4)) format = "application/pdf"; else if (!memcmp(header, "%!", 2)) format = "application/postscript"; else if (!memcmp(header, "\377\330\377", 3) && header[3] >= 0xe0 && header[3] <= 0xef) format = "image/jpeg"; else if (!memcmp(header, "\211PNG", 4)) format = "image/png"; else if (!memcmp(header, "RAS2", 4)) format = "image/pwg-raster"; else if (!memcmp(header, "UNIRAST", 8)) format = "image/urf"; else format = NULL; if (format) { serverLogClient(SERVER_LOGLEVEL_DEBUG, client, "%s Auto-typed document-format='%s'", op_name, format); ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-detected", NULL, format); } } if ((op == IPP_OP_PRINT_JOB || op == IPP_OP_SEND_DOCUMENT) && (supported = ippFindAttribute(client->printer->pinfo.attrs, "document-format-supported", IPP_TAG_MIMETYPE)) != NULL && !ippContainsString(supported, format) && attr && ippGetGroupTag(attr) == IPP_TAG_OPERATION) { serverRespondUnsupported(client, attr); valid = 0; } /* * document-name */ if ((attr = ippFindAttribute(client->request, "document-name", IPP_TAG_NAME)) != NULL) ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_NAME, "document-name-supplied", NULL, ippGetString(attr, 0, NULL)); return (valid); } /* * 'valid_job_attributes()' - Determine whether the job attributes are valid. * * When one or more job attributes are invalid, this function adds a suitable * response and attributes to the unsupported group. */ static int /* O - 1 if valid, 0 if not */ valid_job_attributes( server_client_t *client) /* I - Client */ { int i, /* Looping var */ count, /* Number of values */ valid = 1; /* Valid attributes? */ ipp_attribute_t *attr, /* Current attribute */ *supported; /* xxx-supported attribute */ /* * Check operation attributes... */ valid = valid_doc_attributes(client); /* * Check the various job template attributes... */ if ((attr = ippFindAttribute(client->request, "copies", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetInteger(attr, 0) < 1 || ippGetInteger(attr, 0) > 999) { serverRespondUnsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "ipp-attribute-fidelity", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_BOOLEAN) { serverRespondUnsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "job-hold-until", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || (ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG && ippGetValueTag(attr) != IPP_TAG_KEYWORD) || strcmp(ippGetString(attr, 0, NULL), "no-hold")) { serverRespondUnsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "job-impressions", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetInteger(attr, 0) < 0) { serverRespondUnsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "job-name", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || (ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG)) { serverRespondUnsupported(client, attr); valid = 0; } ippSetGroupTag(client->request, &attr, IPP_TAG_JOB); } else ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled"); if ((attr = ippFindAttribute(client->request, "job-priority", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetInteger(attr, 0) < 1 || ippGetInteger(attr, 0) > 100) { serverRespondUnsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "job-sheets", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || (ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG && ippGetValueTag(attr) != IPP_TAG_KEYWORD) || strcmp(ippGetString(attr, 0, NULL), "none")) { serverRespondUnsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "media", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || (ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG && ippGetValueTag(attr) != IPP_TAG_KEYWORD)) { serverRespondUnsupported(client, attr); valid = 0; } else { supported = ippFindAttribute(client->printer->pinfo.attrs, "media-supported", IPP_TAG_KEYWORD); if (!ippContainsString(supported, ippGetString(attr, 0, NULL))) { serverRespondUnsupported(client, attr); valid = 0; } } } if ((attr = ippFindAttribute(client->request, "media-col", IPP_TAG_ZERO)) != NULL) { ipp_t *col, /* media-col collection */ *size; /* media-size collection */ ipp_attribute_t *member, /* Member attribute */ *x_dim, /* x-dimension */ *y_dim; /* y-dimension */ int x_value, /* y-dimension value */ y_value; /* x-dimension value */ if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_BEGIN_COLLECTION) { serverRespondUnsupported(client, attr); valid = 0; } col = ippGetCollection(attr, 0); if ((member = ippFindAttribute(col, "media-size-name", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(member) != 1 || (ippGetValueTag(member) != IPP_TAG_NAME && ippGetValueTag(member) != IPP_TAG_NAMELANG && ippGetValueTag(member) != IPP_TAG_KEYWORD)) { serverRespondUnsupported(client, attr); valid = 0; } else { supported = ippFindAttribute(client->printer->pinfo.attrs, "media-supported", IPP_TAG_KEYWORD); if (!ippContainsString(supported, ippGetString(member, 0, NULL))) { serverRespondUnsupported(client, attr); valid = 0; } } } else if ((member = ippFindAttribute(col, "media-size", IPP_TAG_BEGIN_COLLECTION)) != NULL) { if (ippGetCount(member) != 1) { serverRespondUnsupported(client, attr); valid = 0; } else { size = ippGetCollection(member, 0); if ((x_dim = ippFindAttribute(size, "x-dimension", IPP_TAG_INTEGER)) == NULL || ippGetCount(x_dim) != 1 || (y_dim = ippFindAttribute(size, "y-dimension", IPP_TAG_INTEGER)) == NULL || ippGetCount(y_dim) != 1) { serverRespondUnsupported(client, attr); valid = 0; } else if ((supported = ippFindAttribute(client->printer->pinfo.attrs, "media-size-supported", IPP_TAG_BEGIN_COLLECTION)) != NULL) { x_value = ippGetInteger(x_dim, 0); y_value = ippGetInteger(y_dim, 0); count = ippGetCount(supported); for (i = 0; i < count ; i ++) { size = ippGetCollection(supported, i); x_dim = ippFindAttribute(size, "x-dimension", IPP_TAG_ZERO); y_dim = ippFindAttribute(size, "y-dimension", IPP_TAG_ZERO); if (ippContainsInteger(x_dim, x_value) && ippContainsInteger(y_dim, y_value)) break; } if (i >= count) { serverRespondUnsupported(client, attr); valid = 0; } } } } } if ((attr = ippFindAttribute(client->request, "multiple-document-handling", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_KEYWORD || (strcmp(ippGetString(attr, 0, NULL), "separate-documents-uncollated-copies") && strcmp(ippGetString(attr, 0, NULL), "separate-documents-collated-copies"))) { serverRespondUnsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "orientation-requested", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_ENUM || ippGetInteger(attr, 0) < IPP_ORIENT_PORTRAIT || ippGetInteger(attr, 0) > IPP_ORIENT_REVERSE_PORTRAIT) { serverRespondUnsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "page-ranges", IPP_TAG_ZERO)) != NULL) { if (ippGetValueTag(attr) != IPP_TAG_RANGE) { serverRespondUnsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "print-quality", IPP_TAG_ZERO)) != NULL) { if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_ENUM || ippGetInteger(attr, 0) < IPP_QUALITY_DRAFT || ippGetInteger(attr, 0) > IPP_QUALITY_HIGH) { serverRespondUnsupported(client, attr); valid = 0; } } if ((attr = ippFindAttribute(client->request, "printer-resolution", IPP_TAG_ZERO)) != NULL) { supported = ippFindAttribute(client->printer->dev_attrs, "printer-resolution-supported", IPP_TAG_RESOLUTION); if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_RESOLUTION || !supported) { serverRespondUnsupported(client, attr); valid = 0; } else { int xdpi, /* Horizontal resolution for job template attribute */ ydpi, /* Vertical resolution for job template attribute */ sydpi; /* Vertical resolution for supported value */ ipp_res_t units, /* Units for job template attribute */ sunits; /* Units for supported value */ xdpi = ippGetResolution(attr, 0, &ydpi, &units); count = ippGetCount(supported); for (i = 0; i < count; i ++) { if (xdpi == ippGetResolution(supported, i, &sydpi, &sunits) && ydpi == sydpi && units == sunits) break; } if (i >= count) { serverRespondUnsupported(client, attr); valid = 0; } } } if ((attr = ippFindAttribute(client->request, "sides", IPP_TAG_ZERO)) != NULL) { const char *sides = ippGetString(attr, 0, NULL); /* "sides" value... */ if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_KEYWORD) { serverRespondUnsupported(client, attr); valid = 0; } else if ((supported = ippFindAttribute(client->printer->dev_attrs, "sides-supported", IPP_TAG_KEYWORD)) != NULL) { if (!ippContainsString(supported, sides)) { serverRespondUnsupported(client, attr); valid = 0; } } else if (strcmp(sides, "one-sided")) { serverRespondUnsupported(client, attr); valid = 0; } } return (valid); } ippsample/server/printer.png0000644000175000017500000001513013240604116015236 0ustar tilltillPNG  IHDR>a$iCCPICC Profile8UoT>oR? XGůUS[IJ*$:7鶪O{7@Hkk?<kktq݋m6nƶد-mR;`zv x#=\% oYRڱ#&?>ҹЪn_;j;$}*}+(}'}/LtY"$].9⦅%{_a݊]hk5'SN{<_ t jM{-4%TńtY۟R6#v\喊x:'HO3^&0::m,L%3:qVE t]~Iv6Wٯ) |ʸ2]G4(6w‹$"AEv m[D;Vh[}چN|3HS:KtxU'D;77;_"e?Yqxl+iTXtXML:com.adobe.xmp Michael Sweet Copyright 2010 Apple Inc. New Image タ IDATxw.+* "K( ĂGPboĚXB%?k˂5b,g2o̼7o{=ݙNy|isKI zaH,qԒifKjlMM¸51dI%qmZѴEӒ& 0]Uj`z0601* NkqhӜo*aJΟz~R TLvou`ONJUЧwo}-Z- G,zƅw[+mkKui/Xj>h'hڵkZ)5k9jzZ5I?w$Z4#Fie7|Ϳ뮻0a}M^iffϞ}wsM7Cvvaff֭Ϙ1Ì9tlw#0zdٜ{f졇jnSO=eN>dnw-+Vmxֻ{|AsqǙ;ݻ{y/bZӿ3hРt R_ʰIN:wyޓO>鉍մ;zof}̙tAYג?xoӦM>s~47dow òo{:u{'QFy7oκ&ۄ3x8{.̍l-[xX[ׯ_q6};xoVb[}7^~9OC% k۶w%x3gt\A/c=~t{ ,.R\zKƵ}W_}'=ϗ^+WH3ɗ ^]]BCCm{7x-s[6d:mbWd)QF믿>#_{OJ=nENrKl[E4TW˲6޶qeHaiauٞ_~?4}8p?~5Df\n:#7^xᅌtRkPIDx}棏>2Z{'=1tן7oc=6~"I[ 5r5k|mSN9|'yG?n|,n \̈h&uH9sWX}`zH$=^x'KhGB^/W_gu_GĿ.4$U%롏?-U@(AIK/UT  .ϗ]v] KAH!_4OgΉA@_~ٰaCD}՞4I{= s1F A#q׌XFL(D "t9F{#yM6mYux*.2eJK \ d|ŚhWF9.V4bq ޼D"N䋸ϬwYd'=268gغa>*'^x"@"^z+kƞS&V^%?pmqe4w\{'?S}kky}3nS75[BGm~]b*5n(H}4"?aܓTX6܄J{=I%`ݯ4$= U`ذa!b('FBn<#GeZjK}|(8Δܘ@98rp#G98rpਊ,CiӦO/6Ͱox8;u/ `KdؖV(0*@nt-lsȇq2CT}sw}זjZQ2\|Ŗ\ ʐ,81H z&3qt 5)a2 ܊`a,8aAЌ`}")NIS֮]kE UNGe3r1~'ߐcTGsTe]23Aȴj~AMe -a b19xf`!nQ'GEUV*Y Fa8'O;*!h` 0>%TJBA"ea:@pln}PSSrN ~w]3a8 x>G |7JA,~32[خ'x%k\wu6OEFEW1eba6_U Cl yx04|;~#0zyJE%1fyrYO^PN0 Iah`* ez-yVHHYfq9 $fv5<XTũyXo/(Kx O‹va+uEIby^"ЄO7 Frtާ@mS%@cz>iB&Jz<~]؉h#eTUz:0G,A[!l34*I`.G%Kx-| k !VBNp&F4:p~xSa&:_)ުoS\L m/di$ og%1T!LCGG!b/&HFBpBeK ,ng8+w,5e/YX~6LU@~H@9?]d<~jK5[@9 NEh"$u`GQLA74Bd~  Ea:tp(a,@T\i_0x K2dpWH^R#.f0({W^ ܳr˖5mivhUqW[6eKg 1w+#ϟW1z0ݺ/<4?_P[lڸDlϫK1z(P'z$dM'&nڸlٺ,1RVL:n{\/4j 5,iX1sj3`L]9Gd'~:*(H zv-7ȴS3kW0]:7J^5gxOORIz5:"/ں̟; q&5+Y3ׯ]D~UH~N BQP̲3y =Dc ]Fmm|zlPy и鄛QM vB05KR=8Q:n[>J :a + ?H\>JD Od0B=FVa<^O{}!J@:`4W^ .xB#Zia8.+/F@,IFDp'L#lD[#K >A)M#x e|;J<'!`^ @`B@!xup5PG {U"l*\1T@QǞBm'tV80@P+bqF`+T %euD DjC A7-YaxFV>wb9NT1))9P3= ѣG;T#id6u?k6, r9 :`icEk:jD7=ӌ?ޮ@ͯ+tְӃ=^%:VYA #XE\)vdR(7Y;0l1C{Сv]6Ҁ K%1FU-cE F&Z8Jf3z8GVne-&/Ȓm!g/+%zD2d=>LˇH?û\|n>`+ :(Ivtjӫu=et<yɃ1&(rJw ;q*yHygd"0CnРAhva0u #else # include #endif /* WIN32 */ /* * Local functions... */ static void process_attr_message(server_job_t *job, char *message); static void process_state_message(server_job_t *job, char *message); static double time_seconds(void); /* * 'serverTransformJob()' - Generate printer-ready document data for a Job. */ int /* O - 0 on success, non-zero on error */ serverTransformJob( server_client_t *client, /* I - Client connection (if any) */ server_job_t *job, /* I - Job to transform */ const char *command, /* I - Command to run */ const char *format, /* I - Destination MIME media type */ server_transform_t mode) /* I - Transform mode */ { int pid, /* Process ID */ status = 0; /* Exit status */ double start, /* Start time */ end; /* End time */ char *myargv[3], /* Command-line arguments */ *myenvp[200]; /* Environment variables */ int myenvc; /* Number of environment variables */ ipp_attribute_t *attr; /* Job attribute */ char val[1280], /* IPP_NAME=value */ *valptr; /* Pointer into string */ #ifndef WIN32 posix_spawn_file_actions_t actions; /* Spawn file actions */ int mystdout[2] = {-1, -1}, /* Pipe for stdout */ mystderr[2] = {-1, -1}; /* Pipe for stderr */ struct pollfd polldata[2]; /* Poll data */ int pollcount, /* Number of pipes to poll */ pollret; /* Return value from poll() */ char data[32768], /* Data from stdout */ line[2048], /* Line from stderr */ *ptr, /* Pointer into line */ *endptr; /* End of line */ ssize_t bytes; /* Bytes read */ #endif /* !WIN32 */ serverLogJob(SERVER_LOGLEVEL_DEBUG, job, "Running command \"%s %s\".", command, job->filename); start = time_seconds(); /* * Setup the command-line arguments... */ myargv[0] = (char *)command; myargv[1] = job->filename; myargv[2] = NULL; /* * Copy the current environment, then add environment variables for every * Job attribute and select Printer attributes... */ for (myenvc = 0; environ[myenvc] && myenvc < (int)(sizeof(myenvp) / sizeof(myenvp[0]) - 1); myenvc ++) myenvp[myenvc] = strdup(environ[myenvc]); if (myenvc > (int)(sizeof(myenvp) / sizeof(myenvp[0]) - 32)) { serverLogJob(SERVER_LOGLEVEL_ERROR, job, "Too many environment variables to transform job."); goto transform_failure; } if (asprintf(myenvp + myenvc, "CONTENT_TYPE=%s", job->format) > 0) myenvc ++; if (job->printer->pinfo.device_uri && asprintf(myenvp + myenvc, "DEVICE_URI=%s", job->printer->pinfo.device_uri) > 0) myenvc ++; if ((attr = ippFindAttribute(job->attrs, "document-name", IPP_TAG_NAME)) != NULL && asprintf(myenvp + myenvc, "DOCUMENT_NAME=%s", ippGetString(attr, 0, NULL)) > 0) myenvc ++; /* TODO: OUTPUT_ORDER, defaults */ if (format && asprintf(myenvp + myenvc, "OUTPUT_TYPE=%s", format) > 0) myenvc ++; if ((attr = ippFindAttribute(job->printer->pinfo.attrs, "materials-col-default", IPP_TAG_BEGIN_COLLECTION)) != NULL) { ippAttributeString(attr, val, sizeof(val)); if (asprintf(myenvp + myenvc, "PRINTER_MATERIALS_COL_DEFAULT=%s", val)) myenvc ++; } if ((attr = ippFindAttribute(job->printer->pinfo.attrs, "media-default", IPP_TAG_KEYWORD)) != NULL && asprintf(myenvp + myenvc, "PRINTER_MEDIA_DEFAULT=%s", ippGetString(attr, 0, NULL))) myenvc ++; if ((attr = ippFindAttribute(job->printer->pinfo.attrs, "platform-temperature-default", IPP_TAG_INTEGER)) != NULL && asprintf(myenvp + myenvc, "PRINTER_PLATFORM_TEMPERATURE_DEFAULT=%d", ippGetInteger(attr, 0))) myenvc ++; if ((attr = ippFindAttribute(job->printer->pinfo.attrs, "print-base-default", IPP_TAG_KEYWORD)) != NULL && asprintf(myenvp + myenvc, "PRINTER_PRINT_BASE_DEFAULT=%s", ippGetString(attr, 0, NULL))) myenvc ++; if ((attr = ippFindAttribute(job->printer->pinfo.attrs, "print-quality-default", IPP_TAG_ENUM)) != NULL && asprintf(myenvp + myenvc, "PRINTER_PRINT_QUALITY_DEFAULT=%d", ippGetInteger(attr, 0))) myenvc ++; if ((attr = ippFindAttribute(job->printer->pinfo.attrs, "print-supports-default", IPP_TAG_INTEGER)) != NULL && asprintf(myenvp + myenvc, "PRINTER_PPRINT_SUPPORTS_DEFAULT=%s", ippGetString(attr, 0, NULL))) myenvc ++; if ((attr = ippFindAttribute(job->printer->pinfo.attrs, "sides-default", IPP_TAG_KEYWORD)) != NULL && asprintf(myenvp + myenvc, "PRINTER_SIDES_DEFAULT=%s", ippGetString(attr, 0, NULL))) myenvc ++; if ((attr = ippFindAttribute(job->printer->pinfo.attrs, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION)) != NULL && ippAttributeString(attr, val, sizeof(val)) > 0 && asprintf(myenvp + myenvc, "PWG_RASTER_DOCUMENT_RESOLUTION_SUPPORTED=%s", val) > 0) myenvc ++; if ((attr = ippFindAttribute(job->printer->pinfo.attrs, "pwg-raster-document-sheet-back", IPP_TAG_KEYWORD)) != NULL && asprintf(myenvp + myenvc, "PWG_RASTER_DOCUMENT_SHEET_BACK=%s", ippGetString(attr, 0, NULL)) > 0) myenvc ++; if ((attr = ippFindAttribute(job->printer->pinfo.attrs, "pwg-raster-document-type-supported", IPP_TAG_RESOLUTION)) != NULL && ippAttributeString(attr, val, sizeof(val)) > 0 && asprintf(myenvp + myenvc, "PWG_RASTER_DOCUMENT_TYPE_SUPPORTED=%s", val) > 0) myenvc ++; if (LogLevel == SERVER_LOGLEVEL_INFO) myenvp[myenvc ++] = strdup("SERVER_LOGLEVEL=info"); else if (LogLevel == SERVER_LOGLEVEL_DEBUG) myenvp[myenvc ++] = strdup("SERVER_LOGLEVEL=debug"); else myenvp[myenvc ++] = strdup("SERVER_LOGLEVEL=error"); for (attr = ippFirstAttribute(job->attrs); attr && myenvc < (int)(sizeof(myenvp) / sizeof(myenvp[0]) - 1); attr = ippNextAttribute(job->attrs)) { /* * Convert "attribute-name" to "IPP_ATTRIBUTE_NAME=" and then add the * value(s) from the attribute. */ const char *name = ippGetName(attr); if (!name) continue; valptr = val; *valptr++ = 'I'; *valptr++ = 'P'; *valptr++ = 'P'; *valptr++ = '_'; while (*name && valptr < (val + sizeof(val) - 2)) { if (*name == '-') *valptr++ = '_'; else *valptr++ = (char)toupper(*name & 255); name ++; } *valptr++ = '='; ippAttributeString(attr, valptr, sizeof(val) - (size_t)(valptr - val)); myenvp[myenvc++] = strdup(val); } myenvp[myenvc] = NULL; /* * Now run the program... */ #ifdef WIN32 status = _spawnvpe(_P_WAIT, command, myargv, myenvp); #else if (mode == SERVER_TRANSFORM_TO_CLIENT) { if (pipe(mystdout)) { serverLogJob(SERVER_LOGLEVEL_ERROR, job, "Unable to create pipe for stdout: %s", strerror(errno)); goto transform_failure; } } else { mystdout[0] = -1; if (mode == SERVER_TRANSFORM_TO_FILE) { serverCreateJobFilename(job->printer, job, format, line, sizeof(line)); mystdout[1] = open(line, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0666); } else mystdout[1] = open("/dev/null", O_WRONLY); if (mystdout[1] < 0) { serverLogJob(SERVER_LOGLEVEL_ERROR, job, "Unable to open file for stdout: %s", strerror(errno)); goto transform_failure; } } if (pipe(mystderr)) { serverLogJob(SERVER_LOGLEVEL_ERROR, job, "Unable to create pipe for stderr: %s", strerror(errno)); goto transform_failure; } posix_spawn_file_actions_init(&actions); posix_spawn_file_actions_addopen(&actions, 0, "/dev/null", O_RDONLY, 0); if (mystdout[1] < 0) posix_spawn_file_actions_addopen(&actions, 1, "/dev/null", O_WRONLY, 0); else posix_spawn_file_actions_adddup2(&actions, mystdout[1], 1); if (mystderr[1] < 0) posix_spawn_file_actions_addopen(&actions, 2, "/dev/null", O_WRONLY, 0); else posix_spawn_file_actions_adddup2(&actions, mystderr[1], 2); if (posix_spawn(&pid, command, &actions, NULL, myargv, myenvp)) { serverLogJob(SERVER_LOGLEVEL_ERROR, job, "Unable to start job processing command: %s", strerror(errno)); posix_spawn_file_actions_destroy(&actions); goto transform_failure; } serverLogJob(SERVER_LOGLEVEL_DEBUG, job, "Started job processing command, pid=%d", pid); /* * Free memory used for command... */ posix_spawn_file_actions_destroy(&actions); while (myenvc > 0) free(myenvp[-- myenvc]); /* * Read from the stdout and stderr pipes until EOF... */ close(mystdout[1]); close(mystderr[1]); endptr = line; pollcount = 0; polldata[pollcount].fd = mystderr[0]; polldata[pollcount].events = POLLIN; pollcount ++; if (mystdout[0] >= 0) { polldata[pollcount].fd = mystdout[0]; polldata[pollcount].events = POLLIN; pollcount ++; } while ((pollret = poll(polldata, (nfds_t)pollcount, -1)) > 0) { serverLogJob(SERVER_LOGLEVEL_DEBUG, job, "poll() returned %d, polldata[0].revents=%d, polldata[1].revents=%d", pollret, polldata[0].revents, polldata[1].revents); if (polldata[0].revents & POLLIN) { if ((bytes = read(mystderr[0], endptr, sizeof(line) - (size_t)(endptr - line) - 1)) > 0) { endptr += bytes; *endptr = '\0'; while ((ptr = strchr(line, '\n')) != NULL) { *ptr++ = '\0'; if (!strncmp(line, "STATE:", 6)) { /* * Process printer-state-reasons keywords. */ process_state_message(job, line); } else if (!strncmp(line, "ATTR:", 5)) { /* * Process printer attribute update. */ process_attr_message(job, line); } else serverLogJob(SERVER_LOGLEVEL_DEBUG, job, "%s: %s", command, line); bytes = ptr - line; if (ptr < endptr) memmove(line, ptr, (size_t)(endptr - ptr)); endptr -= bytes; *endptr = '\0'; } } } else if (pollcount > 1 && polldata[1].revents & POLLIN) { if ((bytes = read(mystdout[0], data, sizeof(data))) > 0) httpWrite2(client->http, data, (size_t)bytes); } if (polldata[0].revents & POLLHUP) break; } if (mystdout[0] >= 0) { close(mystdout[0]); httpFlushWrite(client->http); httpWrite2(client->http, "", 0); } close(mystderr[0]); if (endptr > line) { /* * Write the final output that wasn't terminated by a newline... */ serverLogJob(SERVER_LOGLEVEL_DEBUG, job, "%s: %s", command, line); } /* * Wait for child to complete... */ # ifdef HAVE_WAITPID while (waitpid(pid, &status, 0) < 0); # else while (wait(&status) < 0); # endif /* HAVE_WAITPID */ #endif /* WIN32 */ end = time_seconds(); serverLogJob(SERVER_LOGLEVEL_DEBUG, job, "Total transform time is %.3f seconds.", end - start); return (status); /* * This is where we go for hard failures... */ transform_failure: if (mystdout[0] >= 0) close(mystdout[0]); if (mystdout[1] >= 0) close(mystdout[1]); if (mystderr[0] >= 0) close(mystderr[0]); if (mystderr[1] >= 0) close(mystderr[1]); while (myenvc > 0) free(myenvp[-- myenvc]); return (-1); } /* * 'process_attr_message()' - Process an ATTR: message from a command. */ static void process_attr_message( server_job_t *job, /* I - Job */ char *message) /* I - Message */ { (void)job; (void)message; } /* * 'process_state_message()' - Process a STATE: message from a command. */ static void process_state_message( server_job_t *job, /* I - Job */ char *message) /* I - Message */ { int i; /* Looping var */ server_preason_t state_reasons, /* printer-state-reasons values */ bit; /* Current reason bit */ char *ptr, /* Pointer into message */ *next; /* Next keyword in message */ int remove; /* Non-zero if we are removing keywords */ /* * Skip leading "STATE:" and any whitespace... */ for (message += 6; *message; message ++) if (*message != ' ' && *message != '\t') break; /* * Support the following forms of message: * * "keyword[,keyword,...]" to set the printer-state-reasons value(s). * * "-keyword[,keyword,...]" to remove keywords. * * "+keyword[,keyword,...]" to add keywords. * * Keywords may or may not have a suffix (-report, -warning, -error) per * RFC 2911. */ if (*message == '-') { remove = 1; state_reasons = job->printer->state_reasons; message ++; } else if (*message == '+') { remove = 0; state_reasons = job->printer->state_reasons; message ++; } else { remove = 0; state_reasons = SERVER_PREASON_NONE; } while (*message) { if ((next = strchr(message, ',')) != NULL) *next++ = '\0'; if ((ptr = strstr(message, "-error")) != NULL) *ptr = '\0'; else if ((ptr = strstr(message, "-report")) != NULL) *ptr = '\0'; else if ((ptr = strstr(message, "-warning")) != NULL) *ptr = '\0'; for (i = 0, bit = 1; i < (int)(sizeof(server_preasons) / sizeof(server_preasons[0])); i ++, bit *= 2) { if (!strcmp(message, server_preasons[i])) { if (remove) state_reasons &= ~bit; else state_reasons |= bit; } } if (next) message = next; else break; } job->printer->state_reasons = state_reasons; } /* * 'time_seconds()' - Return the current time in fractional seconds. */ static double /* O - Time in seconds */ time_seconds(void) { #ifdef WIN32 struct _timeb curtime; /* Current time */ _ftime(&curtime); return ((double)curtime.time + 0.001 * curtime.millitm); #else struct timeval curtime; /* Current time */ gettimeofday(&curtime, NULL); return ((double)curtime.tv_sec + 0.000001 * curtime.tv_usec); #endif /* WIN32 */ } ippsample/server/Dependencies0000644000175000017500000000451213240604116015360 0ustar tilltillclient.o: client.c ippserver.h ../config.h ../cups/cups.h ../cups/file.h \ ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ ../cups/language.h ../cups/pwg.h ../cups/string-private.h \ ../cups/thread-private.h printer-png.h printer3d-png.h conf.o: conf.c ippserver.h ../config.h ../cups/cups.h ../cups/file.h \ ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ ../cups/language.h ../cups/pwg.h ../cups/string-private.h \ ../cups/thread-private.h ../cups/dir.h device.o: device.c ippserver.h ../config.h ../cups/cups.h ../cups/file.h \ ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ ../cups/language.h ../cups/pwg.h ../cups/string-private.h \ ../cups/thread-private.h ipp.o: ipp.c ippserver.h ../config.h ../cups/cups.h ../cups/file.h \ ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ ../cups/language.h ../cups/pwg.h ../cups/string-private.h \ ../cups/thread-private.h job.o: job.c ippserver.h ../config.h ../cups/cups.h ../cups/file.h \ ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ ../cups/language.h ../cups/pwg.h ../cups/string-private.h \ ../cups/thread-private.h log.o: log.c ippserver.h ../config.h ../cups/cups.h ../cups/file.h \ ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ ../cups/language.h ../cups/pwg.h ../cups/string-private.h \ ../cups/thread-private.h main.o: main.c ippserver.h ../config.h ../cups/cups.h ../cups/file.h \ ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ ../cups/language.h ../cups/pwg.h ../cups/string-private.h \ ../cups/thread-private.h printer.o: printer.c ippserver.h ../config.h ../cups/cups.h \ ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h \ ../cups/array.h ../cups/language.h ../cups/pwg.h \ ../cups/string-private.h ../cups/thread-private.h subscription.o: subscription.c ippserver.h ../config.h ../cups/cups.h \ ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h \ ../cups/array.h ../cups/language.h ../cups/pwg.h \ ../cups/string-private.h ../cups/thread-private.h transform.o: transform.c ippserver.h ../config.h ../cups/cups.h \ ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h \ ../cups/array.h ../cups/language.h ../cups/pwg.h \ ../cups/string-private.h ../cups/thread-private.h ippsample/server/ippserver.h0000644000175000017500000005173013240604116015243 0ustar tilltill/* * Header file for sample IPP server implementation. * * Copyright © 2014-2018 by the IEEE-ISTO Printer Working Group * Copyright © 2010-2018 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ /* * Disable private and deprecated stuff so we can verify that the public API * is sufficient to implement a server. */ #define _IPP_PRIVATE_STRUCTURES 0 /* Disable private IPP stuff */ #define _CUPS_NO_DEPRECATED 1 /* Disable deprecated stuff */ /* * Include necessary headers... */ #include /* CUPS configuration header */ #include /* Public API */ #include /* CUPS string functions */ #include /* For multithreading functions */ #include #include #include #include #include #include #include #ifdef WIN32 # include # include # include # define WEXITSTATUS(s) (s) # include typedef ULONG nfds_t; # define poll WSAPoll #else extern char **environ; # include # include # include #endif /* WIN32 */ #ifdef HAVE_DNSSD # include #elif defined(HAVE_AVAHI) # include # include # include # include #endif /* HAVE_DNSSD */ #ifdef HAVE_SYS_MOUNT_H # include #endif /* HAVE_SYS_MOUNT_H */ #ifdef HAVE_SYS_STATFS_H # include #endif /* HAVE_SYS_STATFS_H */ #ifdef HAVE_SYS_STATVFS_H # include #endif /* HAVE_SYS_STATVFS_H */ #ifdef HAVE_SYS_VFS_H # include #endif /* HAVE_SYS_VFS_H */ #ifdef HAVE_PTHREAD_H # define _cupsCondDeinit(c) pthread_cond_destroy(c) # define _cupsMutexDeinit(m) pthread_mutex_destroy(m) # define _cupsRWDeinit(rw) pthread_rwlock_destroy(rw) #else # define _cupsCondDeinit(c) # define _cupsMutexDeinit(m) # define _cupsRWDeinit(rw) #endif /* HAVE_PTHREAD_H */ #ifdef _MAIN_C_ # define VAR # define VALUE(...) =__VA_ARGS__ #else # define VAR extern # define VALUE(...) #endif /* _MAIN_C_ */ /* * Constants... */ /* Maximum lease duration value from RFC 3995 - 2^26-1 seconds or ~2 years */ # define SERVER_NOTIFY_LEASE_DURATION_MAX 67108863 /* But a value of 0 means "never expires"... */ # define SERVER_NOTIFY_LEASE_DURATION_FOREVER 0 /* Default duration is 1 day */ # define SERVER_NOTIFY_LEASE_DURATION_DEFAULT 86400 /* URL schemes and DNS-SD types for IPP and web resources... */ # define SERVER_IPP_SCHEME "ipp" # define SERVER_IPP_TYPE "_ipp._tcp" # define SERVER_IPPS_SCHEME "ipps" # define SERVER_IPPS_TYPE "_ipps._tcp" # define SERVER_IPPS_3D_TYPE "_ipps-3d._tcp" # define SERVER_WEB_TYPE "_http._tcp" # define SERVER_HTTP_SCHEME "http" # define SERVER_HTTPS_SCHEME "https" /* * LogLevel constants... */ typedef enum server_loglevel_e { SERVER_LOGLEVEL_ERROR, SERVER_LOGLEVEL_INFO, SERVER_LOGLEVEL_DEBUG } server_loglevel_t; /* * Event mask enumeration... */ enum server_event_e /* notify-events bit values */ { SERVER_EVENT_DOCUMENT_COMPLETED = 0x00000001, SERVER_EVENT_DOCUMENT_CONFIG_CHANGED = 0x00000002, SERVER_EVENT_DOCUMENT_CREATED = 0x00000004, SERVER_EVENT_DOCUMENT_FETCHABLE = 0x00000008, SERVER_EVENT_DOCUMENT_STATE_CHANGED = 0x00000010, SERVER_EVENT_DOCUMENT_STOPPED = 0x00000020, SERVER_EVENT_JOB_COMPLETED = 0x00000040, SERVER_EVENT_JOB_CONFIG_CHANGED = 0x00000080, SERVER_EVENT_JOB_CREATED = 0x00000100, SERVER_EVENT_JOB_FETCHABLE = 0x00000200, SERVER_EVENT_JOB_PROGRESS = 0x00000400, SERVER_EVENT_JOB_STATE_CHANGED = 0x00000800, SERVER_EVENT_JOB_STOPPED = 0x00001000, SERVER_EVENT_PRINTER_CONFIG_CHANGED = 0x00002000, SERVER_EVENT_PRINTER_FINISHINGS_CHANGED = 0x00004000, SERVER_EVENT_PRINTER_MEDIA_CHANGED = 0x00008000, SERVER_EVENT_PRINTER_QUEUE_ORDER_CHANGED = 0x00010000, SERVER_EVENT_PRINTER_RESTARTED = 0x00020000, SERVER_EVENT_PRINTER_SHUTDOWN = 0x00040000, SERVER_EVENT_PRINTER_STATE_CHANGED = 0x00080000, SERVER_EVENT_PRINTER_STOPPED = 0x00100000, /* "Wildcard" values... */ SERVER_EVENT_NONE = 0x00000000, /* Nothing */ SERVER_EVENT_DOCUMENT_ALL = 0x0000003f, SERVER_EVENT_DOCUMENT_STATE_ALL = 0x00000037, SERVER_EVENT_JOB_ALL = 0x00001fc0, SERVER_EVENT_JOB_STATE_ALL = 0x00001940, SERVER_EVENT_PRINTER_ALL = 0x001fe000, SERVER_EVENT_PRINTER_CONFIG_ALL = 0x0000e000, SERVER_EVENT_PRINTER_STATE_ALL = 0x001e0000, SERVER_EVENT_ALL = 0x001fffff /* Everything */ }; typedef unsigned int server_event_t; /* Bitfield for notify-events */ #define SERVER_EVENT_DEFAULT SERVER_EVENT_JOB_COMPLETED #define SERVER_EVENT_DEFAULT_STRING "job-completed" VAR const char * const server_events[21] VALUE({ /* Strings for bits */ /* "none" is implied for no bits set */ "document-completed", "document-config-changed", "document-created", "document-fetchable", "document-state-changed", "document-stopped", "job-completed", "job-config-changed", "job-created", "job-fetchable", "job-progress", "job-state-changed", "job-stopped", "printer-config-changed", "printer-finishings-changed", "printer-media-changed", "printer-queue-order-changed", "printer-restarted", "printer-shutdown", "printer-state-changed", "printer-stopped" }); enum server_jreason_e /* job-state-reasons bit values */ { SERVER_JREASON_NONE = 0x00000000, /* none */ SERVER_JREASON_ABORTED_BY_SYSTEM = 0x00000001, SERVER_JREASON_COMPRESSION_ERROR = 0x00000002, SERVER_JREASON_DOCUMENT_ACCESS_ERROR = 0x00000004, SERVER_JREASON_DOCUMENT_FORMAT_ERROR = 0x00000008, SERVER_JREASON_DOCUMENT_PASSWORD_ERROR = 0x00000010, SERVER_JREASON_DOCUMENT_PERMISSION_ERROR = 0x00000020, SERVER_JREASON_DOCUMENT_SECURITY_ERROR = 0x00000040, SERVER_JREASON_DOCUMENT_UNPRINTABLE_ERROR = 0x00000080, SERVER_JREASON_ERRORS_DETECTED = 0x00000100, SERVER_JREASON_JOB_CANCELED_AT_DEVICE = 0x00000200, SERVER_JREASON_JOB_CANCELED_BY_USER = 0x00000400, SERVER_JREASON_JOB_COMPLETED_SUCCESSFULLY = 0x00000800, SERVER_JREASON_JOB_COMPLETED_WITH_ERRORS = 0x00001000, SERVER_JREASON_JOB_COMPLETED_WITH_WARNINGS = 0x00002000, SERVER_JREASON_JOB_DATA_INSUFFICIENT = 0x00004000, SERVER_JREASON_JOB_FETCHABLE = 0x00008000, SERVER_JREASON_JOB_INCOMING = 0x00010000, SERVER_JREASON_JOB_PASSWORD_WAIT = 0x00020000, SERVER_JREASON_JOB_PRINTING = 0x00040000, SERVER_JREASON_JOB_QUEUED = 0x00080000, SERVER_JREASON_JOB_SPOOLING = 0x00100000, SERVER_JREASON_JOB_STOPPED = 0x00200000, SERVER_JREASON_JOB_TRANSFORMING = 0x00400000, SERVER_JREASON_PRINTER_STOPPED = 0x00800000, SERVER_JREASON_PRINTER_STOPPED_PARTLY = 0x01000000, SERVER_JREASON_PROCESSING_TO_STOP_POINT = 0x02000000, SERVER_JREASON_QUEUED_IN_DEVICE = 0x04000000, SERVER_JREASON_WARNINGS_DETECTED = 0x08000000 }; typedef unsigned int server_jreason_t; /* Bitfield for job-state-reasons */ VAR const char * const server_jreasons[28] VALUE({ /* Strings for bits */ /* "none" is implied for no bits set */ "aborted-by-system", "compression-error", "document-access-error", "document-format-error", "document-password-error", "document-permission-error", "document-security-error", "document-unprintable-error", "errors-detected", "job-canceled-at-device", "job-canceled-by-user", "job-completed-successfully", "job-completed-with-errors", "job-completed-with-warnings", "job-data-insufficient", "job-fetchable", "job-incoming", "job-password-wait", "job-printing", "job-queued", "job-spooling", "job-stopped", "job-transforming", "printer-stopped", "printer-stopped-partly", "processing-to-stop-point", "queued-in-device", "warnings-detected" }); enum server_preason_e /* printer-state-reasons bit values */ { SERVER_PREASON_NONE = 0x0000, /* none */ SERVER_PREASON_OTHER = 0x0001, /* other */ SERVER_PREASON_COVER_OPEN = 0x0002, /* cover-open */ SERVER_PREASON_INPUT_TRAY_MISSING = 0x0004, /* input-tray-missing */ SERVER_PREASON_MARKER_SUPPLY_EMPTY = 0x0008, /* marker-supply-empty */ SERVER_PREASON_MARKER_SUPPLY_LOW = 0x0010, /* marker-supply-low */ SERVER_PREASON_MARKER_WASTE_ALMOST_FULL = 0x0020, /* marker-waste-almost-full */ SERVER_PREASON_MARKER_WASTE_FULL = 0x0040, /* marker-waste-full */ SERVER_PREASON_MEDIA_EMPTY = 0x0080, /* media-empty */ SERVER_PREASON_MEDIA_JAM = 0x0100, /* media-jam */ SERVER_PREASON_MEDIA_LOW = 0x0200, /* media-low */ SERVER_PREASON_MEDIA_NEEDED = 0x0400, /* media-needed */ SERVER_PREASON_MOVING_TO_PAUSED = 0x0800, /* moving-to-paused */ SERVER_PREASON_PAUSED = 0x1000, /* paused */ SERVER_PREASON_SPOOL_AREA_FULL = 0x2000,/* spool-area-full */ SERVER_PREASON_TONER_EMPTY = 0x4000, /* toner-empty */ SERVER_PREASON_TONER_LOW = 0x8000 /* toner-low */ }; typedef unsigned int server_preason_t; /* Bitfield for printer-state-reasons */ VAR const char * const server_preasons[16] VALUE({ /* Strings for bits */ /* "none" is implied for no bits set */ "other", "cover-open", "input-tray-missing", "marker-supply-empty", "marker-supply-low", "marker-waste-almost-full", "marker-waste-full", "media-empty", "media-jam", "media-low", "media-needed", "moving-to-paused", "paused", "spool-area-full", "toner-empty", "toner-low" }); typedef enum server_transform_e /* Transform modes for server */ { SERVER_TRANSFORM_COMMAND, /* Run command for print job processing */ SERVER_TRANSFORM_TO_CLIENT, /* Send output to client */ SERVER_TRANSFORM_TO_FILE /* Send output to file */ } server_transform_t; /* * Base types... */ # ifdef HAVE_DNSSD typedef DNSServiceRef server_srv_t; /* Service reference */ typedef TXTRecordRef server_txt_t; /* TXT record */ typedef DNSRecordRef server_loc_t; /* LOC record */ # elif defined(HAVE_AVAHI) typedef AvahiEntryGroup *server_srv_t; /* Service reference */ typedef AvahiStringList *server_txt_t; /* TXT record */ typedef void *server_loc_t; /* LOC record */ # else typedef void *server_srv_t; /* Service reference */ typedef void *server_txt_t; /* TXT record */ typedef void *server_loc_t; /* LOC record */ # endif /* HAVE_DNSSD */ /* * Structures... */ typedef struct server_filter_s /**** Attribute filter ****/ { cups_array_t *ra; /* Requested attributes */ ipp_tag_t group_tag; /* Group to copy */ } server_filter_t; typedef struct server_job_s server_job_t; typedef struct server_device_s /**** Output Device data ****/ { _cups_rwlock_t rwlock; /* Printer lock */ char *name, /* printer-name (mapped to output-device) */ *uuid; /* output-device-uuid */ ipp_t *attrs; /* All printer attributes */ ipp_pstate_t state; /* printer-state value */ server_preason_t reasons; /* printer-state-reasons values */ } server_device_t; typedef struct server_lang_s /**** Localization data ****/ { char *lang, /* Language code */ *filename; /* Strings file */ } server_lang_t; typedef struct server_pinfo_s /**** Printer information ****/ { char *icon, /* Icon file */ *location, /* Location of printer */ *make, /* Manufacturer */ *model, /* Model */ *document_formats, /* Supported input formats */ *command, /* Command to run with job files */ *device_uri, /* Device URI */ *output_format, /* Output format */ *auth_type, /* Type of authentication */ *proxy_user; /* Proxy user, if any */ int duplex, /* Duplex mode */ pin, /* PIN printing mode? */ ppm, /* Pages per minute for mono */ ppm_color; /* Pages per minute for color */ ipp_t *attrs; /* Printer attributes */ cups_array_t *strings; /* Strings files */ } server_pinfo_t; typedef struct server_printer_s /**** Printer data ****/ { _cups_rwlock_t rwlock; /* Printer lock */ server_srv_t ipp_ref, /* Bonjour IPP service */ #ifdef HAVE_SSL ipps_ref, /* Bonjour IPPS service */ #endif /* HAVE_SSL */ http_ref, /* Bonjour HTTP(S) service */ printer_ref; /* Bonjour LPD service */ server_loc_t geo_ref; /* Bonjour geo-location */ char *default_uri, /* Default/first URI */ *dnssd_name, /* printer-dnssd-name */ *name, /* printer-name */ *resource; /* Resource path */ size_t resourcelen; /* Length of resource path */ server_pinfo_t pinfo; /* Printer information */ cups_array_t *devices; /* Associated devices */ ipp_t *dev_attrs; /* Current device attributes */ time_t start_time; /* Startup time */ time_t config_time; /* printer-config-change-time */ ipp_pstate_t state, /* printer-state value */ dev_state; /* Current device printer-state value */ server_preason_t state_reasons, /* printer-state-reasons values */ dev_reasons; /* Current device printer-state-reasons values */ time_t state_time; /* printer-state-change-time */ cups_array_t *jobs, /* Jobs */ *active_jobs, /* Active jobs */ *completed_jobs;/* Completed jobs */ server_job_t *processing_job;/* Current processing job */ int next_job_id; /* Next job-id value */ cups_array_t *subscriptions; /* Subscriptions */ int next_sub_id; /* Next notify-subscription-id value */ } server_printer_t; struct server_job_s /**** Job data ****/ { int id; /* job-id */ _cups_rwlock_t rwlock; /* Job lock */ const char *name, /* job-name */ *username, /* job-originating-user-name */ *format; /* document-format */ int priority; /* job-priority */ char *dev_uuid; /* output-device-uuid-assigned */ ipp_jstate_t state, /* job-state value */ dev_state; /* output-device-job-state value */ server_jreason_t state_reasons, /* job-state-reasons values */ dev_state_reasons; /* output-device-job-state-reasons values */ char *dev_state_message; /* output-device-job-state-message value */ time_t created, /* time-at-creation value */ processing, /* time-at-processing value */ completed; /* time-at-completed value */ int impressions, /* job-impressions value */ impcompleted; /* job-impressions-completed value */ ipp_t *attrs; /* Attributes */ int cancel; /* Non-zero when job canceled */ char *filename; /* Print file name */ int fd; /* Print file descriptor */ server_printer_t *printer; /* Printer */ }; typedef struct server_subscription_s /**** Subscription data ****/ { int id; /* notify-subscription-id */ const char *uuid; /* notify-subscription-uuid */ _cups_rwlock_t rwlock; /* Subscription lock */ server_event_t mask; /* Event mask */ server_printer_t *printer; /* Printer */ server_job_t *job; /* Job, if any */ ipp_t *attrs; /* Attributes */ const char *username; /* notify-subscriber-user-name */ int lease; /* notify-lease-duration */ int interval; /* notify-time-interval */ time_t expire; /* Lease expiration time */ int first_sequence, /* First notify-sequence-number in cache */ last_sequence; /* Last notify-sequence-number used */ cups_array_t *events; /* Events (ipp_t *'s) */ int pending_delete; /* Non-zero when the subscription is about to be deleted/canceled */ } server_subscription_t; typedef struct server_client_s /**** Client data ****/ { int number; /* Client number */ http_t *http; /* HTTP connection */ ipp_t *request, /* IPP request */ *response; /* IPP response */ time_t start; /* Request start time */ http_state_t operation; /* Request operation */ ipp_op_t operation_id; /* IPP operation-id */ char uri[1024], /* Request URI */ *options; /* URI options */ http_addr_t addr; /* Client address */ char hostname[256], /* Client hostname */ username[32]; /* Client authenticated username */ server_printer_t *printer; /* Printer */ server_job_t *job; /* Current job, if any */ int fetch_compression, /* Compress file? */ fetch_file; /* File to fetch */ } server_client_t; typedef struct server_listener_s /**** Listener data ****/ { int fd; /* Listener socket */ char host[256]; /* Hostname, if any */ int port; /* Port number */ } server_listener_t; /* * Globals... */ VAR char *ConfigDirectory VALUE(NULL); VAR char *DataDirectory VALUE(NULL); VAR int DefaultPort VALUE(0); VAR char *DefaultPrinter VALUE(NULL); VAR http_encryption_t Encryption VALUE(HTTP_ENCRYPTION_IF_REQUESTED); VAR int KeepFiles VALUE(0); #ifdef HAVE_SSL VAR char *KeychainPath VALUE(NULL); #endif /* HAVE_SSL */ VAR cups_array_t *Listeners VALUE(NULL); VAR char *LogFile VALUE(NULL); VAR server_loglevel_t LogLevel VALUE(SERVER_LOGLEVEL_ERROR); VAR int MaxJobs VALUE(100), MaxCompletedJobs VALUE(100); VAR cups_array_t *Printers VALUE(NULL); VAR char *ServerName VALUE(NULL); VAR char *SpoolDirectory VALUE(NULL); #ifdef HAVE_DNSSD VAR DNSServiceRef DNSSDMaster VALUE(NULL); #elif defined(HAVE_AVAHI) VAR AvahiThreadedPoll *DNSSDMaster VALUE(NULL); VAR AvahiClient *DNSSDClient VALUE(NULL); #endif /* HAVE_DNSSD */ VAR char *DNSSDSubType VALUE(NULL); //VAR _cups_mutex_t SubscriptionMutex VALUE(_CUPS_MUTEX_INITIALIZER); VAR _cups_cond_t SubscriptionCondition VALUE(_CUPS_COND_INITIALIZER); /* * Functions... */ extern void serverAddEvent(server_printer_t *printer, server_job_t *job, server_event_t event, const char *message, ...) __attribute__((__format__(__printf__, 4, 5))); extern void serverCheckJobs(server_printer_t *printer); extern void serverCleanAllJobs(void); extern void serverCleanJobs(server_printer_t *printer); extern void serverCopyAttributes(ipp_t *to, ipp_t *from, cups_array_t *ra, ipp_tag_t group_tag, int quickcopy); extern void serverCopyJobStateReasons(ipp_t *ipp, ipp_tag_t group_tag, server_job_t *job); extern void serverCopyPrinterStateReasons(ipp_t *ipp, ipp_tag_t group_tag, server_printer_t *printer); extern server_client_t *serverCreateClient(int sock); extern server_device_t *serverCreateDevice(server_client_t *client); extern server_job_t *serverCreateJob(server_client_t *client); extern void serverCreateJobFilename(server_printer_t *printer, server_job_t *job, const char *format, char *fname, size_t fnamesize); extern int serverCreateListeners(const char *host, int port); extern server_printer_t *serverCreatePrinter(const char *resource, const char *name, server_pinfo_t *pinfo); extern server_subscription_t *serverCreateSubcription(server_printer_t *printer, server_job_t *job, int interval, int lease, const char *username, ipp_attribute_t *notify_events, ipp_attribute_t *notify_attributes, ipp_attribute_t *notify_user_data); extern void serverDeleteClient(server_client_t *client); extern void serverDeleteDevice(server_device_t *device); extern void serverDeleteJob(server_job_t *job); extern void serverDeletePrinter(server_printer_t *printer); extern void serverDeleteSubscription(server_subscription_t *sub); extern void serverDNSSDInit(void); extern int serverFinalizeConfiguration(void); extern server_device_t *serverFindDevice(server_client_t *client); extern server_job_t *serverFindJob(server_client_t *client, int job_id); extern server_printer_t *serverFindPrinter(const char *resource); extern server_subscription_t *serverFindSubscription(server_client_t *client, int sub_id); extern server_jreason_t serverGetJobStateReasonsBits(ipp_attribute_t *attr); extern server_event_t serverGetNotifyEventsBits(ipp_attribute_t *attr); extern const char *serverGetNotifySubscribedEvent(server_event_t event); extern server_preason_t serverGetPrinterStateReasonsBits(ipp_attribute_t *attr); extern int serverLoadAttributes(const char *filename, server_pinfo_t *pinfo); extern int serverLoadConfiguration(const char *directory); extern void serverLog(server_loglevel_t level, const char *format, ...) __attribute__((__format__(__printf__, 2, 3))); extern void serverLogAttributes(server_client_t *client, const char *title, ipp_t *ipp, int type); extern void serverLogClient(server_loglevel_t level, server_client_t *client, const char *format, ...) __attribute__((__format__(__printf__, 3, 4))); extern void serverLogJob(server_loglevel_t level, server_job_t *job, const char *format, ...) __attribute__((__format__(__printf__, 3, 4))); extern void serverLogPrinter(server_loglevel_t level, server_printer_t *printer, const char *format, ...) __attribute__((__format__(__printf__, 3, 4))); extern void *serverProcessClient(server_client_t *client); extern int serverProcessHTTP(server_client_t *client); extern int serverProcessIPP(server_client_t *client); extern void *serverProcessJob(server_job_t *job); extern int serverRespondHTTP(server_client_t *client, http_status_t code, const char *content_coding, const char *type, size_t length); extern void serverRespondIPP(server_client_t *client, ipp_status_t status, const char *message, ...) __attribute__ ((__format__ (__printf__, 3, 4))); extern void serverRespondUnsupported(server_client_t *client, ipp_attribute_t *attr); extern void serverRun(void); extern char *serverTimeString(time_t tv, char *buffer, size_t bufsize); extern int serverTransformJob(server_client_t *client, server_job_t *job, const char *command, const char *format, server_transform_t mode); extern void serverUpdateDeviceAttributesNoLock(server_printer_t *printer); extern void serverUpdateDeviceStateNoLock(server_printer_t *printer); ippsample/server/device.c0000644000175000017500000000721413240604116014454 0ustar tilltill/* * Device support for sample IPP server implementation. * * Copyright © 2014-2018 by the IEEE-ISTO Printer Working Group * Copyright © 2010-2018 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ #include "ippserver.h" /* * 'serverCreateDevice()' - Create an output device tracking object. */ server_device_t * /* O - Device */ serverCreateDevice( server_client_t *client) /* I - Client */ { server_device_t *device; /* Device */ ipp_attribute_t *uuid; /* output-device-uuid */ if ((uuid = ippFindAttribute(client->request, "output-device-uuid", IPP_TAG_URI)) == NULL) return (NULL); if ((device = calloc(1, sizeof(server_device_t))) == NULL) return (NULL); _cupsRWInit(&device->rwlock); device->uuid = strdup(ippGetString(uuid, 0, NULL)); device->state = IPP_PSTATE_STOPPED; _cupsRWLockWrite(&client->printer->rwlock); cupsArrayAdd(client->printer->devices, device); _cupsRWUnlock(&client->printer->rwlock); return (device); } /* * 'serverDeleteDevice()' - Remove a device from a printer. * * Note: Caller is responsible for locking the printer object. */ void serverDeleteDevice(server_device_t *device) /* I - Device */ { /* * Free memory used for the device... */ _cupsRWDeinit(&device->rwlock); if (device->name) free(device->name); free(device->uuid); ippDelete(device->attrs); free(device); } /* * 'serverFindDevice()' - Find a device. */ server_device_t * /* I - Device */ serverFindDevice(server_client_t *client) /* I - Client */ { ipp_attribute_t *uuid; /* output-device-uuid */ server_device_t key, /* Search key */ *device; /* Matching device */ if ((uuid = ippFindAttribute(client->request, "output-device-uuid", IPP_TAG_URI)) == NULL) return (NULL); key.uuid = (char *)ippGetString(uuid, 0, NULL); _cupsRWLockRead(&client->printer->rwlock); device = (server_device_t *)cupsArrayFind(client->printer->devices, &key); _cupsRWUnlock(&client->printer->rwlock); return (device); } /* * 'serverUpdateDeviceAttributesNoLock()' - Update the composite device attributes. * * Note: Caller MUST lock the printer object for writing before using. */ void serverUpdateDeviceAttributesNoLock( server_printer_t *printer) /* I - Printer */ { server_device_t *device; /* Current device */ ipp_t *dev_attrs; /* Device attributes */ /* TODO: Support multiple output devices, icons, etc... */ device = (server_device_t *)cupsArrayFirst(printer->devices); dev_attrs = ippNew(); if (device) serverCopyAttributes(dev_attrs, device->attrs, NULL, IPP_TAG_PRINTER, 0); ippDelete(printer->dev_attrs); printer->dev_attrs = dev_attrs; printer->config_time = time(NULL); } /* * 'serverUpdateDeviceStatusNoLock()' - Update the composite device state. * * Note: Caller MUST lock the printer object for writing before using. */ void serverUpdateDeviceStateNoLock( server_printer_t *printer) /* I - Printer */ { server_device_t *device; /* Current device */ ipp_attribute_t *attr; /* Current attribute */ /* TODO: Support multiple output devices, icons, etc... */ device = (server_device_t *)cupsArrayFirst(printer->devices); if ((attr = ippFindAttribute(device->attrs, "printer-state", IPP_TAG_ENUM)) != NULL) printer->dev_state = (ipp_pstate_t)ippGetInteger(attr, 0); else printer->dev_state = IPP_PSTATE_STOPPED; if ((attr = ippFindAttribute(device->attrs, "printer-state-reasons", IPP_TAG_KEYWORD)) != NULL) printer->dev_reasons = serverGetPrinterStateReasonsBits(attr); else printer->dev_reasons = SERVER_PREASON_PAUSED; printer->state_time = time(NULL); } ippsample/server/printer3d.opacity0000644000175000017500000007406113240604116016361 0ustar tilltillbplist00 X$versionX$objectsY$archiverT$topcopqrswxJ !"23456789AEIMANPV]gmsvw}    /25:?DEFGHIJOWPW`rs !"#$%&'()1:IJ]`ejopqrstuvz!&+./012348LOTY^abcdefglq~!"#$%&'+?BGLQRSTUVW\et   .ADINSTUVWXY]qty~ ,/49>?@ABCDIR_efy|#()*+,-.3CG[^chmnopqrsxyz       # ( - . / 0 1 2 3 8 C O [ g s ~        ! ' - 0 1 7 : ? M S T U V i l q v { | } ~      - . / R b c d e f g h l p t z9 { | } ~ :         ! " # $ ( : ; < = > ? @ A K L M T UD V ` a b c k l m n o { |< } U$null0  !"#$%&'()*+,-./0123456789:;<=>??ABC::DEFGHI:JKLMNO?QRSTJAVWXYZC\]^C?C<N>@UNSRGB\NSColorSpace_NSCustomColorSpaceJ0 0 0 0.513B"CDTNSID2yzFG\NSColorSpaceH~\NSColorSpaceyzJKWNSColorL~WNSColor#V yzQRXPCFilterSTU~XPCFilterZPCDrawableXPCObjectyzWX]PCFilterLayerYZ[\~]PCFilterLayerWPCLayerZPCDrawableXPCObject"::N_`AbdN=: >@"?jC9;de"npnq< "`J:WPrinterde"xzn{? "J9e"vAkʁ!Lwȁف "NAWANWAWNUdimLKTrectSisIWfilPropSshXTantiSflVVcornRXVcornRYUstrosSshYUalPixSangSflHBE F #@jY9 de"nCD ]cornerRadiusX]cornerRadiusY_{{32, 20}, {80, 64}}"N>:=?:>AVrelLP2SblHWgradAngUradGCTfilTWrelRadCVfilPosSaEqStypXrelLinP1VfilColVrelLP1UfilImVothColXrelLinP2SgEqUfilGrSrEqXgradStopUpgNumSbEqR#@VNOXWQGPHASUTIV ;"<@WNSWhiteB13:;">@L0.6 0.6 0.63e"JLM"?W=ValtColSlocScolFGKyz^PCGradientStop~^PCGradientStopZPCDrawableXPCObject"?FHKyz^NSMutableArray~WNSArrayV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}Q0QtW100 - tS100yz _PCDrawVectorProperties~_PCDrawVectorPropertiesZPCDrawableXPCObjecte"ZM"N: :"?$%:N(J:],>.TcapSSposUinvisSwidUdashSd`aiWcb\AeU[T]Vf;"0<@B03:;"3>@L0.4 0.4 0.43e"678^_M"?W]Z[K"?%Z\KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"KvLMgh #@ yzQR_PCStrokeVectorPropertiesSTUV~_PCStrokeVectorProperties_PCDrawVectorPropertiesZPCDrawableXPCObjectyzXY\PCRectVectorZ[\]^_~\PCRectVector\PCPathVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObjectab"cdeNgAiWANlmnWAWNVfConPtVconPtsVlConPtl m |9 _{{93.5, 12.5}, {19, 71}}"tNv>w:yz=|?~:>AvrsX{uGtnkwyxoz :;">@L0.6 0.6 0.63e"pqM"?iW=mGK"?i~mnKV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}Q0QtW100 - tS100e"}M"N: :y?:NJ:]>i{~ky[xz:;">@L0.4 0.4 0.43e"M"?W]}[K"?}~KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"vLMgh "NANN:YhasConPt1VcPLinkUisCloRptTnextYhasConPt2VconPt1VconPt2 k"Ne>NANTprev k"N>NAN k"N> NAmN k"N>AAN k yz]PCCustomPoint~]PCCustomPointZPCDrawableXPCObjectX{16, 75}X{16, 75}X{16, 75}X{35, 84}X{35, 84}X{35, 84}X{35, 23}X{35, 23}X{35, 23}\{15.5, 14.5}\{15.5, 14.5}\{15.5, 14.5}e"*emMyz23^PCCustomVector456789~^PCCustomVector\PCPathVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObjectab"c;<N>A@WANlDEWAWN 9 _{{15, 74}, {98, 9}}"KNM>N:yQ=S?UW:Z>[AX{Gyx :;"^>@L0.6 0.6 0.63e"abcM"?@W=GK"?@UKV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}W100 - te"wxM"{N}:~ :y?:NJ:]>[i{y[x:;">@L0.4 0.4 0.43e"M"?xW][K"?xKV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"vLMgh "NANN: ƀǀȀ"N<>NANŀÀ "N>NAN€ "N>NADN "N>AAN \{18.5, 37.5}\{18.5, 37.5}\{18.5, 37.5}\{88.5, 37.5}\{88.5, 37.5}\{88.5, 37.5}]{108.5, 46.5}]{108.5, 46.5}]{108.5, 46.5}\{38.5, 46.5}\{38.5, 46.5}\{38.5, 46.5}e"<DM"N>AWANWAWNVcomTypTvecs  ؀9 _{{0, 0}, {0, 0}}"N > : =?::AҀӀXWՀGԀ̀ʀ׀UT΀V :;">@L0.6 0.6 0.63e"πЀM"??W=GK"??)рK:;",>@L0.6 0.6 0.63V{0, 0}V{0, 0}_{0, -0.26230134357521712}_{0, -0.40646547864169474}_{0, -0.26230134357521712}_{0, -0.40646547864169474}e"56ـM"9N;:< :??AB:NEJ:]I:K߀iWڀU[TۀV:;"M>@L0.4 0.4 0.43e"PQR܀݀M"??W][K"??\ހK:;"_>@L0.4 0.4 0.43V{0, 0}V{0, 0}_{0, -0.26230134357521712}_{0, -0.40646547864169474}_{0, -0.26230134357521712}_{0, -0.40646547864169474}e"hvLMgh e"mvno "rsNAvWANzWAWN j de"n ]cornerRadiusX]cornerRadiusY_4{{16.006443793714311, 12.003826699052428}, {80, 64}}"N>:y=?n:>NX{Gyx:;">@L0.6 0.6 0.63e"M"?vW=GK"?vKV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}W100 - te"M"N: :y?n:AJ:]>ʁi{ y[x:;">@L0.4 0.4 0.43e"рM"?W][K"?KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"vLMgh "NAWANWWWAWN  j de"nCD _4{{24.006443793714311, 28.003826699052425}, {64, 40}}"N>:=?o : >N XWG UT V:;">@L0.6 0.6 0.63e"  M"?W=GK"? KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"()M",N.:/ :2?45o:A8J:]<>>iW U[TV:;"@>@L0.4 0.4 0.43e"CDEM"?)W][K"?)5KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"XvLMgh yz]^_PCPathGroupVector_`abcd~_PCPathGroupVector\PCPathVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObjectab"cgNiAkWANlopWAWNˁ:K " >-9 "uNw>x:{=}?:>A+'(XW*G)#!,UT$V :;">@L0.6 0.6 0.63e"%&M"?kW="GK"?k"#KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e".M"N: :?:NJ:]>734iW65/!8U[T0V9:;">@L0.4 0.4 0.43e"12M"?W].[K"?./KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"vLMgh "NANN: !H;IJ"Ng>NANG:EF !<"N>NAND;BC !="N>NAoNA<?@ !>"N>AAN ! =\{93.5, 74.5}\{93.5, 74.5}\{93.5, 74.5}]{112.5, 83.5}]{112.5, 83.5}]{112.5, 83.5}]{112.5, 22.5}]{112.5, 22.5}]{112.5, 22.5}\{93.5, 12.5}\{93.5, 12.5}\{93.5, 12.5}e"go:;<=>Mab"c!N#A%WANl)*WAWNˁev M iX9 "/N1>2:5=7?9;:>>AVRSXWUGTNLWUTOV :;"B>@L0.6 0.6 0.63e"EFGPQM"?%W=MGK"?%9MNKV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"Z[YM"^N`:a :d?fg:NjJ:]n>pb^_iWa`ZLcU[T[Vd:;"r>@L0.4 0.4 0.43e"uvw\]M"?[W]Y[K"?[gYZKV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"vLMgh "NANN: Lsftu"N!>NANrepq Lg"N>NANofmn Lh"N>NA)Nlgjk Li"N>AAN L hX{15, 74}X{15, 74}X{15, 74}X{93, 74}X{93, 74}X{93, 74}Y{113, 83}Y{113, 83}Y{113, 83}X{35, 83}X{35, 83}X{35, 83}e"!)efghiM"WNAWANWWAWNWaEndAngWaStaAngx y 9 _{{56.5, 42.5}, {7, 3}}"N>:y=?:>A~X{Gzwyx{ :;">@L0.6 0.6 0.63e"|}M"?W=yGK"?yzKV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}W100 - te"M"N: :y?!":N%J:])>+i{wy[x:;"->@L0.4 0.4 0.43e"012M"?W][K"?"KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"EvLMgh yzJK_PCEllipseVectorLMNOPQ~_PCEllipseVector\PCPathVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObject"STNAWWANWW[WAWN  j9 de"`bnCD _{{56, 44}, {7, 9}}"gNi>j:m=o?qs:v>AXWGUTV :;"z>@L0.6 0.6 0.63e"}~M"?WW=GK"?WqKV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"M"N: :?:AJ:]>iW U[TV:;">@L0.4 0.4 0.43e"M"?W][K"?KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"vLMgh "WNAWANWWAWN  9 _{{56.5, 52.5}, {7, 3}}"N>:=?:>AXWGUTV :;">@L0.6 0.6 0.63e"M"?W=GK"?KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"M"N: : ?  :NJ:]>€iWĀÁƀU[TV:;">@L0.4 0.4 0.43e"M"?W][K"? KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"/vLMgh 45"N8A?WAN=>?WAWNSpt1Spt2 ׁ؁ɀ9 e"DEʀM"HNJ:K :N?PQ:NTJ:]X>ZρЀiWҀсˁԀU[T̀V:;"\>@L0.4 0.4 0.43e"_`á΀M"?EW]ʀ[K"?EQʁˀKV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"tvLMgh \{63.5, 53.5}\{63.5, 43.5}yz{|\PCLineVector}~~\PCLineVector\PCPathVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObject45"NA?WAN>WAWN ؁ڀ9 e"ۀM"N: :y?:NJ:]>i{܁y[x݁:;">@L0.4 0.4 0.43e"ށ߀M"?W]ۀ[K"?ہ܀KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}W100 - te"vLMgh _{57, 54.66015625}\{56.5, 43.5}ab"cNAWANlWAWNˁ  9 "N>:=?:>NXWGUTV:;">@L0.6 0.6 0.63e"M"?W=GK"?KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"  M" N :  : ?  :N J:] > iWU[TV:;" >@L0.4 0.4 0.43e"  !M"? W][K"?  KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e" 4vLMgh "NAN = >N @ A: "N E H> INA MN "N Q > T> UNA YN "N ] M `> aNA eN "N i Y l> mNAN   "N>NA xN z { e    \{40.5, 83.5}\{40.5, 83.5}\{40.5, 83.5}\{40.5, 88.5}\{40.5, 88.5}\{40.5, 88.5}\{43.5, 91.5}\{43.5, 91.5}\{43.5, 91.5}\{51.5, 91.5}\{51.5, 91.5}\{51.5, 91.5}\{56.5, 88.5}\{56.5, 88.5}\{56.5, 88.5}\{59.5, 77.5}\{59.5, 77.5}\{59.5, 77.5}e"  > M Y eӁM" NA WANWW WAWN  j+9 de" nCD _{{56.5, 74.5}, {6, 4}}" N : : ?  : >A)%&XW( '!*UT"V :;" >@F0 0 03:;" >@L0.6 0.6 0.63e"  Ɂ#$M"? W=GK"? !KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e"  ݁,M" N :  : ? :N J:] > 512iW43-6U[T.V7:;" >@L0.4 0.4 0.43e"  /0M"? W],[K"? ,-KV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e" vLMgh yz  ]PCFolderLayer    ~]PCFolderLayerWPCLayerZPCDrawableXPCObject"::N  A  NS=: >@"? $C9;de" ( *n +< " J:ZBackgroundde" 2 4n 5? "J9e" ;v < =A_ " @ ANA DWAN G G IWAWNBE F #@(jR9 de" N Pn OC QD ]cornerRadiusX]cornerRadiusY_{{0, 0}, {128, 128}}" WN Y: Z:y ]= _? a < c: f> gAOKLX{NGMGAPyxHQ :;" j>@L0.6 0.6 0.63e" m n oIJM"? DW=FGK"? D aFGKV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}W100 - te"  SM" N :  :y ? <:A J:] > g \XYi{[ZTA ]y[xUQ^:;" >@L0.4 0.4 0.43e"  VWM"? W]S[K"? STKV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}e" vLMgh   "   NNAWAN WA WNTstrYXstrTBndsTstrXVattStr` oa9 n_{{0, 64}, {128, 56}} " XNSString\NSAttributesbmcYippserverde" ٣ ԁdef] ؀[gilWNSColor_NSParagraphStyleVNSFont " ? ZNSTabStops[NSAlignmenthyz _NSMutableParagraphStyle ~_NSParagraphStyle " VNSSizeXNSfFlagsVNSName#@8jk_.LucidaGrandeUIyz VNSFont ~VNSFontyz ~yz _NSAttributedString ~_NSAttributedString;" <@D1 03yz \PCTextVector   ~\PCTextVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObjecte" v9 yz WPCFrame ~WPCFrame_PCMetadataObjectZPCDrawableXPCObjecte" v s     "       NN? " #?: %?ANN +CYauSizCropVnewFacUapIn1TpathTapIDUcropRUapIn2UisRelUisColTcropVvarValut v_{{0.5, 0}, {0, 0}}]printer3d.png 0 1 2 3 4 5 6" 7 8 9 : ; < = > ? @AS C D E F? H I JA L M  O PYUcodeSUprColVprShTiSfraVcodePlVcodeFrUcodeFTsnShVexPropTpropUgenCHUgrTypVanLooCVprLinCUcodeL w sde" S Zn T U V W X Yxyz{|} [ \= ^ _ `~G V{JFIF}U{GIF}_"kCGImageDestinationBackgroundColorU{PNG}V{TIFF}_*kCGImageDestinationLossyCompressionQualityde" i jn de" m nn de" q rn de" u wn v x [Compression#?Zpublic.png]public.folderde"  n :;" >@L0.5 0 0 0.53SiosUcocoaUtouchVMyViewVUIViewyz _PCBitmapProperties ~_PCBitmapPropertiesXPCObjectyz YPCFactory ~YPCFactoryZPCDrawableXPCObjecte" ꠀMYselectionZ{128, 128};" <@E0.753_CICheckerboardGenerator 0 1 2 3 4 5 6" 7 8 9 : ; < = > ? @AS C D E F? A L M PY  de" n T U V W X Yxyz{|} = G de" n de" n de" n de" n v x #?_com.likethought.opacity.opacityde" n :;" >@L0.5 0 0 0.53de" n 0/ 0 0065666 _framePickerVisibleZhideRulers[windowFrame_layerViewDimension]hideVariablesZexpansionsYprintInfo]toolbarHidden_editFrameMetadata_{{62, 0}, {1195, 778}}#@cde" n /5 "   \NSAttributesde"  n   /    /  55 _NSHorizontallyCentered]NSRightMargin\NSLeftMargin_NSHorizonalPagination_NSVerticalPagination_NSVerticallyCentered[NSTopMargin^NSBottomMargin"B"Byz % &[NSPrintInfo '~[NSPrintInfode" ) 1n * + , - . / 0§ 2 3  5 6 * 8Áʁs΁Ӂ׀ _"com.likethought.opacity.preview.ui_(com.likethought.opacity.preview.elementsWfactory_#com.likethought.opacity.preview.web_&com.likethought.opacity.preview.cursorTtype_&com.likethought.opacity.preview.iphonede" B Fn C / Eāţ= IGƀ Ucolor[resolutionse" N O P RǁȀɀM#?#?de" W [n X Y Zˁ́ͣ000666 VstatusWtoolbarTdockde" d gn e fρТ h iсҀ WaddressUimage_#http://likethought.com/opacity/web/_,http://likethought.com/opacity/web/image.pngde" p un q / s CԁՁĤM wM=hրhG XhotspotXXhotspotYde" ~ n  C /؁āفځہ܁݁ = ހG߁ށ UrectXUrectHUrectWUrectYTleftStop#@4#@F#@iyz WPCImage ~WPCImage_PCMetadataObjectZPCDrawableXPCObject_NSKeyedArchiver Troot"+5:? "',38?FLSX^dkry   "$')25>@CFGJLORTVWZcegiktvy{}      ' 0 8 = E N j s  % ' 0 2 4 E G I K \ ^ ` b k n p r 0 4 : B H L T X ] b c d f h i k n o x z    ! " $ - ; F T \ g p x     ! 2 7 < > @ B D [ h u w y { }  0;=?AJOQS\in{ (YZ\^_acefh}   !$'*,sy~ $    "$&(*,.02467DLOQ^kmv{}  &-5<CJQX_ackoxJOSY]cefhjlnprtvxy{} &-6;=?AJSny(1x!#$&(*,.02468:<>@BCP]_hmoqsjlmoqsuwy{} "+0246cmtz}#$&(*,./0245fgikmoqrsuwx $-6CP]fqsuwy{}8:<=?@BCDFHJLMNd.0246KMOQSZahov}    "$&(*,9FHQVXZ\qsuwy   BCEGIKMNOQST      , 9 F S a o } !!!!!!!!!!! !"!$!%!&!9!!!!!!!!!!!!!!!!!!!!!!!!!!!"""" " " """$"&"("5"B"D"K"R"n"""""""#E#G#H#J#L#N#P#R#T#V#X#Z#[#]#_#a#c#e#g#i#v######################$$5$Q$m$v${$}$$$$$$$$$$$$$$$$$$$$$$%%%%%%$%[%%%%%%%%%%%%%%%%%%%%%%&& & &&&%&'&)&+&-&B&D&F&H&J&Q&X&_&f&m&t&|&&&&&''''' ' ''''''''''!'#'%'('5'B'D'M'R'T'V'X'm'o'q's'u''''''''''''''''(((((("(#($(&()(+(,(-(:(=(?(B(D(F(}((((((((((((())))) ) ))%)')0)5)8);)=)R)T)W)Y)[)p)r)u)x)z))))))))))*(*+*,*/*2*4*6*9*;*>*A*D*E*H*J*L*N*Q*S*V*c*p*r*{***********************+++ + +/+C+P+d+m+x++++++++++++++++,F,I,J,M,P,R,T,W,Y,\,^,a,d,g,i,k,n,p,q,~,,,,,,,,,,,,,,,,,,,,,-- --------------------------------.... . .!.#.&.).+.2.9.@.G.N.U.^.c.e.g.i......................./%/&/)/+/./1/4/5/6/9/5@5555555555555556#6&6'6*6-6/616466696;6>6A6D6F6H6K6N6O6\6i6k6t6y6|666666666666666666666677t7w7x7{7~777777777777777777777777777788 8 8888 8'8.858<8E8J8L8N8P8Y8k8z888888999999999 9#9%9&9'9497999<9>9@9U9999999999999999999999:: ::::*:,:/:1:3:H:J:M:P:R:Y:`:g:n:u:|::::;;;;; ; ;;;;;;;; ;";$;&;);+;.;;;H;J;S;X;[;^;`;u;w;z;|;~;;;;;;;;;;;;;;;;<=@=C=F=H=O=V=]=d=k=r={=~======>>>>> > >>>>>>>>>!>$>1>>>@>I>N>Q>T>V>k>m>p>r>t>>>>>>>>>>>>>>>>??????"?#?%?&?'?*?-?0?2?3?4?=?@?C?E?????????????????????@@@ @@@@@-@/@2@4@6@K@M@P@S@U@\@c@j@q@x@@@@@@@@@@@@@AA AAA`AbAcAfAgAiAjAkAnAqAtAvAwAxAAAAAABBBBB B BBBBBBBB B"B%B(B+B8BEBGBPBUBXB[B]BrBtBwByB{BBBBBBBBBBBBBBBBBBCCHCJCMCNCQCRCUCVCWCYC\C_CaCbCcCCCCCCCCCCCCCCCCCCCCD D DDDD!D#D8D:D=D?DADVDXD[D^D`DgDnDuD|DDDDDDEEEEEEEEE!E$E'E*E+E.E0E2E4E7E9EJ@JCJFJHJOJVJ]JdJkJrJ{J~JJJJJJKKKKK K KKKKKKKKK!K$K1K>K@KIKNKQKTKVKkKmKpKrKtKKKKKKKKKKKKKKKKKKKLL LLLNLOLRLULVLYL[L^L_LaLvLxL{L~LLLLLLLLLLLLLLLLLLLLLLLLLLMBMEMHMIMJMMMNMOMXMZM]M`MaMbMoMrMuMxM{M}MMMNNNNNNN!N$N&N)N+N.N1N4N6N8N;N>N?NLNYN[NdNiNlNoNqNNNNNNNNNNNNNNNNNNNNNOdOgOhOkOnOpOrOuOwOzO}OOOOOOOOOOOOOOOOOOOOOOOOOPPP PPPP%P,P5P:P

P@PPPPPPPPPPPPPPPPPPPPPPPPQQQQQQ!Q(Q*Q-Q0Q3Q;QNQUQbQmQyQ{Q~QQQQQQQQQQQQRRRRR"R+R0R9RNRSRhRuRzR|RRRRRRRRRRRRRRS SS$S/S8SASDSGSISSSSSSSSSSSSSSSSSSSSSSSSSSST TZT`TfTmTqTxTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTUU U UUUUU&U)U,U.U1U4U7U9U@UFUkUqUxUUUUUUUUUUUUUUUUUUUUVVV!V.V/V0V2V?VLVNVRVXV^VeVlVuVVVVVVVVVVVVVVW WWWW9WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWX X XXXXXX!X.X/X0X2X?XBXEXHXKXMXVXxXXXXXXXXXXXXXXXXXXXXXXXXYYYY Y Y Y+Y7YLYZYeYoY}YYYYYYYYYYYYYYZZ Z ZZZZZZZ0Z2Z5Z8Z;Z>Z@ZCZFZHZaZoZ|ZZZZZZZZZ[[ [[)[,[/[2[5[8[;[>[M[P[S[V[Y[\[_[b[d[[[[\ \\9\F\M\P\S\V\]\_\b\e\g\m\y\\\\\\\\\\\\\\\\\\\\\\\\\]]] ] ]]]]C]r]]]]]]]]]]]]]]]]]]]]]]]]^^^^ ^ ^^^^^^ ^&^,^2^7^;^D^M^V^X^a^i^t^|^^^^^^ ^ippsample/server/printer.c0000644000175000017500000021704613240604116014706 0ustar tilltill/* * Printer object code for sample IPP server implementation. * * Copyright © 2014-2018 by the IEEE-ISTO Printer Working Group * Copyright © 2010-2018 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ #include "ippserver.h" /* * Local functions... */ static int compare_active_jobs(server_job_t *a, server_job_t *b); static int compare_completed_jobs(server_job_t *a, server_job_t *b); static int compare_devices(server_device_t *a, server_device_t *b); static int compare_jobs(server_job_t *a, server_job_t *b); static ipp_t *create_media_col(const char *media, const char *source, const char *type, int width, int length, int margins); static ipp_t *create_media_size(int width, int length); #ifdef HAVE_DNSSD static void DNSSD_API dnssd_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, server_printer_t *printer); #elif defined(HAVE_AVAHI) static void dnssd_callback(AvahiEntryGroup *p, AvahiEntryGroupState state, void *context); #endif /* HAVE_DNSSD */ #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) static void register_geo(server_printer_t *printer); #endif /* HAVE_DNSSD || HAVE_AVAHI */ static int register_printer(server_printer_t *printer, const char *adminurl, const char *regtype); /* * 'serverCopyPrinterStateReasons()' - Copy printer-state-reasons values. */ void serverCopyPrinterStateReasons( ipp_t *ipp, /* I - Attributes */ ipp_tag_t group_tag, /* I - Group */ server_printer_t *printer) /* I - Printer */ { server_preason_t creasons = printer->state_reasons | printer->dev_reasons; /* Combined reasons */ if (creasons == SERVER_PREASON_NONE) { ippAddString(ipp, group_tag, IPP_CONST_TAG(IPP_TAG_KEYWORD), "printer-state-reasons", NULL, "none"); } else { int i, /* Looping var */ num_reasons = 0;/* Number of reasons */ server_preason_t reason; /* Current reason */ const char *reasons[32]; /* Reason strings */ for (i = 0, reason = 1; i < (int)(sizeof(server_preasons) / sizeof(server_preasons[0])); i ++, reason <<= 1) { if (creasons & reason) reasons[num_reasons ++] = server_preasons[i]; } ippAddStrings(ipp, group_tag, IPP_CONST_TAG(IPP_TAG_KEYWORD), "printer-state-reasons", num_reasons, NULL, reasons); } } /* * 'serverCreatePrinter()' - Create, register, and listen for connections to a * printer object. */ server_printer_t * /* O - Printer */ serverCreatePrinter( const char *resource, /* I - Resource path for URIs */ const char *name, /* I - printer-name */ server_pinfo_t *pinfo) /* I - Printer information */ { int i; /* Looping var */ server_printer_t *printer; /* Printer */ cups_array_t *existing; /* Existing attributes cache */ char title[256]; /* Title for attributes */ server_listener_t *lis; /* Current listener */ cups_array_t *uris; /* Array of URIs */ int num_uris; /* Number of URIs */ int is_print3d; /* 3D printer? */ char uri[1024], /* Printer URI */ *uriptr, /* Current URI */ **uriptrs, /* All URIs */ icons[1024], /* printer-icons URI */ adminurl[1024], /* printer-more-info URI */ supplyurl[1024],/* printer-supply-info-uri URI */ device_id[1024],/* printer-device-id */ make_model[128],/* printer-make-and-model */ uuid[128], /* printer-uuid */ spooldir[1024]; /* Per-printer spool directory */ int num_formats = 0;/* Number of document-format-supported values */ char *defformat = NULL, /* document-format-default value */ *formats[100], /* document-format-supported values */ *ptr; /* Pointer into string */ const char *prefix; /* Prefix string */ ipp_attribute_t *format_sup = NULL, /* document-format-supported */ *xri_sup, /* printer-xri-supported */ *media_col_database, /* media-col-database value */ *media_size_supported; /* media-size-supported value */ ipp_t *media_col, /* media-col-default value */ *xri_col; /* printer-xri-supported value */ int k_supported; /* Maximum file size supported */ #ifdef HAVE_STATVFS struct statvfs spoolinfo; /* FS info for spool directory */ double spoolsize; /* FS size */ #elif defined(HAVE_STATFS) struct statfs spoolinfo; /* FS info for spool directory */ double spoolsize; /* FS size */ #endif /* HAVE_STATVFS */ ipp_attribute_t *attr; /* Attribute */ const char *webscheme; /* HTTP/HTTPS */ static const int orients[4] = /* orientation-requested-supported values */ { IPP_ORIENT_PORTRAIT, IPP_ORIENT_LANDSCAPE, IPP_ORIENT_REVERSE_LANDSCAPE, IPP_ORIENT_REVERSE_PORTRAIT }; static const char * const versions[] =/* ipp-versions-supported values */ { "1.0", "1.1", "2.0" }; static const char * const features[] =/* ipp-features-supported values */ { "document-object", "ipp-everywhere", "infrastructure-printer", "page-overrides" }; static const char * const features3d[] =/* ipp-features-supported values */ { "ipp-3d" }; static const int ops[] = /* operations-supported values */ { IPP_OP_PRINT_JOB, IPP_OP_PRINT_URI, IPP_OP_VALIDATE_JOB, IPP_OP_CREATE_JOB, IPP_OP_SEND_DOCUMENT, IPP_OP_SEND_URI, IPP_OP_CANCEL_JOB, IPP_OP_GET_JOB_ATTRIBUTES, IPP_OP_GET_JOBS, IPP_OP_GET_PRINTER_ATTRIBUTES, IPP_OP_GET_PRINTER_SUPPORTED_VALUES, IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS, IPP_OP_CREATE_JOB_SUBSCRIPTIONS, IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES, IPP_OP_GET_SUBSCRIPTIONS, IPP_OP_RENEW_SUBSCRIPTION, IPP_OP_CANCEL_SUBSCRIPTION, IPP_OP_GET_NOTIFICATIONS, IPP_OP_GET_DOCUMENT_ATTRIBUTES, IPP_OP_GET_DOCUMENTS, IPP_OP_CANCEL_MY_JOBS, IPP_OP_CLOSE_JOB, IPP_OP_IDENTIFY_PRINTER, IPP_OP_VALIDATE_DOCUMENT, IPP_OP_ACKNOWLEDGE_DOCUMENT, IPP_OP_ACKNOWLEDGE_IDENTIFY_PRINTER, IPP_OP_ACKNOWLEDGE_JOB, IPP_OP_FETCH_DOCUMENT, IPP_OP_FETCH_JOB, IPP_OP_GET_OUTPUT_DEVICE_ATTRIBUTES, IPP_OP_UPDATE_ACTIVE_JOBS, IPP_OP_UPDATE_DOCUMENT_STATUS, IPP_OP_UPDATE_JOB_STATUS, IPP_OP_UPDATE_OUTPUT_DEVICE_ATTRIBUTES, IPP_OP_DEREGISTER_OUTPUT_DEVICE }; static const int ops3d[] = /* operations-supported values */ { IPP_OP_VALIDATE_JOB, IPP_OP_CREATE_JOB, IPP_OP_SEND_DOCUMENT, IPP_OP_SEND_URI, IPP_OP_CANCEL_JOB, IPP_OP_GET_JOB_ATTRIBUTES, IPP_OP_GET_JOBS, IPP_OP_GET_PRINTER_ATTRIBUTES, IPP_OP_GET_PRINTER_SUPPORTED_VALUES, IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS, IPP_OP_CREATE_JOB_SUBSCRIPTIONS, IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES, IPP_OP_GET_SUBSCRIPTIONS, IPP_OP_RENEW_SUBSCRIPTION, IPP_OP_CANCEL_SUBSCRIPTION, IPP_OP_GET_NOTIFICATIONS, IPP_OP_GET_DOCUMENT_ATTRIBUTES, IPP_OP_GET_DOCUMENTS, IPP_OP_CANCEL_MY_JOBS, IPP_OP_CLOSE_JOB, IPP_OP_IDENTIFY_PRINTER, IPP_OP_VALIDATE_DOCUMENT, IPP_OP_ACKNOWLEDGE_DOCUMENT, IPP_OP_ACKNOWLEDGE_IDENTIFY_PRINTER, IPP_OP_ACKNOWLEDGE_JOB, IPP_OP_FETCH_DOCUMENT, IPP_OP_FETCH_JOB, IPP_OP_GET_OUTPUT_DEVICE_ATTRIBUTES, IPP_OP_UPDATE_ACTIVE_JOBS, IPP_OP_UPDATE_DOCUMENT_STATUS, IPP_OP_UPDATE_JOB_STATUS, IPP_OP_UPDATE_OUTPUT_DEVICE_ATTRIBUTES, IPP_OP_DEREGISTER_OUTPUT_DEVICE }; static const char * const charsets[] =/* charset-supported values */ { "us-ascii", "utf-8" }; static const char * const compressions[] =/* compression-supported values */ { #ifdef HAVE_LIBZ "deflate", "gzip", #endif /* HAVE_LIBZ */ "none" }; static const char * const identify_actions[] = { "display", "sound" }; static const char * const job_creation[] = { /* job-creation-attributes-supported values */ "copies", "ipp-attribute-fidelity", "job-account-id", "job-accounting-user-id", "job-name", "job-password", "job-priority", "media", "media-col", "multiple-document-handling", "orientation-requested", "print-quality", "sides" }; static const char * const job_creation3d[] = { /* job-creation-attributes-supported values */ "ipp-attribute-fidelity", "job-name", "job-priority", "materials-col", "platform-temperatures", "print-accuracy", "print-base", "print-quality", "print-supports" }; static const int media_col_sizes[][2] = { /* Default media-col sizes */ { 21590, 27940 }, /* Letter */ { 21590, 35560 }, /* Legal */ { 21000, 29700 } /* A4 */ }; static const char * const media_col_supported[] = { /* media-col-supported values */ "media-bottom-margin", "media-left-margin", "media-right-margin", "media-size", "media-size-name", "media-source", "media-top-margin", "media-type" }; static const char * const media_supported[] = { /* Default media-supported values */ "na_letter_8.5x11in", /* Letter */ "na_legal_8.5x14in", /* Legal */ "iso_a4_210x297mm" /* A4 */ }; static const int media_xxx_margin_supported[] = { /* Default media-xxx-margin-supported values */ 635 }; static const char * const multiple_document_handling[] = { /* multiple-document-handling-supported values */ "separate-documents-uncollated-copies", "separate-documents-collated-copies" }; static const char * const notify_attributes[] = { /* notify-attributes-supported */ "printer-state-change-time", "notify-lease-expiration-time", "notify-subscriber-user-name" }; static const char * const overrides[] = { /* overrides-supported */ "document-number", "pages" }; static const char * const print_color_mode_supported[] = { /* print-color-mode-supported values */ "auto", "color", "monochrome" }; static const int print_quality_supported[] = { /* print-quality-supported values */ IPP_QUALITY_DRAFT, IPP_QUALITY_NORMAL, IPP_QUALITY_HIGH }; static const char * const printer_supply[] = { /* printer-supply values */ "index=1;class=receptacleThatIsFilled;type=wasteToner;unit=percent;" "maxcapacity=100;level=67;colorantname=unknown;", "index=2;class=supplyThatIsConsumed;type=toner;unit=percent;" "maxcapacity=100;level=100;colorantname=black;", "index=3;class=supplyThatIsConsumed;type=toner;unit=percent;" "maxcapacity=100;level=25;colorantname=cyan;", "index=4;class=supplyThatIsConsumed;type=toner;unit=percent;" "maxcapacity=100;level=50;colorantname=magenta;", "index=5;class=supplyThatIsConsumed;type=toner;unit=percent;" "maxcapacity=100;level=75;colorantname=yellow;" }; static const char * const printer_supply_desc[] = { /* printer-supply-description values */ "Toner Waste", "Black Toner", "Cyan Toner", "Magenta Toner", "Yellow Toner" }; static const int pwg_raster_document_resolution_supported[] = { 150, 300 }; static const char * const pwg_raster_document_type_supported[] = { "black_1", "cmyk_8", "sgray_8", "srgb_8", "srgb_16" }; static const char * const reference_uri_schemes_supported[] = { /* reference-uri-schemes-supported */ "file", "ftp", "http" #ifdef HAVE_SSL , "https" #endif /* HAVE_SSL */ }; static const char * const sides_supported[] = { /* sides-supported values */ "one-sided", "two-sided-long-edge", "two-sided-short-edge" }; static const char * const urf_supported[] = { /* urf-supported values */ "CP1", "IS1-5-7", "MT1-2-3-4-5-6-8-9-10-11-12-13", "RS300", "SRGB24", "V1.4", "W8", "DM1" }; static const char * const which_jobs[] = { /* which-jobs-supported values */ "completed", "not-completed", "aborted", "all", "canceled", "pending", "pending-held", "processing", "processing-stopped" }; serverLog(SERVER_LOGLEVEL_DEBUG, "serverCreatePrinter(resource=\"%s\", name=\"%s\", pinfo=%p)", resource, name, (void *)pinfo); is_print3d = !strncmp(resource, "/ipp/print3d/", 13); /* * Allocate memory for the printer... */ if ((printer = calloc(1, sizeof(server_printer_t))) == NULL) { perror("ippserver: Unable to allocate memory for printer"); return (NULL); } printer->resource = strdup(resource); printer->resourcelen = strlen(resource); printer->name = strdup(name); printer->dnssd_name = strdup(name); printer->start_time = time(NULL); printer->config_time = printer->start_time; printer->state = IPP_PSTATE_IDLE; printer->state_reasons = SERVER_PREASON_NONE; printer->state_time = printer->start_time; printer->jobs = cupsArrayNew3((cups_array_func_t)compare_jobs, NULL, NULL, 0, NULL, (cups_afree_func_t)serverDeleteJob); printer->active_jobs = cupsArrayNew((cups_array_func_t)compare_active_jobs, NULL); printer->completed_jobs = cupsArrayNew((cups_array_func_t)compare_completed_jobs, NULL); printer->next_job_id = 1; printer->pinfo = *pinfo; uris = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); for (lis = cupsArrayFirst(Listeners); lis; lis = cupsArrayNext(Listeners)) { httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), SERVER_IPP_SCHEME, NULL, lis->host, lis->port, resource); if (!cupsArrayFind(uris, uri)) cupsArrayAdd(uris, uri); } num_uris = cupsArrayCount(uris); uriptrs = calloc((size_t)num_uris, sizeof(char *)); for (i = 0, uriptr = cupsArrayFirst(uris); uriptr; i ++, uriptr = cupsArrayNext(uris)) uriptrs[i] = uriptr; printer->devices = cupsArrayNew((cups_array_func_t)compare_devices, NULL); if (printer->pinfo.ppm == 0) { printer->pinfo.ppm = ippGetInteger(ippFindAttribute(printer->pinfo.attrs, "pages-per-minute", IPP_TAG_INTEGER), 0); serverLog(SERVER_LOGLEVEL_DEBUG, "Using ppm=%d", printer->pinfo.ppm); } if (printer->pinfo.ppm_color == 0) { printer->pinfo.ppm_color = ippGetInteger(ippFindAttribute(printer->pinfo.attrs, "pages-per-minute-color", IPP_TAG_INTEGER), 0); serverLog(SERVER_LOGLEVEL_DEBUG, "Using ppm_color=%d", printer->pinfo.ppm_color); } _cupsRWInit(&(printer->rwlock)); /* * Prepare values for the printer attributes... */ lis = cupsArrayFirst(Listeners); #ifdef HAVE_SSL if (Encryption != HTTP_ENCRYPTION_NEVER) { httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), SERVER_IPPS_SCHEME, NULL, lis->host, lis->port, resource); webscheme = SERVER_HTTPS_SCHEME; } else #endif /* HAVE_SSL */ { httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), SERVER_IPP_SCHEME, NULL, lis->host, lis->port, resource); webscheme = SERVER_HTTP_SCHEME; } printer->default_uri = strdup(uri); httpAssembleURIf(HTTP_URI_CODING_ALL, icons, sizeof(icons), webscheme, NULL, lis->host, lis->port, "%s/icon.png", resource); httpAssembleURI(HTTP_URI_CODING_ALL, adminurl, sizeof(adminurl), webscheme, NULL, lis->host, lis->port, resource); httpAssembleURIf(HTTP_URI_CODING_ALL, supplyurl, sizeof(supplyurl), webscheme, NULL, lis->host, lis->port, "%s/supplies", resource); serverLogPrinter(SERVER_LOGLEVEL_INFO, printer, "printer-uri=\"%s\"", (char *)cupsArrayFirst(uris)); serverLogPrinter(SERVER_LOGLEVEL_DEBUG, printer, "printer-more-info=\"%s\"", adminurl); serverLogPrinter(SERVER_LOGLEVEL_DEBUG, printer, "printer-supply-info-uri=\"%s\"", supplyurl); if (printer->pinfo.document_formats) { num_formats = 1; formats[0] = strdup(printer->pinfo.document_formats); defformat = formats[0]; for (ptr = strchr(formats[0], ','); ptr; ptr = strchr(ptr, ',')) { *ptr++ = '\0'; formats[num_formats++] = ptr; if (!strcasecmp(ptr, "application/octet-stream")) defformat = ptr; } } /* * Create the printer's spool directory... */ snprintf(spooldir, sizeof(spooldir), "%s/%s", SpoolDirectory, printer->name); if (mkdir(spooldir, 0755) && errno != EEXIST) serverLog(SERVER_LOGLEVEL_ERROR, "Unable to create spool directory \"%s\": %s", spooldir, strerror(errno)); /* * Get the maximum spool size based on the size of the filesystem used for * the spool directory. If the host OS doesn't support the statfs call * or the filesystem is larger than 2TiB, always report INT_MAX. */ #ifdef HAVE_STATVFS if (statvfs(spooldir, &spoolinfo)) k_supported = INT_MAX; else if ((spoolsize = (double)spoolinfo.f_frsize * spoolinfo.f_blocks / 1024) > INT_MAX) k_supported = INT_MAX; else k_supported = (int)spoolsize; #elif defined(HAVE_STATFS) if (statfs(spooldir, &spoolinfo)) k_supported = INT_MAX; else if ((spoolsize = (double)spoolinfo.f_bsize * spoolinfo.f_blocks / 1024) > INT_MAX) k_supported = INT_MAX; else k_supported = (int)spoolsize; #else k_supported = INT_MAX; #endif /* HAVE_STATVFS */ /* * Create the printer attributes. This list of attributes is sorted to improve * performance when the client provides a requested-attributes attribute... */ if (!printer->pinfo.attrs) printer->pinfo.attrs = ippNew(); existing = cupsArrayNew((cups_array_func_t)strcmp, NULL); for (attr = ippFirstAttribute(printer->pinfo.attrs); attr; attr = ippNextAttribute(printer->pinfo.attrs)) { const char *attrname = ippGetName(attr);/* Attribute name */ if (attrname) cupsArrayAdd(existing, (void *)attrname); } /* charset-configured */ ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_CHARSET), "charset-configured", NULL, "utf-8"); /* charset-supported */ ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_CHARSET), "charset-supported", sizeof(charsets) / sizeof(charsets[0]), NULL, charsets); /* color-supported */ if (!is_print3d) { if (!cupsArrayFind(existing, (void *)"color-supported")) ippAddBoolean(printer->pinfo.attrs, IPP_TAG_PRINTER, "color-supported", printer->pinfo.ppm_color > 0); } /* compression-supported */ if (!cupsArrayFind(existing, (void *)"compression-supported")) ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "compression-supported", (int)(sizeof(compressions) / sizeof(compressions[0])), NULL, compressions); /* copies-default */ if (!cupsArrayFind(existing, (void *)"copies-default")) ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default", 1); /* copies-supported */ if (!cupsArrayFind(existing, (void *)"copies-supported")) ippAddRange(printer->pinfo.attrs, IPP_TAG_PRINTER, "copies-supported", 1, is_print3d ? 1 : 999); /* document-format-default */ if (defformat && !cupsArrayFind(existing, (void *)"document-format-default")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, "document-format-default", NULL, defformat); /* document-format-supported */ if ((format_sup = ippFindAttribute(printer->pinfo.attrs, "document-format-supported", IPP_TAG_ZERO)) == NULL && num_formats > 0) format_sup = ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, "document-format-supported", num_formats, NULL, (const char * const *)formats); /* document-password-supported */ if (!cupsArrayFind(existing, (void *)"document-password-supported")) ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "document-password-supported", 127); /* finishings-default */ if (!is_print3d && !cupsArrayFind(existing, (void *)"finishings-default")) ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "finishings-default", IPP_FINISHINGS_NONE); /* finishings-supported */ if (!is_print3d && !cupsArrayFind(existing, (void *)"finishings-supported")) ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "finishings-supported", IPP_FINISHINGS_NONE); /* generated-natural-language-supported */ ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_LANGUAGE), "generated-natural-language-supported", NULL, "en"); /* identify-actions-default */ if (!cupsArrayFind(existing, (void *)"identify-actions-default")) ippAddString (printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "identify-actions-default", NULL, "sound"); /* identify-actions-supported */ if (!cupsArrayFind(existing, (void *)"identify-actions-supported")) ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "identify-actions-supported", sizeof(identify_actions) / sizeof(identify_actions[0]), NULL, identify_actions); /* ipp-features-supported */ if (!cupsArrayFind(existing, (void *)"ipp-features-supported")) { if (is_print3d) ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-features-supported", sizeof(features3d) / sizeof(features3d[0]), NULL, features3d); else ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-features-supported", sizeof(features) / sizeof(features[0]), NULL, features); } /* ipp-versions-supported */ if (!cupsArrayFind(existing, (void *)"ipp-versions-supported")) ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]), NULL, versions); /* ippget-event-life */ ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "ippget-event-life", 300); /* job-account-id-default */ if (!is_print3d && !cupsArrayFind(existing, (void *)"job-account-id-default")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-account-id-default", NULL, ""); /* job-account-id-supported */ if (!is_print3d && !cupsArrayFind(existing, (void *)"job-account-id-supported")) ippAddBoolean(printer->pinfo.attrs, IPP_TAG_PRINTER, "job-account-id-supported", 1); /* job-accounting-user-id-default */ if (!is_print3d && !cupsArrayFind(existing, (void *)"job-accounting-user-id-default")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-accounting-user-id-default", NULL, ""); /* job-accounting-user-id-supported */ if (!is_print3d && !cupsArrayFind(existing, (void *)"job-accounting-user-id-supported")) ippAddBoolean(printer->pinfo.attrs, IPP_TAG_PRINTER, "job-accounting-user-id-supported", 1); /* job-creation-attributes-supported */ if (!cupsArrayFind(existing, (void *)"job-creation-attributes-supported")) { if (is_print3d) ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-creation-attributes-supported", sizeof(job_creation3d) / sizeof(job_creation3d[0]), NULL, job_creation3d); else ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-creation-attributes-supported", sizeof(job_creation) / sizeof(job_creation[0]), NULL, job_creation); } /* job-ids-supported */ ippAddBoolean(printer->pinfo.attrs, IPP_TAG_PRINTER, "job-ids-supported", 1); /* job-k-octets-supported */ ippAddRange(printer->pinfo.attrs, IPP_TAG_PRINTER, "job-k-octets-supported", 0, k_supported); /* job-password-encryption-supported */ if (!is_print3d && !cupsArrayFind(existing, (void *)"job-password-encryption-supported")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "job-password-encryption-supported", NULL, "none"); /* job-password-supported */ if (!is_print3d && !cupsArrayFind(existing, (void *)"job-password-supported")) ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-password-supported", 4); /* job-priority-default */ if (!cupsArrayFind(existing, (void *)"job-priority-default")) ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-priority-default", 50); /* job-priority-supported */ if (!cupsArrayFind(existing, (void *)"job-priority-supported")) ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-priority-supported", 100); /* job-sheets-default */ if (!is_print3d && !cupsArrayFind(existing, (void *)"job-sheets-default")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-sheets-default", NULL, "none"); /* job-sheets-supported */ if (!is_print3d && !cupsArrayFind(existing, (void *)"job-sheets-supported")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-sheets-supported", NULL, "none"); if (!is_print3d) { /* media-bottom-margin-supported */ if (!cupsArrayFind(existing, (void *)"media-bottom-margin-supported")) ippAddIntegers(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin-supported", (int)(sizeof(media_xxx_margin_supported) / sizeof(media_xxx_margin_supported[0])), media_xxx_margin_supported); /* media-col-database */ if (!cupsArrayFind(existing, (void *)"media-col-database")) { media_col_database = ippAddCollections(printer->pinfo.attrs, IPP_TAG_PRINTER, "media-col-database", (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])), NULL); for (i = 0; i < (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])); i ++) { media_col = create_media_col(media_supported[i], NULL, NULL, media_col_sizes[i][0], media_col_sizes[i][1], media_xxx_margin_supported[0]); ippSetCollection(printer->pinfo.attrs, &media_col_database, i, media_col); ippDelete(media_col); } } /* media-col-default */ if (!cupsArrayFind(existing, (void *)"media-col-default")) { media_col = create_media_col(media_supported[0], NULL, NULL, media_col_sizes[0][0], media_col_sizes[0][1], media_xxx_margin_supported[0]); ippAddCollection(printer->pinfo.attrs, IPP_TAG_PRINTER, "media-col-default", media_col); ippDelete(media_col); } /* media-col-ready */ if (!cupsArrayFind(existing, (void *)"media-col-ready")) { media_col = create_media_col(media_supported[0], "main", NULL, media_col_sizes[0][0], media_col_sizes[0][1], media_xxx_margin_supported[0]); ippAddCollection(printer->pinfo.attrs, IPP_TAG_PRINTER, "media-col-ready", media_col); ippDelete(media_col); } /* media-default */ if (!cupsArrayFind(existing, (void *)"media-default")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-default", NULL, media_supported[0]); /* media-left-margin-supported */ if (!cupsArrayFind(existing, (void *)"media-left-margin-supported")) ippAddIntegers(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-left-margin-supported", (int)(sizeof(media_xxx_margin_supported) / sizeof(media_xxx_margin_supported[0])), media_xxx_margin_supported); /* media-ready */ if (!cupsArrayFind(existing, (void *)"media-ready")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-ready", NULL, media_supported[0]); /* media-right-margin-supported */ if (!cupsArrayFind(existing, (void *)"media-right-margin-supported")) ippAddIntegers(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-right-margin-supported", (int)(sizeof(media_xxx_margin_supported) / sizeof(media_xxx_margin_supported[0])), media_xxx_margin_supported); /* media-supported */ if (!cupsArrayFind(existing, (void *)"media-supported")) ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-supported", (int)(sizeof(media_supported) / sizeof(media_supported[0])), NULL, media_supported); /* media-size-supported */ if (!cupsArrayFind(existing, (void *)"media-size-supported")) { media_size_supported = ippAddCollections(printer->pinfo.attrs, IPP_TAG_PRINTER, "media-size-supported", (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])), NULL); for (i = 0; i < (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0])); i ++) { ipp_t *size = create_media_size(media_col_sizes[i][0], media_col_sizes[i][1]); ippSetCollection(printer->pinfo.attrs, &media_size_supported, i, size); ippDelete(size); } } /* media-source-supported */ if (!cupsArrayFind(existing, (void *)"media-source-supported")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-source-supported", NULL, "main"); /* media-top-margin-supported */ if (!cupsArrayFind(existing, (void *)"media-top-margin-supported")) ippAddIntegers(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-top-margin-supported", (int)(sizeof(media_xxx_margin_supported) / sizeof(media_xxx_margin_supported[0])), media_xxx_margin_supported); /* media-type-supported */ if (!cupsArrayFind(existing, (void *)"media-type-supported")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-type-supported", NULL, "auto"); /* media-col-supported */ if (!cupsArrayFind(existing, (void *)"media-col-supported")) ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-col-supported", (int)(sizeof(media_col_supported) / sizeof(media_col_supported[0])), NULL, media_col_supported); /* multiple-document-handling-supported */ ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "multiple-document-handling-supported", sizeof(multiple_document_handling) / sizeof(multiple_document_handling[0]), NULL, multiple_document_handling); } /* multiple-document-jobs-supported */ ippAddBoolean(printer->pinfo.attrs, IPP_TAG_PRINTER, "multiple-document-jobs-supported", 0); /* multiple-operation-time-out */ ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "multiple-operation-time-out", 60); /* multiple-operation-time-out-action */ ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "multiple-operation-time-out-action", NULL, "abort-job"); /* natural-language-configured */ ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_LANGUAGE), "natural-language-configured", NULL, "en"); /* notify-attributes-supported */ ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "notify-attributes-supported", sizeof(notify_attributes) / sizeof(notify_attributes[0]), NULL, notify_attributes); /* notify-events-default */ ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "notify-events-default", NULL, "job-completed"); /* notify-events-supported */ ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "notify-events-supported", sizeof(server_events) / sizeof(server_events[0]), NULL, server_events); /* notify-lease-duration-default */ ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "notify-lease-duration-default", 86400); /* notify-lease-duration-supported */ ippAddRange(printer->pinfo.attrs, IPP_TAG_PRINTER, "notify-lease-duration-supported", 0, SERVER_NOTIFY_LEASE_DURATION_MAX); /* notify-max-events-supported */ ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "notify-max-events-supported", (int)(sizeof(server_events) / sizeof(server_events[0]))); /* notify-pull-method-supported */ ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "notify-pull-method-supported", NULL, "ippget"); /* number-up-default */ if (!is_print3d && !cupsArrayFind(existing, (void *)"number-up-default")) ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "number-up-default", 1); /* number-up-supported */ if (!is_print3d && !cupsArrayFind(existing, (void *)"number-up-supported")) ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "number-up-supported", 1); /* operations-supported */ if (is_print3d) ippAddIntegers(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "operations-supported", sizeof(ops3d) / sizeof(ops3d[0]), ops3d); else ippAddIntegers(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "operations-supported", sizeof(ops) / sizeof(ops[0]), ops); if (!is_print3d) { /* orientation-requested-default */ if (!cupsArrayFind(existing, (void *)"orientation-requested-default")) ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "orientation-requested-default", 0); /* orientation-requested-supported */ if (!cupsArrayFind(existing, (void *)"orientation-requested-supported")) ippAddIntegers(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "orientation-requested-supported", 4, orients); /* output-bin-default */ if (!cupsArrayFind(existing, (void *)"output-bin-default")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-default", NULL, "face-down"); /* output-bin-supported */ if (!cupsArrayFind(existing, (void *)"output-bin-supported")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-supported", NULL, "face-down"); /* overrides-supported */ if (!cupsArrayFind(existing, (void *)"overrides-supported")) ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "overrides-supported", (int)(sizeof(overrides) / sizeof(overrides[0])), NULL, overrides); /* page-ranges-supported */ if (!cupsArrayFind(existing, (void *)"page-ranges-supported")) ippAddBoolean(printer->pinfo.attrs, IPP_TAG_PRINTER, "page-ranges-supported", 1); /* pages-per-minute */ if (!cupsArrayFind(existing, (void *)"pages-per-minute")) ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "pages-per-minute", printer->pinfo.ppm); /* pages-per-minute-color */ if (printer->pinfo.ppm_color > 0 && !cupsArrayFind(existing, (void *)"pages-per-minute-color")) ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "pages-per-minute-color", printer->pinfo.ppm_color); /* pdl-override-supported */ if (!cupsArrayFind(existing, (void *)"pdl-override-supported")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pdl-override-supported", NULL, "attempted"); /* preferred-attributes-supported */ ippAddBoolean(printer->pinfo.attrs, IPP_TAG_PRINTER, "preferred-attributes-supported", 0); /* print-color-mode-default */ if (!cupsArrayFind(existing, (void *)"print-color-mode-default")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-color-mode-default", NULL, "auto"); /* print-color-mode-supported */ if (!cupsArrayFind(existing, (void *)"print-color-mode-supported")) ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-color-mode-supported", (int)(sizeof(print_color_mode_supported) / sizeof(print_color_mode_supported[0])), NULL, print_color_mode_supported); /* print-content-optimize-default */ if (!cupsArrayFind(existing, (void *)"print-content-optimize-default")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-content-optimize-default", NULL, "auto"); /* print-content-optimize-supported */ if (!cupsArrayFind(existing, (void *)"print-content-optimize-supported")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-content-optimize-supported", NULL, "auto"); /* print-rendering-intent-default */ if (!cupsArrayFind(existing, (void *)"print-rendering-intent-default")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-default", NULL, "auto"); /* print-rendering-intent-supported */ if (!cupsArrayFind(existing, (void *)"print-rendering-intent-supported")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-supported", NULL, "auto"); } /* print-quality-default */ if (!cupsArrayFind(existing, (void *)"print-quality-default")) ippAddInteger(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "print-quality-default", IPP_QUALITY_NORMAL); /* print-quality-supported */ if (!cupsArrayFind(existing, (void *)"print-quality-supported")) ippAddIntegers(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "print-quality-supported", (int)(sizeof(print_quality_supported) / sizeof(print_quality_supported[0])), print_quality_supported); /* printer-device-id */ if (!is_print3d) { int count = ippGetCount(format_sup);/* Number of supported formats */ snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;", printer->pinfo.make, printer->pinfo.model); ptr = device_id + strlen(device_id); prefix = "CMD:"; for (i = 0; i < count; i ++) { const char *format = ippGetString(format_sup, i, NULL); /* Current format */ if (!strcasecmp(format, "application/pdf")) snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPDF", prefix); else if (!strcasecmp(format, "application/postscript")) snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPS", prefix); else if (!strcasecmp(format, "application/vnd.hp-PCL")) snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPCL", prefix); else if (!strcasecmp(format, "image/jpeg")) snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sJPEG", prefix); else if (!strcasecmp(format, "image/png")) snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPNG", prefix); else if (!strcasecmp(format, "image/urf")) snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sURF", prefix); else if (strcasecmp(format, "application/octet-stream")) snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%s%s", prefix, format); ptr += strlen(ptr); prefix = ","; } if (ptr < (device_id + sizeof(device_id) - 1)) { *ptr++ = ';'; *ptr = '\0'; } ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-device-id", NULL, device_id); } /* printer-get-attributes-supported */ ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "printer-get-attributes-supported", NULL, "document-format"); /* printer-geo-location */ if (!cupsArrayFind(existing, (void *)"printer-geo-location")) ippAddOutOfBand(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_UNKNOWN, "printer-geo-location"); /* printer-icons */ ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-icons", NULL, icons); /* printer-info */ ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL, name); /* printer-is-accepting-jobs */ ippAddBoolean(printer->pinfo.attrs, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1); if (!is_print3d) { /* printer-input-tray */ if (!cupsArrayFind(existing, (void *)"printer-input-tray")) { const char *tray = "type=sheetFeedAutoRemovableTray;mediafeed=0;mediaxfeed=0;maxcapacity=250;level=100;status=0;name=main;"; ippAddOctetString(printer->pinfo.attrs, IPP_TAG_PRINTER, "printer-input-tray", tray, (int)strlen(tray)); } } /* printer-location */ if (!cupsArrayFind(existing, (void *)"printer-location")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", NULL, printer->pinfo.location); /* printer-make-and-model */ if (!cupsArrayFind(existing, (void *)"printer-make-and-model")) { snprintf(make_model, sizeof(make_model), "%s %s", printer->pinfo.make, printer->pinfo.model); ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-make-and-model", NULL, make_model); } /* printer-mandatory-job-attributes */ if (printer->pinfo.pin && !cupsArrayFind(existing, (void *)"printer-mandatory-job-attributes")) { static const char * const names[] = /* Attributes needed for PIN printing */ { "job-account-id", "job-accounting-user-id", "job-password" }; ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "printer-mandatory-job-attributes", (int)(sizeof(names) / sizeof(names[0])), NULL, names); } /* printer-more-info */ ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info", NULL, adminurl); /* printer-name */ ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL, name); /* printer-organization */ if (!cupsArrayFind(existing, (void *)"printer-organization")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-organization", NULL, "Apple Inc."); /* printer-organizational-unit */ if (!cupsArrayFind(existing, (void *)"printer-organizational-unit")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-organizational-unit", NULL, "Printing Engineering"); if (!is_print3d) { /* printer-resolution-default */ if (!cupsArrayFind(existing, (void *)"printer-resolution-default")) ippAddResolution(printer->pinfo.attrs, IPP_TAG_PRINTER, "printer-resolution-default", IPP_RES_PER_INCH, 600, 600); /* printer-resolution-supported */ if (!cupsArrayFind(existing, (void *)"printer-resolutions-supported")) ippAddResolution(printer->pinfo.attrs, IPP_TAG_PRINTER, "printer-resolution-supported", IPP_RES_PER_INCH, 600, 600); } /* printer-strings-languages-supported */ if (!cupsArrayFind(existing, (void *)"printer-strings-languages-supported") && printer->pinfo.strings) { server_lang_t *lang; for (attr = NULL, lang = (server_lang_t *)cupsArrayFirst(printer->pinfo.strings); lang; lang = (server_lang_t *)cupsArrayNext(printer->pinfo.strings)) { if (attr) ippSetString(printer->pinfo.attrs, &attr, ippGetCount(attr), lang->lang); else attr = ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE, "printer-strings-languages-supported", NULL, lang->lang); } } if (!is_print3d) { /* printer-supply */ if (!cupsArrayFind(existing, (void *)"printer-supply")) { int count = printer->pinfo.ppm_color > 0 ? 5 : 2; /* Number of values */ attr = ippAddOctetString(printer->pinfo.attrs, IPP_TAG_PRINTER, "printer-supply", printer_supply[0], (int)strlen(printer_supply[0])); for (i = 1; i < count; i ++) ippSetOctetString(printer->pinfo.attrs, &attr, i, printer_supply[i], (int)strlen(printer_supply[i])); } /* printer-supply-description */ if (!cupsArrayFind(existing, (void *)"printer-supply-description")) ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-supply-description", printer->pinfo.ppm_color > 0 ? 5 : 2, NULL, printer_supply_desc); /* printer-supply-info-uri */ ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-supply-info-uri", NULL, supplyurl); } /* printer-uri-supported */ ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", num_uris, NULL, (const char **)uriptrs); /* printer-uuid */ if (!cupsArrayFind(existing, (void *)"printer-uuid")) { httpAssembleUUID(lis->host, lis->port, name, 0, uuid, sizeof(uuid)); ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uuid", NULL, uuid); } /* printer-xri-supported */ xri_sup = ippAddCollections(printer->pinfo.attrs, IPP_TAG_PRINTER, "printer-xri-supported", num_uris, NULL); for (i = 0; i < num_uris; i ++) { xri_col = ippNew(); ippAddString(xri_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "xri-authentication", NULL, printer->pinfo.proxy_user ? "basic" : "none"); #ifdef HAVE_SSL if (Encryption != HTTP_ENCRYPTION_NEVER) ippAddString(xri_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "xri-security", NULL, "tls"); else #endif /* HAVE_SSL */ ippAddString(xri_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "xri-security", NULL, "none"); ippAddString(xri_col, IPP_TAG_PRINTER, IPP_TAG_URI, "xri-uri", NULL, uriptrs[i]); ippSetCollection(printer->pinfo.attrs, &xri_sup, i, xri_col); ippDelete(xri_col); } cupsArrayDelete(uris); free(uriptrs); /* pwg-raster-document-xxx-supported */ for (i = 0; i < num_formats; i ++) if (!strcasecmp(formats[i], "image/pwg-raster")) break; if (i < num_formats) { if (!cupsArrayFind(existing, (void *)"pwg-raster-document-resolution-supported")) ippAddResolutions(printer->pinfo.attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", (int)(sizeof(pwg_raster_document_resolution_supported) / sizeof(pwg_raster_document_resolution_supported[0])), IPP_RES_PER_INCH, pwg_raster_document_resolution_supported, pwg_raster_document_resolution_supported); if (!cupsArrayFind(existing, (void *)"pwg-raster-document-sheet-back")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-sheet-back", NULL, "normal"); if (!cupsArrayFind(existing, (void *)"pwg-raster-document-type-supported")) ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-type-supported", (int)(sizeof(pwg_raster_document_type_supported) / sizeof(pwg_raster_document_type_supported[0])), NULL, pwg_raster_document_type_supported); } /* reference-uri-scheme-supported */ ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_URISCHEME), "reference-uri-schemes-supported", (int)(sizeof(reference_uri_schemes_supported) / sizeof(reference_uri_schemes_supported[0])), NULL, reference_uri_schemes_supported); /* sides-default */ if (!is_print3d && !cupsArrayFind(existing, (void *)"sides-default")) ippAddString(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-default", NULL, "one-sided"); /* sides-supported */ if (!is_print3d && !cupsArrayFind(existing, (void *)"sides-supported")) ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-supported", printer->pinfo.duplex ? 3 : 1, NULL, sides_supported); /* urf-supported */ for (i = 0; i < num_formats; i ++) if (!strcasecmp(formats[i], "image/urf")) break; if (i < num_formats && !cupsArrayFind(existing, "urf-supported")) ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "urf-supported", (int)(sizeof(urf_supported) / sizeof(urf_supported[0])) - !printer->pinfo.duplex, NULL, urf_supported); /* uri-authentication-supported */ attr = ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-authentication-supported", num_uris, NULL, NULL); for (i = 0; i < num_uris; i ++) ippSetString(printer->pinfo.attrs, &attr, i, printer->pinfo.proxy_user ? "basic" : "none"); /* uri-security-supported */ #ifdef HAVE_SSL if (Encryption != HTTP_ENCRYPTION_NEVER) { attr = ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-security-supported", num_uris, NULL, NULL); for (i = 0; i < num_uris; i ++) ippSetString(printer->pinfo.attrs, &attr, i, "tls"); } else #endif /* HAVE_SSL */ { attr = ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-security-supported", num_uris, NULL, NULL); for (i = 0; i < num_uris; i ++) ippSetString(printer->pinfo.attrs, &attr, i, "none"); } /* which-jobs-supported */ ippAddStrings(printer->pinfo.attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "which-jobs-supported", sizeof(which_jobs) / sizeof(which_jobs[0]), NULL, which_jobs); if (num_formats > 0) free(formats[0]); cupsArrayDelete(existing); snprintf(title, sizeof(title), "[Printer %s]", printer->name); serverLogAttributes(NULL, title, printer->pinfo.attrs, 0); /* * Register the printer with Bonjour... */ if (!register_printer(printer, adminurl, DNSSDSubType)) goto bad_printer; /* * Return it! */ return (printer); /* * If we get here we were unable to create the printer... */ bad_printer: serverDeletePrinter(printer); return (NULL); } /* * 'serverDeletePrinter()' - Unregister, close listen sockets, and free all memory * used by a printer object. */ void serverDeletePrinter(server_printer_t *printer) /* I - Printer */ { _cupsRWLockWrite(&printer->rwlock); #if HAVE_DNSSD if (printer->geo_ref) DNSServiceRemoveRecord(printer->printer_ref, printer->geo_ref, 0); if (printer->printer_ref) DNSServiceRefDeallocate(printer->printer_ref); if (printer->ipp_ref) DNSServiceRefDeallocate(printer->ipp_ref); # ifdef HAVE_SSL if (printer->ipps_ref) DNSServiceRefDeallocate(printer->ipps_ref); # endif /* HAVE_SSL */ if (printer->http_ref) DNSServiceRefDeallocate(printer->http_ref); #elif defined(HAVE_AVAHI) avahi_threaded_poll_lock(DNSSDMaster); if (printer->ipp_ref) avahi_entry_group_free(printer->ipp_ref); avahi_threaded_poll_unlock(DNSSDMaster); #endif /* HAVE_DNSSD */ if (printer->default_uri) free(printer->default_uri); if (printer->resource) free(printer->resource); if (printer->dnssd_name) free(printer->dnssd_name); if (printer->name) free(printer->name); if (printer->pinfo.icon) free(printer->pinfo.icon); if (printer->pinfo.command) free(printer->pinfo.command); if (printer->pinfo.device_uri) free(printer->pinfo.device_uri); if (printer->pinfo.proxy_user) free(printer->pinfo.proxy_user); cupsArrayDelete(printer->pinfo.strings); ippDelete(printer->pinfo.attrs); ippDelete(printer->dev_attrs); cupsArrayDelete(printer->active_jobs); cupsArrayDelete(printer->completed_jobs); cupsArrayDelete(printer->jobs); cupsArrayDelete(printer->subscriptions); _cupsRWDeinit(&printer->rwlock); free(printer); } /* * 'serverGetPrinterStateReasonsBits()' - Get the bits associated with "printer-state-reasons" values. */ server_preason_t /* O - Bits */ serverGetPrinterStateReasonsBits( ipp_attribute_t *attr) /* I - "printer-state-reasons" bits */ { int i, j, /* Looping vars */ count; /* Number of "printer-state-reasons" values */ const char *keyword; /* "printer-state-reasons" value */ server_preason_t preasons = SERVER_PREASON_NONE; /* Bits for "printer-state-reasons" values */ count = ippGetCount(attr); for (i = 0; i < count; i ++) { keyword = ippGetString(attr, i, NULL); for (j = 0; j < (int)(sizeof(server_preasons) / sizeof(server_preasons[0])); j ++) { if (!strcmp(keyword, server_preasons[j])) { preasons |= (server_preason_t)(1 << j); break; } } } return (preasons); } /* * 'compare_active_jobs()' - Compare two active jobs. */ static int /* O - Result of comparison */ compare_active_jobs(server_job_t *a, /* I - First job */ server_job_t *b) /* I - Second job */ { int diff; /* Difference */ if ((diff = b->priority - a->priority) == 0) diff = b->id - a->id; return (diff); } /* * 'compare_completed_jobs()' - Compare two completed jobs. */ static int /* O - Result of comparison */ compare_completed_jobs(server_job_t *a, /* I - First job */ server_job_t *b) /* I - Second job */ { int diff; /* Difference */ if ((diff = (int)(a->completed - b->completed)) == 0) diff = b->id - a->id; return (diff); } /* * 'compare_devices()' - Compare two devices... */ static int /* O - Result of comparison */ compare_devices(server_device_t *a, /* I - First device */ server_device_t *b) /* I - Second device */ { return (strcmp(a->uuid, b->uuid)); } /* * 'compare_jobs()' - Compare two jobs. */ static int /* O - Result of comparison */ compare_jobs(server_job_t *a, /* I - First job */ server_job_t *b) /* I - Second job */ { return (b->id - a->id); } /* * 'create_media_col()' - Create a media-col value. */ static ipp_t * /* O - media-col collection */ create_media_col(const char *media, /* I - Media name */ const char *source, /* I - Media source */ const char *type, /* I - Media type */ int width, /* I - x-dimension in 2540ths */ int length, /* I - y-dimension in 2540ths */ int margins) /* I - Value for margins */ { ipp_t *media_col = ippNew(), /* media-col value */ *media_size = create_media_size(width, length); /* media-size value */ char media_key[256]; /* media-key value */ if (type && source) snprintf(media_key, sizeof(media_key), "%s_%s_%s%s", media, source, type, margins == 0 ? "_borderless" : ""); else if (type) snprintf(media_key, sizeof(media_key), "%s__%s%s", media, type, margins == 0 ? "_borderless" : ""); else if (source) snprintf(media_key, sizeof(media_key), "%s_%s%s", media, source, margins == 0 ? "_borderless" : ""); else snprintf(media_key, sizeof(media_key), "%s%s", media, margins == 0 ? "_borderless" : ""); ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-key", NULL, media_key); ippAddCollection(media_col, IPP_TAG_PRINTER, "media-size", media_size); ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-size-name", NULL, media); ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin", margins); ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-left-margin", margins); ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-right-margin", margins); ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-top-margin", margins); if (source) ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-source", NULL, source); if (type) ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-type", NULL, type); ippDelete(media_size); return (media_col); } /* * 'create_media_size()' - Create a media-size value. */ static ipp_t * /* O - media-col collection */ create_media_size(int width, /* I - x-dimension in 2540ths */ int length) /* I - y-dimension in 2540ths */ { ipp_t *media_size = ippNew(); /* media-size value */ ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "x-dimension", width); ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "y-dimension", length); return (media_size); } #ifdef HAVE_DNSSD /* * 'dnssd_callback()' - Handle Bonjour registration events. */ static void DNSSD_API dnssd_callback( DNSServiceRef sdRef, /* I - Service reference */ DNSServiceFlags flags, /* I - Status flags */ DNSServiceErrorType errorCode, /* I - Error, if any */ const char *name, /* I - Service name */ const char *regtype, /* I - Service type */ const char *domain, /* I - Domain for service */ server_printer_t *printer) /* I - Printer */ { (void)sdRef; (void)flags; (void)domain; if (errorCode) { fprintf(stderr, "DNSServiceRegister for %s failed with error %d.\n", regtype, (int)errorCode); return; } else if (strcasecmp(name, printer->dnssd_name)) { serverLogPrinter(SERVER_LOGLEVEL_INFO, printer, "Now using DNS-SD service name \"%s\".", name); /* No lock needed since only the main thread accesses/changes this */ free(printer->dnssd_name); printer->dnssd_name = strdup(name); } } #elif defined(HAVE_AVAHI) /* * 'dnssd_callback()' - Handle Bonjour registration events. */ static void dnssd_callback( AvahiEntryGroup *srv, /* I - Service */ AvahiEntryGroupState state, /* I - Registration state */ void *context) /* I - Printer */ { (void)srv; (void)state; (void)context; } #endif /* HAVE_DNSSD */ #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) /* * 'register_geo()' - Register (or update) a printer's geo-location via Bonjour. */ static void register_geo(server_printer_t *printer) /* I - Printer */ { ipp_attribute_t *printer_geo_location;/* printer-geo-location attribute */ double lat_degrees = 0.0, /* Latitude in degrees */ lon_degrees = 0.0, /* Longitude in degrees */ alt_meters = 0.0, /* Altitude in meters */ uncertainty = 10.0; /* Accuracy in meters */ unsigned lat_1000ths, /* Latitude in thousandths of arc seconds */ lon_1000ths, /* Longitude in thousandths of arc seconds */ alt_cmbase; /* Altitude in centimeters */ unsigned char pre; /* Precision as MSD + power */ unsigned char loc[16]; /* LOC record data */ /* * Parse out any geo-location information... */ if ((printer_geo_location = ippFindAttribute(printer->pinfo.attrs, "printer-geo-location", IPP_TAG_URI))) { char scheme[32], /* URI scheme */ userpass[256], /* URI username:password */ host[256], /* URI hostname */ resource[1024]; /* URI resource path */ int port; /* URI port */ if (httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(printer_geo_location, 0, NULL), scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) >= HTTP_URI_STATUS_OK && !strcmp(scheme, "geo")) { /* * Parse "geo:" URI... */ char *ptr; /* Pointer into resource */ lat_degrees = strtod(resource, &ptr); if (ptr && *ptr == ',') { lon_degrees = strtod(ptr, &ptr); if (ptr && *ptr == ',') alt_meters = strtod(ptr, &ptr); if (ptr && !strncmp(ptr, "?u=", 3)) uncertainty = strtod(ptr + 3, NULL); } else lat_degrees = 0.0; } } /* * Convert to a DNS LOC record... */ uncertainty *= 100.0; pre = 0; while (uncertainty >= 10.0 && pre < 15) { uncertainty /= 10.0; pre ++; } if (uncertainty >= 10.0) pre = 0x9f; else pre |= (unsigned)uncertainty << 4; lat_1000ths = (unsigned)(lat_degrees * 3600000.0) + 2147483648U; lon_1000ths = (unsigned)(lon_degrees * 3600000.0) + 2147483648U; alt_cmbase = (unsigned)(alt_meters * 100.0 + 10000000.0); loc[0] = 0; /* VERSION */ loc[1] = 0x51; /* SIZE = 50cm */ loc[2] = pre; /* HORIZ PRE */ loc[3] = pre; /* VERT PRE */ loc[4] = (unsigned char)(lat_1000ths >> 24); /* LATITUDE */ loc[5] = (unsigned char)(lat_1000ths >> 16); loc[6] = (unsigned char)(lat_1000ths >> 8); loc[7] = (unsigned char)lat_1000ths; loc[8] = (unsigned char)(lon_1000ths >> 24); /* LONGITUDE */ loc[9] = (unsigned char)(lon_1000ths >> 16); loc[10] = (unsigned char)(lon_1000ths >> 8); loc[11] = (unsigned char)lon_1000ths; loc[12] = (unsigned char)(alt_cmbase >> 24); /* ALTITUDE */ loc[13] = (unsigned char)(alt_cmbase >> 16); loc[14] = (unsigned char)(alt_cmbase >> 8); loc[15] = (unsigned char)alt_cmbase; /* * Register the geo-location... */ if (printer->geo_ref) { #ifdef HAVE_DNSSD DNSServiceUpdateRecord(printer->ipp_ref, printer->geo_ref, 0, sizeof(loc), loc, 0); #elif defined(HAVE_AVAHI) /* Avahi doesn't support updating */ #endif /* HAVE_DNSSD */ } else { #ifdef HAVE_DNSSD DNSServiceAddRecord(printer->ipp_ref, &printer->geo_ref, 0, kDNSServiceType_LOC, sizeof(loc), loc, 0); #elif defined(HAVE_AVAHI) avahi_entry_group_add_record(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, AVAHI_DNS_CLASS_IN, 29, 0, loc, sizeof(loc)); #endif /* HAVE_DNSSD */ } } #endif /* HAVE_DNSSD || HAVE_AVAHI */ /* * 'register_printer()' - Register a printer object via Bonjour. */ static int /* O - 1 on success, 0 on error */ register_printer( server_printer_t *printer, /* I - Printer */ const char *adminurl, /* I - Web interface URL */ const char *subtype) /* I - Service subtype */ { #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) int is_print3d; /* 3D printer? */ server_txt_t ipp_txt; /* Bonjour IPP TXT record */ ipp_attribute_t *format_sup = ippFindAttribute(printer->pinfo.attrs, "document-format-supported", IPP_TAG_MIMETYPE), /* document-formats-supported */ *urf_sup = ippFindAttribute(printer->pinfo.attrs, "urf-supported", IPP_TAG_KEYWORD), /* urf-supported */ *uuid = ippFindAttribute(printer->pinfo.attrs, "printer-uuid", IPP_TAG_URI); /* printer-uuid */ const char *uuidval; /* String value of UUID */ int i, /* Looping var */ count; /* Number for formats */ char temp[256], /* Temporary list */ *ptr; /* Pointer into list */ #endif /* HAVE_DNSSD || HAVE_AVAHI */ #ifdef HAVE_DNSSD DNSServiceErrorType error; /* Error from Bonjour */ char make_model[256],/* Make and model together */ product[256], /* Product string */ regtype[256]; /* Bonjour service type */ server_listener_t *lis = cupsArrayFirst(Listeners); /* Listen socket */ is_print3d = !strncmp(printer->resource, "/ipp/print3d/", 13); /* * Build the TXT record for IPP... */ snprintf(make_model, sizeof(make_model), "%s %s", printer->pinfo.make, printer->pinfo.model); snprintf(product, sizeof(product), "(%s)", printer->pinfo.model); TXTRecordCreate(&ipp_txt, 1024, NULL); TXTRecordSetValue(&ipp_txt, "rp", (uint8_t)strlen(printer->resource) - 1, printer->resource + 1); TXTRecordSetValue(&ipp_txt, "ty", (uint8_t)strlen(make_model), make_model); TXTRecordSetValue(&ipp_txt, "adminurl", (uint8_t)strlen(adminurl), adminurl); if (printer->pinfo.location && *(printer->pinfo.location)) TXTRecordSetValue(&ipp_txt, "note", (uint8_t)strlen(printer->pinfo.location), printer->pinfo.location); if (format_sup) { for (i = 0, count = ippGetCount(format_sup), ptr = temp; i < count; i ++) { const char *format = ippGetString(format_sup, i, NULL); if (strcmp(format, "application/octet-stream")) { if (ptr > temp && ptr < (temp + sizeof(temp) - 1)) *ptr++ = ','; strlcpy(ptr, format, sizeof(temp) - (size_t)(ptr - temp)); ptr += strlen(ptr); } } *ptr = '\0'; serverLogPrinter(SERVER_LOGLEVEL_DEBUG, printer, "document-format-supported(%d)=%s", count, temp); TXTRecordSetValue(&ipp_txt, "pdl", (uint8_t)strlen(temp), temp); } if (!is_print3d) { TXTRecordSetValue(&ipp_txt, "product", (uint8_t)strlen(product), product); TXTRecordSetValue(&ipp_txt, "Color", 1, printer->pinfo.ppm_color ? "T" : "F"); TXTRecordSetValue(&ipp_txt, "Duplex", 1, printer->pinfo.duplex ? "T" : "F"); if (printer->pinfo.make) TXTRecordSetValue(&ipp_txt, "usb_MFG", (uint8_t)strlen(printer->pinfo.make), printer->pinfo.make); if (printer->pinfo.model) TXTRecordSetValue(&ipp_txt, "usb_MDL", (uint8_t)strlen(printer->pinfo.model), printer->pinfo.model); } uuidval = ippGetString(uuid, 0, NULL); if (uuidval) { uuidval += 9; /* Skip "urn:uuid:" prefix */ TXTRecordSetValue(&ipp_txt, "UUID", (uint8_t)strlen(uuidval), uuidval); } # ifdef HAVE_SSL if (!is_print3d && Encryption != HTTP_ENCRYPTION_NEVER) TXTRecordSetValue(&ipp_txt, "TLS", 3, "1.2"); # endif /* HAVE_SSL */ if (urf_sup) { for (i = 0, count = ippGetCount(urf_sup), ptr = temp; i < count; i ++) { const char *val = ippGetString(urf_sup, i, NULL); if (ptr > temp && ptr < (temp + sizeof(temp) - 1)) *ptr++ = ','; strlcpy(ptr, val, sizeof(temp) - (size_t)(ptr - temp)); ptr += strlen(ptr); } *ptr = '\0'; serverLogPrinter(SERVER_LOGLEVEL_DEBUG, printer, "urf-supported(%d)=%s", count, temp); TXTRecordSetValue(&ipp_txt, "URF", (uint8_t)strlen(temp), temp); } TXTRecordSetValue(&ipp_txt, "txtvers", 1, "1"); TXTRecordSetValue(&ipp_txt, "qtotal", 1, "1"); /* * Register the _printer._tcp (LPD) service type with a port number of 0 to * defend our service name but not actually support LPD... */ printer->printer_ref = DNSSDMaster; if ((error = DNSServiceRegister(&(printer->printer_ref), kDNSServiceFlagsShareConnection, 0 /* interfaceIndex */, printer->dnssd_name, "_printer._tcp", NULL /* domain */, NULL /* host */, 0 /* port */, 0 /* txtLen */, NULL /* txtRecord */, (DNSServiceRegisterReply)dnssd_callback, printer)) != kDNSServiceErr_NoError) { serverLogPrinter(SERVER_LOGLEVEL_ERROR, printer, "Unable to register \"%s._printer._tcp\": %d", printer->dnssd_name, error); return (0); } /* * Then register the corresponding IPP service types with the real port * number to advertise our printer... */ if (!is_print3d) { printer->ipp_ref = DNSSDMaster; if (subtype && *subtype) snprintf(regtype, sizeof(regtype), SERVER_IPP_TYPE ",%s", subtype); else strlcpy(regtype, SERVER_IPP_TYPE, sizeof(regtype)); if ((error = DNSServiceRegister(&(printer->ipp_ref), kDNSServiceFlagsShareConnection, 0 /* interfaceIndex */, printer->dnssd_name, regtype, NULL /* domain */, NULL /* host */, htons(lis->port), TXTRecordGetLength(&ipp_txt), TXTRecordGetBytesPtr(&ipp_txt), (DNSServiceRegisterReply)dnssd_callback, printer)) != kDNSServiceErr_NoError) { serverLogPrinter(SERVER_LOGLEVEL_ERROR, printer, "Unable to register \"%s.%s\": %d", printer->dnssd_name, regtype, error); return (0); } } # ifdef HAVE_SSL if (Encryption != HTTP_ENCRYPTION_NEVER) { printer->ipps_ref = DNSSDMaster; if (is_print3d) { if (subtype && *subtype) snprintf(regtype, sizeof(regtype), SERVER_IPPS_3D_TYPE ",%s", subtype); else strlcpy(regtype, SERVER_IPPS_3D_TYPE, sizeof(regtype)); } else if (subtype && *subtype) snprintf(regtype, sizeof(regtype), SERVER_IPPS_TYPE ",%s", subtype); else strlcpy(regtype, SERVER_IPPS_TYPE, sizeof(regtype)); if ((error = DNSServiceRegister(&(printer->ipps_ref), kDNSServiceFlagsShareConnection, 0 /* interfaceIndex */, printer->dnssd_name, regtype, NULL /* domain */, NULL /* host */, htons(lis->port), TXTRecordGetLength(&ipp_txt), TXTRecordGetBytesPtr(&ipp_txt), (DNSServiceRegisterReply)dnssd_callback, printer)) != kDNSServiceErr_NoError) { serverLogPrinter(SERVER_LOGLEVEL_ERROR, printer, "Unable to register \"%s.%s\": %d", printer->dnssd_name, regtype, error); return (0); } } # endif /* HAVE_SSL */ /* * Register the geolocation of the service... */ register_geo(printer); /* * Similarly, register the _http._tcp,_printer (HTTP) service type with the * real port number to advertise our IPP printer... */ printer->http_ref = DNSSDMaster; if ((error = DNSServiceRegister(&(printer->http_ref), kDNSServiceFlagsShareConnection, 0 /* interfaceIndex */, printer->dnssd_name, SERVER_WEB_TYPE ",_printer", NULL /* domain */, NULL /* host */, htons(lis->port), 0 /* txtLen */, NULL, /* txtRecord */ (DNSServiceRegisterReply)dnssd_callback, printer)) != kDNSServiceErr_NoError) { serverLogPrinter(SERVER_LOGLEVEL_ERROR, printer, "Unable to register \"%s.%s\": %d", printer->dnssd_name, SERVER_WEB_TYPE ",_printer", error); return (0); } TXTRecordDeallocate(&ipp_txt); #elif defined(HAVE_AVAHI) server_listener_t *lis = cupsArrayFirst(Listeners); /* Listen socket */ is_print3d = !strncmp(printer->resource, "/ipp/print3d/", 13); /* * Create the TXT record... */ ipp_txt = NULL; ipp_txt = avahi_string_list_add_printf(ipp_txt, "rp=%s", printer->resource + 1); ipp_txt = avahi_string_list_add_printf(ipp_txt, "ty=%s %s", printer->pinfo.make, printer->pinfo.model); ipp_txt = avahi_string_list_add_printf(ipp_txt, "adminurl=%s", adminurl); if (printer->pinfo.location && *(printer->pinfo.location)) ipp_txt = avahi_string_list_add_printf(ipp_txt, "note=%s", printer->pinfo.location); if (format_sup) { for (i = 0, count = ippGetCount(format_sup), ptr = temp; i < count; i ++) { const char *format = ippGetString(format_sup, i, NULL); if (strcmp(format, "application/octet-stream")) { if (ptr > temp && ptr < (temp + sizeof(temp) - 1)) *ptr++ = ','; strlcpy(ptr, format, sizeof(temp) - (size_t)(ptr - temp)); ptr += strlen(ptr); } } *ptr = '\0'; ipp_txt = avahi_string_list_add_printf(ipp_txt, "pdl=%s", temp); } if (!is_print3d) { ipp_txt = avahi_string_list_add_printf(ipp_txt, "product=(%s)", printer->pinfo.model); ipp_txt = avahi_string_list_add_printf(ipp_txt, "Color=%s", printer->pinfo.ppm_color ? "T" : "F"); ipp_txt = avahi_string_list_add_printf(ipp_txt, "Duplex=%s", printer->pinfo.duplex ? "T" : "F"); if (printer->pinfo.make) ipp_txt = avahi_string_list_add_printf(ipp_txt, "usb_MFG=%s", printer->pinfo.make); if (printer->pinfo.model) ipp_txt = avahi_string_list_add_printf(ipp_txt, "usb_MDL=%s", printer->pinfo.model); } uuidval = ippGetString(uuid, 0, NULL); if (uuidval) { uuidval += 9; /* Skip "urn:uuid:" prefix */ ipp_txt = avahi_string_list_add_printf(ipp_txt, "UUID=%s", uuidval); } # ifdef HAVE_SSL if (!is_print3d && Encryption != HTTP_ENCRYPTION_NEVER) ipp_txt = avahi_string_list_add_printf(ipp_txt, "TLS=1.2"); # endif /* HAVE_SSL */ if (urf_sup) { for (i = 0, count = ippGetCount(urf_sup), ptr = temp; i < count; i ++) { const char *val = ippGetString(urf_sup, i, NULL); if (ptr > temp && ptr < (temp + sizeof(temp) - 1)) *ptr++ = ','; strlcpy(ptr, val, sizeof(temp) - (size_t)(ptr - temp)); ptr += strlen(ptr); } *ptr = '\0'; ipp_txt = avahi_string_list_add_printf(ipp_txt, "URF=%s", temp); } ipp_txt = avahi_string_list_add_printf(ipp_txt, "txtvers=1"); ipp_txt = avahi_string_list_add_printf(ipp_txt, "qtotal=1"); /* * Register _printer._tcp (LPD) with port 0 to reserve the service name... */ avahi_threaded_poll_lock(DNSSDMaster); printer->ipp_ref = avahi_entry_group_new(DNSSDClient, dnssd_callback, NULL); avahi_entry_group_add_service_strlst(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_printer._tcp", NULL, NULL, 0, NULL); /* * Then register the IPP/IPPS services... */ if (!is_print3d) { avahi_entry_group_add_service_strlst(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, SERVER_IPP_TYPE, NULL, NULL, lis->port, ipp_txt); if (subtype && *subtype) { snprintf(temp, sizeof(temp), "%s._sub." SERVER_IPP_TYPE, subtype); avahi_entry_group_add_service_subtype(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, SERVER_IPP_TYPE, NULL, temp); } } # ifdef HAVE_SSL if (Encryption != HTTP_ENCRYPTION_NEVER) { if (is_print3d) { avahi_entry_group_add_service_strlst(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, SERVER_IPPS_3D_TYPE, NULL, NULL, lis->port, ipp_txt); if (subtype && *subtype) { snprintf(temp, sizeof(temp), "%s._sub." SERVER_IPPS_3D_TYPE, subtype); avahi_entry_group_add_service_subtype(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, SERVER_IPP_TYPE, NULL, temp); } } else { avahi_entry_group_add_service_strlst(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, SERVER_IPPS_TYPE, NULL, NULL, lis->port, ipp_txt); if (subtype && *subtype) { snprintf(temp, sizeof(temp), "%s._sub." SERVER_IPPS_TYPE, subtype); avahi_entry_group_add_service_subtype(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, SERVER_IPP_TYPE, NULL, temp); } } } # endif /* HAVE_SSL */ /* * Register the geolocation of the service... */ register_geo(printer); /* * Finally _http.tcp (HTTP) for the web interface... */ avahi_entry_group_add_service_strlst(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, SERVER_WEB_TYPE, NULL, NULL, lis->port, NULL); avahi_entry_group_add_service_subtype(printer->ipp_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, SERVER_WEB_TYPE, NULL, "_printer._sub." SERVER_WEB_TYPE); /* * Commit it... */ avahi_entry_group_commit(printer->ipp_ref); avahi_threaded_poll_unlock(DNSSDMaster); avahi_string_list_free(ipp_txt); #endif /* HAVE_DNSSD */ return (1); } ippsample/server/printer3d-png.h0000644000175000017500000007430713240604116015725 0ustar tilltillstatic const unsigned char printer3d_png[] = { 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x08,0x04,0x00,0x00,0x00,0x69,0x37,0xa9, 0x40,0x00,0x00,0x04,0x0d,0x69,0x43,0x43,0x50,0x49,0x43,0x43,0x20,0x50,0x72,0x6f, 0x66,0x69,0x6c,0x65,0x00,0x00,0x38,0x8d,0x8d,0x55,0x5d,0x68,0x1c,0x55,0x14,0x3e, 0xbb,0x73,0x67,0x23,0x24,0xce,0x53,0x6c,0x34,0x85,0x74,0xa8,0x3f,0x0d,0x25,0x0d, 0x93,0x56,0x34,0xa1,0xb4,0xba,0x7f,0xdd,0xdd,0x36,0x6e,0x96,0x49,0x36,0xda,0x22, 0xe8,0x64,0xf6,0xee,0xce,0x98,0xc9,0xce,0x38,0x33,0xbb,0xfd,0xa1,0x4f,0x45,0x50, 0x7c,0x31,0xea,0x9b,0x14,0xc4,0xbf,0xb7,0x80,0x20,0x28,0xf5,0x0f,0xdb,0x3e,0xb4, 0x2f,0x95,0x0a,0x25,0xda,0xd4,0x20,0x28,0x3e,0xb4,0xf8,0x83,0x50,0xe8,0x8b,0xa6, 0xeb,0x99,0x3b,0x33,0x99,0x69,0xba,0xb1,0xde,0x65,0xee,0x7c,0xf3,0x9d,0xef,0x9e, 0x7b,0xee,0xb9,0x67,0xef,0x05,0xe8,0xb9,0xaa,0x58,0x96,0x91,0x14,0x01,0x16,0x9a, 0xae,0x2d,0x17,0x32,0xe2,0x73,0x87,0x8f,0x88,0x3d,0x2b,0x90,0x84,0x87,0xa0,0x17, 0x06,0xa1,0x57,0x51,0x1d,0x2b,0x5d,0xa9,0x4c,0x02,0x36,0x4f,0x0b,0x77,0xb5,0x5b, 0xdf,0x43,0xc2,0x7b,0x5f,0xd9,0xd5,0xdd,0xfe,0x9f,0xad,0xb7,0x46,0x1d,0x15,0x20, 0x71,0x1f,0x62,0xb3,0xe6,0xa8,0x0b,0x88,0x8f,0x01,0xf0,0xa7,0x55,0xcb,0x76,0x01, 0x7a,0xfa,0x91,0x1f,0x3f,0xea,0x5a,0x1e,0xf6,0x62,0xe8,0xb7,0x31,0x40,0xc4,0x2f, 0x7a,0xb8,0xe1,0x63,0xd7,0xc3,0x73,0x3e,0x7e,0x8d,0x69,0x66,0xe4,0x2c,0xe2,0xd3, 0x88,0x05,0x55,0x53,0x6a,0x88,0x97,0x10,0x8f,0xcc,0xc5,0xf8,0x46,0x0c,0xfb,0x31, 0xb0,0xd6,0x5f,0xa0,0x4d,0x6a,0xeb,0xaa,0xe8,0xe5,0xa2,0x62,0x9b,0x75,0xdd,0xa0, 0xb1,0x70,0xef,0x61,0xfe,0x9f,0x6d,0xc1,0x68,0x85,0xf3,0x6d,0xc3,0xa7,0xcf,0x99, 0x9f,0x3e,0x84,0xef,0x61,0x5c,0xfb,0x2b,0x35,0x25,0xe7,0xe1,0x51,0xc4,0x4b,0xaa, 0x92,0x9f,0x46,0xfc,0x08,0xe2,0x6b,0x6d,0x7d,0xb6,0x1c,0xe0,0xdb,0x96,0x9b,0x91, 0x11,0x3f,0x06,0x90,0xdc,0xde,0x9a,0xaf,0xa6,0x11,0xef,0x44,0x5c,0xac,0xdb,0x07, 0xaa,0xbe,0x9f,0xa4,0xad,0xb5,0x8a,0x21,0x7e,0xe7,0x84,0x36,0xf3,0x2c,0xe2,0x2d, 0x88,0xcf,0x37,0xe7,0xca,0x53,0xc1,0xd8,0xab,0xaa,0x93,0xc5,0x9c,0xc1,0x76,0xc4, 0xb7,0x35,0x5a,0xf2,0xf2,0x3b,0x04,0xc0,0x89,0xba,0x5b,0x9a,0xf1,0xc7,0x72,0xfb, 0x6d,0x53,0x9e,0xf2,0xe7,0xe5,0xea,0x35,0x9a,0xcb,0x7b,0x79,0x44,0xfc,0xfa,0xbc, 0x79,0x48,0xf6,0x7d,0x72,0x9f,0x39,0xed,0xe9,0x7c,0xe8,0xf3,0x84,0x96,0x2d,0x07, 0xfc,0xa5,0x97,0x94,0x83,0x15,0xc4,0x83,0x88,0x7f,0xa1,0x46,0x41,0xf6,0xe7,0xe2, 0xfe,0xb1,0xdc,0x4a,0x10,0x03,0x19,0x6a,0x1a,0xe5,0x49,0x7f,0x2e,0x92,0xa3,0x0e, 0x5b,0x2f,0xe3,0x5d,0x6d,0xa6,0xe8,0xcf,0x4b,0x0c,0x17,0x37,0xd4,0x1f,0x4b,0x16, 0xeb,0xfa,0x81,0x52,0xa0,0xff,0x44,0xb3,0x8b,0x72,0x80,0xaf,0x59,0x06,0xab,0x51, 0x8c,0x8d,0x4f,0xda,0x2d,0xb9,0xea,0xeb,0xf9,0x51,0xc5,0xce,0x17,0x7c,0x9f,0x7c, 0x85,0x36,0xab,0x81,0x7f,0xbe,0x0d,0xb3,0x09,0x05,0x28,0x98,0x30,0x87,0xbd,0x0a, 0x4d,0x58,0x03,0x11,0x64,0x28,0x40,0x06,0xdf,0x16,0xd8,0x68,0xa9,0x83,0x0e,0x06, 0x32,0x14,0xad,0x14,0x19,0x8a,0x5f,0xa1,0x66,0x17,0x1b,0xe7,0xc0,0x3c,0xf2,0x3a, 0xb4,0x99,0xcd,0xc1,0xbe,0xc2,0x94,0xfe,0xc8,0xc8,0x5f,0x83,0xf9,0xb8,0xce,0xb4, 0x2a,0x64,0x87,0x3e,0x82,0x16,0xb2,0x1a,0xfc,0x8e,0xac,0x16,0xd3,0x65,0xf1,0xab, 0x85,0x5c,0x63,0x13,0x3f,0x7e,0x2c,0x37,0x02,0x3f,0x26,0x19,0x20,0x12,0xd9,0x83, 0xcf,0x5e,0x32,0x49,0xf6,0x91,0x71,0x32,0x01,0x22,0x79,0x8a,0x3c,0x4d,0xf6,0x93, 0x1c,0xb2,0x13,0x64,0xef,0xfa,0xd8,0x4a,0x6c,0x45,0x5e,0x3c,0x37,0xd6,0xfd,0xbc, 0x8c,0x33,0x52,0xa6,0x9b,0x45,0xdd,0x39,0xb4,0xbb,0xa0,0x60,0xff,0x33,0x2a,0x4c, 0x5c,0x53,0xd7,0xac,0x2c,0x0e,0xb6,0x86,0x23,0xcb,0x29,0xfb,0x05,0x5d,0xbd,0xfc, 0xc6,0x5f,0xb1,0x5c,0xe9,0x2c,0x37,0x51,0xb6,0xe2,0x19,0x9d,0xba,0x57,0xce,0xf9, 0x5f,0xf9,0xeb,0xfc,0x32,0xf6,0x2b,0xfc,0x6a,0xa4,0xe0,0x7f,0xe4,0x57,0xf1,0xb7, 0x72,0xc7,0x5a,0xcc,0xbb,0xb2,0x4c,0xc3,0xec,0x6c,0x58,0x73,0x77,0x55,0x1a,0x6d, 0x06,0xe3,0x16,0xf0,0xd1,0x99,0xc5,0x89,0xc5,0x1d,0xf3,0x71,0xf1,0xe4,0x57,0x0f, 0x46,0x7e,0x96,0xc9,0x99,0xe7,0xaf,0xf4,0x5d,0x3c,0x59,0x6f,0x2e,0x0e,0x46,0xac, 0x97,0x05,0xfa,0x6a,0xf9,0x56,0x19,0x4e,0x8d,0x44,0xac,0xf4,0x83,0xf4,0x87,0xb4, 0x2c,0xbd,0x27,0x7d,0x28,0xfd,0xc6,0xbd,0xcd,0x7d,0xca,0x7d,0xcd,0x7d,0xce,0x7d, 0xc1,0x5d,0x02,0x91,0x3b,0xcb,0x9d,0xe3,0xbe,0xe1,0x2e,0x70,0x1f,0x73,0x5f,0xc6, 0xf6,0x6a,0xf3,0x1a,0x5a,0xdf,0x7b,0x16,0x79,0x18,0xb7,0x67,0xe9,0x96,0x6b,0xac, 0x4a,0x21,0x23,0x6c,0x15,0x1e,0x16,0x72,0xc2,0x36,0xe1,0x51,0x61,0x32,0xf2,0x27, 0x0c,0x08,0x63,0x42,0x51,0xd8,0x81,0x96,0xad,0xeb,0xfb,0x16,0x9f,0x2f,0x9e,0x3d, 0x1d,0x0e,0x63,0x1f,0xe6,0xa7,0xfb,0x5c,0xbe,0x2e,0x56,0x01,0x89,0xfb,0xb1,0x02, 0xf4,0x4d,0xfe,0x55,0x55,0x54,0xe9,0x70,0x94,0x29,0x1d,0x56,0x6f,0x4d,0x38,0xbe, 0x41,0x13,0x8c,0x24,0x43,0x64,0x8c,0x94,0x36,0x54,0xf7,0xb8,0x57,0xf3,0xa1,0x22, 0x95,0x4f,0xe5,0x52,0x69,0x10,0x53,0x3b,0x53,0x13,0xa9,0xb1,0xd4,0x41,0x0f,0x87, 0xb3,0xa6,0x76,0xa0,0x6d,0x02,0xfb,0xfc,0x1d,0xd5,0xa9,0x6e,0xb2,0x52,0xea,0xd2, 0x63,0xde,0x7d,0x02,0x59,0xd3,0x3a,0x6e,0xeb,0x0d,0xcd,0x15,0x77,0x4b,0xd2,0x93, 0x62,0x1a,0xaf,0x36,0x2a,0x96,0x9a,0xea,0xe8,0x88,0xa8,0x18,0x86,0xc8,0x4c,0x8e, 0x68,0x53,0x87,0xda,0x6d,0x5a,0x1b,0x05,0xef,0xde,0xf4,0x8f,0xf4,0x9b,0x32,0xbb, 0x0f,0x13,0x5b,0x2e,0x47,0x9c,0xfb,0x0c,0xc0,0xbe,0x3f,0xf1,0xec,0xfb,0x2e,0xe2, 0x8e,0xb4,0x00,0x96,0x1c,0x80,0x81,0xc7,0x23,0x6e,0x18,0xcf,0xca,0x07,0xde,0x05, 0x38,0xf3,0x84,0xda,0xb2,0xdb,0xc1,0x1d,0x91,0x48,0x7c,0x0b,0xe0,0xd4,0xf7,0xec, 0xf6,0xbf,0xfa,0x32,0x78,0x7e,0xfd,0xd4,0xe9,0xdc,0xc4,0x73,0xac,0xe7,0x2d,0x80, 0xb5,0x37,0x3b,0x9d,0xbf,0xdf,0xef,0x74,0xd6,0x3e,0x40,0xff,0xab,0x00,0x67,0x8d, 0x7f,0x01,0xa0,0x9f,0x7c,0x55,0x50,0x60,0xfe,0x6f,0x00,0x00,0x02,0xd6,0x69,0x54, 0x58,0x74,0x58,0x4d,0x4c,0x3a,0x63,0x6f,0x6d,0x2e,0x61,0x64,0x6f,0x62,0x65,0x2e, 0x78,0x6d,0x70,0x00,0x00,0x00,0x00,0x00,0x3c,0x78,0x3a,0x78,0x6d,0x70,0x6d,0x65, 0x74,0x61,0x20,0x78,0x6d,0x6c,0x6e,0x73,0x3a,0x78,0x3d,0x22,0x61,0x64,0x6f,0x62, 0x65,0x3a,0x6e,0x73,0x3a,0x6d,0x65,0x74,0x61,0x2f,0x22,0x20,0x78,0x3a,0x78,0x6d, 0x70,0x74,0x6b,0x3d,0x22,0x58,0x4d,0x50,0x20,0x43,0x6f,0x72,0x65,0x20,0x35,0x2e, 0x34,0x2e,0x30,0x22,0x3e,0x0a,0x20,0x20,0x20,0x3c,0x72,0x64,0x66,0x3a,0x52,0x44, 0x46,0x20,0x78,0x6d,0x6c,0x6e,0x73,0x3a,0x72,0x64,0x66,0x3d,0x22,0x68,0x74,0x74, 0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x77,0x33,0x2e,0x6f,0x72,0x67,0x2f,0x31, 0x39,0x39,0x39,0x2f,0x30,0x32,0x2f,0x32,0x32,0x2d,0x72,0x64,0x66,0x2d,0x73,0x79, 0x6e,0x74,0x61,0x78,0x2d,0x6e,0x73,0x23,0x22,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20, 0x20,0x3c,0x72,0x64,0x66,0x3a,0x44,0x65,0x73,0x63,0x72,0x69,0x70,0x74,0x69,0x6f, 0x6e,0x20,0x72,0x64,0x66,0x3a,0x61,0x62,0x6f,0x75,0x74,0x3d,0x22,0x22,0x0a,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x78,0x6d,0x6c,0x6e,0x73, 0x3a,0x64,0x63,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x70,0x75,0x72,0x6c, 0x2e,0x6f,0x72,0x67,0x2f,0x64,0x63,0x2f,0x65,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x73, 0x2f,0x31,0x2e,0x31,0x2f,0x22,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x78,0x6d,0x6c,0x6e,0x73,0x3a,0x70,0x68,0x6f,0x74,0x6f,0x73,0x68, 0x6f,0x70,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6e,0x73,0x2e,0x61,0x64, 0x6f,0x62,0x65,0x2e,0x63,0x6f,0x6d,0x2f,0x70,0x68,0x6f,0x74,0x6f,0x73,0x68,0x6f, 0x70,0x2f,0x31,0x2e,0x30,0x2f,0x22,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x3c,0x64,0x63,0x3a,0x63,0x72,0x65,0x61,0x74,0x6f,0x72,0x3e,0x0a,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x72,0x64,0x66,0x3a, 0x53,0x65,0x71,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x3c,0x72,0x64,0x66,0x3a,0x6c,0x69,0x3e,0x4d,0x69,0x63,0x68, 0x61,0x65,0x6c,0x20,0x53,0x77,0x65,0x65,0x74,0x3c,0x2f,0x72,0x64,0x66,0x3a,0x6c, 0x69,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c, 0x2f,0x72,0x64,0x66,0x3a,0x53,0x65,0x71,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x3c,0x2f,0x64,0x63,0x3a,0x63,0x72,0x65,0x61,0x74,0x6f,0x72,0x3e, 0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x64,0x63,0x3a,0x72,0x69, 0x67,0x68,0x74,0x73,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x3c,0x72,0x64,0x66,0x3a,0x41,0x6c,0x74,0x3e,0x0a,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x72,0x64,0x66,0x3a, 0x6c,0x69,0x20,0x78,0x6d,0x6c,0x3a,0x6c,0x61,0x6e,0x67,0x3d,0x22,0x78,0x2d,0x64, 0x65,0x66,0x61,0x75,0x6c,0x74,0x22,0x3e,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68, 0x74,0x20,0x32,0x30,0x31,0x30,0x20,0x41,0x70,0x70,0x6c,0x65,0x20,0x49,0x6e,0x63, 0x2e,0x3c,0x2f,0x72,0x64,0x66,0x3a,0x6c,0x69,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x72,0x64,0x66,0x3a,0x41,0x6c,0x74, 0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x64,0x63,0x3a, 0x72,0x69,0x67,0x68,0x74,0x73,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x3c,0x70,0x68,0x6f,0x74,0x6f,0x73,0x68,0x6f,0x70,0x3a,0x48,0x65,0x61,0x64, 0x6c,0x69,0x6e,0x65,0x3e,0x4e,0x65,0x77,0x20,0x49,0x6d,0x61,0x67,0x65,0x3c,0x2f, 0x70,0x68,0x6f,0x74,0x6f,0x73,0x68,0x6f,0x70,0x3a,0x48,0x65,0x61,0x64,0x6c,0x69, 0x6e,0x65,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x72,0x64,0x66,0x3a, 0x44,0x65,0x73,0x63,0x72,0x69,0x70,0x74,0x69,0x6f,0x6e,0x3e,0x0a,0x20,0x20,0x20, 0x3c,0x2f,0x72,0x64,0x66,0x3a,0x52,0x44,0x46,0x3e,0x0a,0x3c,0x2f,0x78,0x3a,0x78, 0x6d,0x70,0x6d,0x65,0x74,0x61,0x3e,0x0a,0xef,0xbe,0x80,0x96,0x00,0x00,0x10,0x0a, 0x49,0x44,0x41,0x54,0x78,0xda,0xed,0x9d,0x7b,0x94,0x14,0xd5,0x9d,0xc7,0x3f,0xb7, 0xfa,0x35,0x2f,0x66,0x06,0x11,0x15,0x87,0xa7,0x6e,0x8c,0x11,0x34,0x89,0x51,0x11, 0xd7,0xd5,0x83,0x04,0xc4,0x2c,0x0a,0x9a,0xac,0x72,0x58,0x72,0x50,0xb2,0xba,0xc4, 0x6c,0x1e,0xee,0x89,0x27,0xc7,0xb3,0x89,0x9a,0xa7,0x27,0xc9,0x2e,0xee,0x89,0x39, 0x51,0xd7,0xe7,0x82,0xcf,0xbc,0x34,0xf8,0xc2,0xe5,0x20,0xac,0xca,0x59,0x63,0x36, 0x9b,0x95,0xa0,0x71,0xb3,0xba,0x20,0x30,0x89,0x38,0x40,0x00,0x95,0xc7,0xcc,0x74, 0x7f,0xf7,0x8f,0xae,0xa9,0xae,0x5b,0x8f,0xee,0xea,0x9e,0x9e,0x86,0xc3,0x70,0xfb, 0x4c,0x4f,0x55,0xfd,0x6e,0x57,0xdd,0xfb,0xbb,0xbf,0xc7,0xf7,0xf7,0xbb,0xb7,0xaa, 0x0c,0x56,0xd1,0x38,0xe6,0x33,0x83,0x29,0x8c,0x26,0xcb,0xe1,0x55,0x7a,0xe9,0x61, 0x03,0xab,0x79,0xc4,0x6c,0x89,0xa9,0xa1,0x2e,0x2d,0x53,0xbf,0x0e,0xf7,0xd2,0xaf, 0x65,0xea,0x2a,0xf5,0xda,0x78,0xdd,0x9f,0xcd,0x23,0x74,0x30,0x3c,0xca,0x6e,0xe6, 0x9b,0x95,0xc5,0x4d,0xc7,0xed,0xfe,0x35,0x3c,0x39,0x6c,0xba,0x0f,0x1d,0x3c,0xa9, 0x6b,0x7c,0x12,0xa0,0xd9,0x3c,0x49,0x8a,0xe1,0x55,0xf2,0xcc,0x31,0x2b,0xc1,0x80, 0xba,0x78,0x75,0x18,0x8d,0xbe,0x5f,0x11,0x26,0x9b,0x6e,0x07,0xb8,0x65,0x58,0x76, 0x1f,0x3a,0xb8,0x05,0x8c,0xc6,0xb1,0x71,0xd8,0x89,0x7f,0x49,0x0d,0x26,0x39,0xcc, 0x1f,0xb6,0xdd,0x87,0x14,0xf3,0x1d,0x66,0x30,0x9c,0xcb,0x0c,0xa3,0xad,0x74,0x0d, 0x63,0x06,0x74,0x1b,0x1d,0x38,0xec,0x40,0x6f,0x55,0x00,0xd9,0x48,0xc3,0x5a,0x05, 0x48,0xc7,0x11,0x76,0xb1,0x12,0xb8,0x84,0x96,0xc3,0x9c,0x01,0xb1,0x12,0xf0,0xdf, 0x7c,0x14,0xd8,0xcc,0xb8,0xe1,0x2a,0x01,0x86,0x66,0x7f,0xac,0x34,0xfc,0x24,0x60, 0xb8,0x14,0x07,0x8e,0x30,0x20,0xb2,0xbc,0xc9,0x2c,0x66,0xd1,0xe3,0xee,0xdd,0xcc, 0x2c,0x96,0x02,0xbf,0xe0,0xd3,0x8c,0x61,0x02,0x9f,0x62,0x43,0x44,0xdd,0x6d,0xdc, 0xc4,0x9f,0xd3,0xce,0x34,0x6e,0xa1,0xe0,0xa3,0x3f,0xc7,0x85,0x1c,0x4f,0x8e,0x89, 0x9c,0xcb,0x53,0xbe,0xe3,0x9b,0xb8,0x8a,0x53,0x68,0xe1,0x2c,0xbe,0x65,0xd5,0x1f, 0xb8,0xda,0x83,0xcc,0xa3,0x9d,0x1f,0x32,0x8b,0x0b,0xd9,0x6e,0xb5,0xee,0x0e,0x66, 0x71,0x9b,0xb7,0x77,0x27,0x33,0x19,0xc9,0x58,0xe6,0xb1,0x3e,0xa2,0x55,0x6f,0x71, 0x3d,0x93,0x39,0x2d,0xae,0xa3,0x71,0x89,0x93,0xdf,0x08,0xa1,0xcd,0xee,0xde,0x5c, 0xa1,0xc5,0x7a,0x40,0x46,0xb8,0x9f,0x36,0x3d,0x13,0xa8,0xfb,0xaa,0x4e,0xf7,0xa8, 0xe8,0x22,0xf5,0xba,0xd4,0x47,0x85,0xd0,0x48,0x9d,0xad,0x4e,0xa1,0xa5,0xde,0xaf, 0xfe,0x4d,0x47,0x09,0x7d,0x40,0xd3,0xd4,0x22,0x34,0xdb,0x97,0x8c,0x2a,0x5e,0xed, 0x0e,0xf7,0x4c,0x0f,0x6b,0xa2,0xd0,0x6d,0xbe,0xb6,0xe5,0x35,0x56,0x68,0xad,0x24, 0x69,0xaf,0x2e,0x17,0x1a,0xa1,0x73,0x74,0x82,0x50,0xab,0x9e,0x0d,0xb4,0xea,0x15, 0x9d,0x2c,0x84,0x4e,0x8e,0xe9,0x67,0x15,0x0c,0x98,0xac,0xac,0x96,0x68,0x8d,0x76, 0xea,0x19,0x8d,0x11,0x9a,0xe0,0x75,0xb1,0x58,0xf7,0xa3,0x3a,0x51,0x77,0xeb,0x2d, 0xbd,0xa1,0xcf,0x0a,0xa1,0x3b,0x5d,0xea,0x24,0xa1,0xeb,0x54,0x90,0x24,0x6d,0xf2, 0xce,0xb8,0x43,0x9d,0x42,0x0f,0x48,0x92,0x36,0xeb,0x44,0xa1,0x07,0x2d,0x06,0x9c, 0xa2,0xb4,0x16,0x6b,0xb5,0x76,0x6a,0x97,0x6e,0x14,0x3a,0xc3,0xd7,0xb6,0xa7,0x85, 0x4e,0x72,0xb7,0x6f,0x14,0x9a,0xa6,0x1e,0x49,0xd2,0xb7,0x85,0x3e,0xa8,0xbc,0xd5, 0xaa,0x0f,0xeb,0x04,0xdd,0xa6,0x2d,0xda,0x3a,0x78,0x06,0xe4,0xb4,0xdc,0xa3,0xae, 0x11,0x42,0xf7,0x59,0x75,0xcf,0xd3,0x76,0x8f,0x7e,0xbe,0xd0,0x44,0x49,0xd2,0x01, 0x39,0x42,0xab,0x42,0xe7,0xff,0x92,0xd0,0x5c,0x6f,0xef,0x4e,0xa1,0xd3,0x2d,0x06, 0xa0,0xeb,0xbc,0xfd,0x37,0x5c,0x09,0x1b,0x28,0x97,0x09,0x7d,0x4f,0x92,0xd4,0xad, 0x16,0xa1,0xdf,0x78,0xe9,0xbe,0x71,0x42,0x2b,0xac,0x56,0x1d,0xad,0x37,0xca,0xa6, 0x08,0xab,0x60,0xc0,0x95,0x16,0x7d,0xbc,0xd0,0xb5,0x56,0xdd,0x4d,0x3e,0xea,0x3d, 0x42,0xe8,0x1d,0x49,0xd2,0x74,0xa1,0xb3,0xf4,0xbf,0x81,0xf3,0x77,0x09,0xdd,0xee, 0xed,0xfd,0x4a,0x28,0xe3,0x8d,0xdd,0x5c,0xa1,0x73,0xbd,0x3d,0x49,0x3a,0x57,0xe8, 0x2b,0xee,0xf6,0x36,0x65,0x94,0xd1,0x36,0x49,0xd2,0x5d,0x42,0xc7,0xfa,0xea,0xfd, 0xa5,0xd0,0x37,0xad,0x56,0x3d,0x5b,0x21,0x47,0x9a,0xae,0xd5,0x5e,0x9e,0xc0,0x66, 0x36,0xc5,0xd2,0x4f,0x74,0x8d,0xdc,0x68,0xe0,0xf3,0xbc,0xc0,0xcb,0x9c,0xca,0x02, 0xae,0xe7,0x64,0x97,0xfe,0x3e,0xdd,0xc0,0x9d,0xfc,0xd4,0xdd,0xdf,0x07,0xf4,0xf1, 0x36,0xc7,0x7b,0x67,0x38,0xc9,0x3a,0xdf,0x22,0x5e,0xe4,0x01,0xbe,0x83,0x03,0x2c, 0xa3,0x8f,0x4f,0x71,0x0c,0x00,0xbf,0x07,0xf6,0xf1,0x71,0xaf,0xde,0xab,0xc0,0x66, 0xab,0x55,0x1f,0xaa,0x15,0x08,0x55,0x2a,0x23,0x81,0x3d,0x65,0xa9,0x03,0xf4,0x4b, 0xf9,0x0f,0x16,0xf1,0x1a,0xf7,0x72,0x3f,0x57,0x71,0x1b,0xcd,0xc0,0x16,0x17,0x6d, 0xda,0xa5,0xc7,0xc7,0x00,0xbb,0x5c,0xce,0x17,0xe8,0x66,0x35,0x33,0x81,0x7b,0x80, 0xab,0xdd,0xe3,0x9b,0x81,0x3d,0xac,0x0e,0x9c,0xa5,0x21,0x38,0x60,0x27,0x30,0xa1, 0x2c,0xb5,0x44,0x3f,0x83,0xff,0xe2,0x2e,0x4e,0xa2,0xc0,0x3d,0x2c,0x04,0x70,0x23, 0xf0,0x67,0x91,0xf5,0xf9,0x70,0xec,0xf9,0xda,0xb9,0x14,0x58,0x06,0xac,0xe3,0x75, 0x26,0x32,0xd3,0x3d,0x3e,0x16,0x98,0x16,0x38,0xcb,0x63,0x8d,0x61,0x40,0x37,0x70, 0x42,0x59,0xaa,0xe3,0x63,0x50,0x8e,0xbf,0x61,0x3d,0x7f,0x07,0xac,0x60,0x3b,0x30, 0x82,0x71,0xc0,0x8b,0x55,0x5c,0x6f,0x11,0xf0,0x73,0xde,0xe5,0x6e,0xe0,0x33,0x1e, 0x44,0x3f,0x05,0xf8,0x35,0xfb,0x1b,0x83,0x04,0xfd,0x98,0xf9,0xb7,0xbc,0x01,0x5c, 0x18,0x4b,0xff,0x39,0x70,0x01,0x19,0x8b,0x9e,0xe3,0x16,0xd2,0xf4,0xb3,0x06,0x80, 0x8b,0x80,0x7b,0xcb,0x28,0x51,0xb0,0x7c,0x9c,0x2e,0xf6,0x72,0x1f,0x3f,0x21,0xc5, 0x62,0xef,0xe8,0x74,0x72,0xf4,0xf2,0xa3,0xc1,0x40,0xc1,0xe4,0x5e,0xa0,0x59,0x3f, 0x70,0xbd,0xf9,0x3e,0xcd,0x16,0x9a,0x11,0xa8,0x7b,0xae,0xde,0x74,0xf7,0x57,0x29, 0x23,0xf4,0x82,0x24,0xa9,0x47,0xbf,0xf0,0x20,0xce,0xe3,0x42,0x68,0xbd,0x24,0x69, 0xbb,0x8e,0x16,0xba,0x54,0x7f,0xf2,0xce,0xf2,0x07,0xed,0xb7,0x80,0x50,0xb0,0x7c, 0x45,0xa8,0x59,0xe8,0x12,0xeb,0xe8,0xcd,0x42,0xad,0x7a,0xca,0xdb,0xef,0xf5,0x3c, 0xbe,0xdd,0x83,0x3a,0xb8,0xc1,0xb1,0x4a,0x69,0xb2,0xbe,0xa8,0x2f,0x6b,0xb2,0xd0, 0x31,0x7a,0x25,0x50,0x77,0xa2,0x5a,0x35,0x4f,0x37,0x6b,0xbe,0xb2,0x42,0x4b,0x5c, 0xda,0xff,0x08,0x75,0x69,0xa1,0x6e,0xd6,0x27,0xd5,0x22,0x34,0xdf,0xfb,0xd5,0x13, 0x6a,0x17,0x3a,0x56,0x7f,0xad,0xaf,0xe9,0x72,0x8d,0x17,0x9e,0xc7,0x8e,0x66,0xc0, 0x6b,0xae,0x92,0x3f,0x61,0x1d,0xdd,0xaf,0x4f,0x08,0xa1,0xf3,0xf5,0x25,0x5d,0xa7, 0x73,0xd4,0xa4,0x85,0x43,0xc5,0x80,0xc5,0x5a,0xa3,0x89,0x42,0xc8,0xd1,0x39,0x96, 0xd7,0x2f,0xd6,0x7d,0x5d,0x9f,0x51,0xd6,0x85,0xbd,0xdf,0xf7,0x68,0xdb,0x74,0x99, 0xfb,0x2b,0xd4,0xa2,0x1b,0xb4,0xd7,0xf7,0xbb,0xb7,0x74,0x91,0x72,0x2e,0x6d,0xbc, 0xe6,0xb8,0xb8,0x21,0x8e,0x01,0xd2,0x59,0x42,0x5d,0x11,0xf3,0xb7,0x77,0xa8,0xcb, 0xbb,0xc2,0x99,0xfa,0x51,0x7d,0x18,0x60,0x97,0x52,0x93,0xb6,0xea,0x05,0xed,0x8e, 0x65,0xd6,0x7e,0xbd,0xac,0xd7,0x5d,0x45,0xf1,0x97,0x9d,0x7a,0x5e,0xeb,0xad,0xce, 0x0f,0x94,0x3e,0x6d,0xd0,0x3a,0xed,0x1a,0xf4,0xa4,0x6f,0x8f,0xfe,0x5d,0xbf,0xb7, 0xc0,0x53,0xb2,0x52,0x35,0x0e,0xe8,0x2a,0x9b,0x44,0xce,0x71,0x66,0x0c,0x2e,0xf8, 0x8b,0x58,0x20,0x32,0xb9,0x2e,0x61,0xed,0xd1,0x9c,0x77,0x24,0x1f,0x70,0x84,0x01, 0xf5,0xcc,0x09,0xda,0x65,0x3a,0x9d,0x9c,0x13,0x4b,0x3d,0x8a,0x45,0x40,0xeb,0x91, 0x9c,0xe0,0x00,0x20,0x5a,0xcb,0x1c,0xf6,0x5a,0xc7,0x5a,0xb8,0x81,0xeb,0xc9,0x0d, 0x07,0x15,0x10,0x6b,0xb9,0x82,0xc7,0xd9,0xc3,0x6e,0xef,0xb3,0x87,0x5f,0xf3,0x9f, 0x9c,0xca,0x33,0xe8,0x70,0x97,0x80,0x02,0x6b,0x99,0xcf,0xbf,0x72,0x3a,0x79,0xab, 0xb3,0x29,0xd2,0xac,0xe3,0x7a,0xa6,0xb0,0x94,0x09,0x87,0x54,0xb2,0xbd,0xae,0x0c, 0x10,0xfd,0x74,0xf2,0x13,0x4e,0xa5,0x0f,0x79,0xb3,0x0a,0xc5,0xad,0x14,0x19,0x0c, 0x77,0x71,0x2b,0x6f,0x31,0xe2,0x10,0x62,0x81,0x53,0xcf,0xee,0xe7,0xe9,0x65,0x2f, 0x53,0xe8,0x05,0xd2,0x64,0xc9,0x92,0x73,0xff,0x1c,0x0a,0x1c,0xa0,0x8f,0x6b,0xf8, 0x08,0x6b,0x29,0x1c,0x42,0xaa,0x90,0xae,0x2f,0x03,0x0e,0x00,0x7d,0xa4,0xc8,0x92, 0x23,0xed,0x49,0x40,0x81,0x3c,0x7d,0xf4,0xd2,0x4f,0x9e,0xf3,0x59,0xc5,0x2c,0xb2, 0x87,0x8c,0x0c,0xa4,0xeb,0xab,0x00,0x7d,0x80,0x21,0x4b,0x2b,0x39,0x52,0xae,0x12, 0x08,0x91,0xa7,0x8f,0x34,0xfb,0xe9,0xe3,0x6c,0xfe,0x9e,0x3e,0xd2,0x87,0x0c,0x00, 0xa9,0x4b,0x3b,0xde,0xf1,0x8d,0x34,0xa4,0xc8,0x91,0x23,0x4b,0x86,0x0c,0x69,0xd2, 0x64,0xc8,0x90,0xa3,0x99,0x16,0x9a,0x49,0xf3,0x01,0x7a,0xd8,0x12,0x30,0x91,0x43, 0x59,0xde,0xa9,0x35,0x1f,0x90,0xb4,0x6c,0xd4,0x42,0xa5,0x35,0x46,0x8e,0x38,0x64, 0x3e,0x8e,0xc6,0xe8,0x6a,0x6d,0xd4,0x46,0x2d,0x51,0x73,0x44,0x68,0x56,0x43,0x34, 0x18,0x5d,0x36,0x68,0x81,0x5a,0x35,0xe1,0x90,0xea,0x7c,0xf8,0x73,0xb5,0x5e,0x2b, 0xc3,0x84,0x1a,0xdd,0xa0,0x78,0x99,0x6f,0xf1,0x3c,0x9d,0xec,0x62,0x06,0x33,0x69, 0xb7,0x68,0xc6,0x75,0x7d,0x8a,0x34,0x75,0x3b,0xf8,0x07,0x6e,0x1f,0x42,0x23,0x58, 0xbc,0xfe,0xef,0x78,0x82,0x4d,0x4c,0x67,0x05,0x3b,0x68,0x26,0x1b,0xbb,0x14,0x2e, 0x5d,0xcb,0x05,0x56,0xf3,0x0d,0xd6,0xd3,0x44,0x1b,0x17,0x73,0x01,0x99,0x98,0x0e, 0xc7,0x31,0xa2,0x9d,0x4e,0x7a,0xf8,0xb3,0xd8,0xfa,0x1e,0x44,0x71,0xe9,0xc1,0xe3, 0x71,0xf4,0x81,0xfd,0x3c,0xeb,0xf8,0x31,0xbd,0xcc,0xe4,0x73,0x64,0x58,0xc1,0x1e, 0x1c,0x52,0x38,0x31,0x2c,0x4f,0x57,0xdb,0xf9,0xc7,0xb9,0x89,0x6e,0xf2,0x8c,0xe7, 0xaf,0x98,0x1a,0x79,0x52,0x55,0x64,0xc8,0x19,0xfc,0x96,0x29,0x43,0x32,0xfa,0xef, 0xf3,0x34,0x3f,0xe3,0x18,0xe6,0xf2,0x11,0x0f,0x88,0xbd,0x47,0x6b,0x19,0x93,0x5b, 0x05,0x03,0xfa,0x79,0x90,0xaf,0xf3,0x1e,0x7b,0x99,0xc6,0x42,0x6f,0x8e,0xa7,0xda, 0x91,0x3a,0xdb,0x3d,0x7a,0x1f,0x00,0x2f,0x55,0x03,0x5a,0x63,0xae,0x33,0x70,0xfc, 0x6d,0x1e,0xe4,0x29,0x4e,0xe3,0x0b,0x4c,0xb2,0x6a,0xf5,0x95,0xf5,0x38,0x09,0x19, 0xb0,0x97,0x7b,0xf9,0x06,0x29,0xde,0x63,0x1e,0x0b,0x39,0x2e,0x72,0xa4,0x2b,0x8d, 0x7c,0x74,0x06,0xa9,0xb2,0xea,0x28,0x81,0x8a,0xbd,0xce,0x5d,0xfc,0x92,0xf3,0xf8, 0x26,0xa3,0x3c,0xff,0x2e,0xcf,0xc7,0x1b,0x4c,0xac,0xcd,0x49,0xc0,0x80,0x5d,0x2c, 0x65,0x29,0x2d,0x18,0x16,0x73,0x05,0x23,0xea,0x2a,0xb2,0x1d,0x55,0xe8,0x76,0x34, 0x23,0xc5,0x73,0xfc,0x90,0x2d,0xcc,0xe6,0x56,0x9a,0x2c,0x36,0x19,0x8f,0x15,0xa6, 0x8c,0xc9,0xad,0xc0,0x80,0x6d,0x7c,0x9f,0xdb,0xc8,0x32,0x86,0xeb,0x98,0xe3,0x56, 0xae,0x76,0xc4,0xca,0x79,0x85,0x5c,0x95,0x12,0x63,0x5f,0x7f,0x3f,0x3f,0xe5,0x07, 0xa4,0x98,0xc3,0x54,0x1c,0xef,0x57,0x26,0x54,0xbf,0x46,0x06,0x88,0x6d,0x4c,0x22, 0xcd,0xd9,0xdc,0x10,0x9b,0xd2,0xa4,0x0a,0xab,0x9d,0x54,0x02,0x92,0x95,0x1e,0x6e, 0xe7,0x4e,0x26,0x71,0xa5,0x6f,0xfe,0xd7,0x94,0x71,0xbe,0x55,0x33,0xe0,0x77,0xdc, 0xca,0x72,0xf6,0x03,0xcf,0xf3,0xfc,0x90,0xf9,0xec,0xb6,0x9a,0x7f,0x99,0xc3,0xf0, 0xed,0xc8,0xd9,0xe4,0xea,0x10,0x46,0x0c,0x10,0x2a,0xd0,0xcf,0x7e,0xde,0x65,0x2c, 0xa7,0x71,0x9d,0x3b,0xaa,0x51,0xee,0xce,0xfe,0x6e,0x2c,0xfd,0x2a,0x1e,0x4d,0xa0, 0x78,0x57,0xf0,0x0a,0x5d,0x74,0xc4,0x8e,0x74,0x3a,0x5a,0xf8,0x0b,0xf4,0xb1,0x97, 0x9d,0x34,0x33,0x1d,0xe3,0xda,0x54,0x13,0x10,0x6e,0x07,0x59,0xdf,0x8d,0xa6,0x17, 0x23,0x39,0xf9,0x6a,0x38,0x3e,0x09,0x30,0x09,0x65,0x21,0x5d,0x2e,0xb6,0x7f,0x9f, 0x03,0x4c,0xb1,0x40,0xa4,0xac,0xf0,0x31,0x3c,0x2e,0x8d,0xa5,0x1b,0xab,0xa3,0x26, 0x12,0x8e,0xd5,0xc8,0x00,0xe3,0x5a,0x55,0x91,0xb1,0x4e,0x6c,0x02,0x46,0xaf,0x9c, 0xfe,0x0d,0x35,0x7d,0x40,0x02,0xe2,0xe0,0xd7,0x20,0x24,0xc0,0xe0,0xb8,0x71,0xbc, 0x43,0xc1,0xbd,0xcc,0x40,0x72,0x03,0x9f,0xae,0x39,0xde,0x18,0x1d,0x0c,0xba,0x0d, 0x78,0x92,0xa1,0x86,0xc4,0x12,0xe0,0xe0,0x90,0x26,0x8d,0x71,0x57,0x70,0x0e,0x5c, 0x62,0xc1,0x41,0xcf,0xe0,0x3c,0x8c,0x30,0x6e,0xe7,0x86,0xd0,0x06,0x14,0x59,0xe0, 0x60,0x5c,0x09,0x28,0x9d,0x78,0x85,0x8f,0xd3,0x03,0xfc,0xbe,0x98,0x27,0x13,0x04, 0xa8,0xc9,0xa0,0x51,0xf9,0x80,0x7a,0x8e,0x07,0x6a,0x4c,0xe8,0xaf,0x3a,0x38,0x95, 0x10,0x09,0x3a,0x14,0x48,0xf9,0x1a,0x54,0xe4,0xba,0xf1,0xe9,0xa8,0x93,0xc0,0xf7, 0x06,0x1b,0xa9,0x58,0xd4,0x56,0xa9,0x3e,0x6e,0x58,0x2b,0xaf,0x2d,0x71,0xe7,0x72, 0x02,0x06,0xb3,0x46,0x06,0x18,0x0a,0x2e,0xcf,0x4d,0x84,0x19,0x72,0x3c,0xb6,0xa4, 0xea,0x22,0x01,0xe1,0x7a,0x41,0xf1,0x26,0x52,0xcc,0xe3,0xd9,0x58,0x87,0xac,0x70, 0xc1,0xd3,0xb8,0x28,0xcb,0x6b,0x12,0x5d,0xac,0x64,0xa8,0x4a,0x2c,0x33,0x56,0x47, 0xa2,0x25,0x23,0xca,0xc5,0x39,0xbe,0xb6,0xd4,0x23,0xab,0x54,0x51,0x02,0xf2,0x9e, 0xb0,0xf9,0x11,0xbf,0x9f,0xef,0x0a,0x34,0x2b,0x6a,0xa4,0xab,0xeb,0x70,0x79,0x49, 0x29,0xf9,0x86,0x54,0x8d,0x41,0x78,0x95,0x0c,0x70,0x42,0xb1,0x95,0xcd,0x7d,0xe3, 0x1d,0x0d,0x76,0x28,0xce,0x32,0x47,0x89,0x76,0x94,0xf8,0x06,0x19,0xa7,0x50,0x9c, 0x1f,0x0f,0x84,0x06,0xed,0x05,0xfc,0xd8,0xcb,0xcf,0x5d,0xdb,0x24,0xfa,0x4d,0x63, 0xf5,0xf1,0x61,0x52,0x9f,0x5d,0xaa,0x37,0x70,0x7d,0x2c,0x2c,0x50,0x3e,0x68,0x1e, 0xb4,0x11,0x74,0xbc,0xce,0x96,0xc6,0x3a,0xa8,0xfb,0x4e,0x0c,0x0c,0x35,0x91,0x16, 0x39,0xa8,0x1a,0x95,0x46,0xab,0x24,0x31,0x25,0x59,0x73,0x2a,0xcc,0xea,0x28,0xa0, 0x96,0x35,0x4b,0x40,0xbf,0xaf,0xb3,0x26,0xe0,0x02,0xe3,0x2c,0xae,0x89,0x3c,0x12, 0x45,0x37,0x89,0xfc,0x7f,0x98,0xe5,0xa6,0x22,0xd3,0xea,0xa6,0x02,0x05,0x2f,0x12, 0xc3,0x17,0x17,0x12,0x80,0xa4,0x4e,0x42,0x11,0x2e,0x2f,0xea,0x41,0x6f,0x11,0xa5, 0x02,0x8e,0x0f,0x86,0x39,0x55,0xa6,0x5f,0x06,0xe5,0x06,0x9d,0x50,0x10,0x1a,0xc4, 0x04,0xe5,0xf0,0x78,0x32,0x2b,0x1f,0x74,0x93,0x61,0x3c,0x10,0x36,0xc2,0x43,0x14, 0x0b,0xd8,0x81,0x11,0xbe,0x58,0xdc,0xf1,0x29,0x40,0xe9,0x12,0xa9,0xc4,0x23,0xbe, 0x83,0xfb,0xf9,0x25,0x3d,0xc0,0x68,0xa6,0x72,0x15,0x47,0x55,0x95,0x18,0x2f,0x01, 0x21,0xc5,0x80,0xa2,0xba,0xc5,0x02,0x84,0x12,0x13,0x25,0x15,0xf0,0x27,0x28,0x8c, 0x85,0x09,0xa3,0x47,0xd2,0x5f,0x2e,0xe6,0x72,0xbe,0xca,0xf1,0xc0,0x1f,0x78,0x8e, 0xcf,0xf3,0x70,0x82,0x39,0x21,0x5b,0x05,0xa2,0x75,0xbc,0x96,0x8c,0x64,0x42,0x37, 0x68,0x02,0x5e,0x3f,0xc8,0x61,0x45,0x42,0xd3,0x78,0xee,0x77,0x32,0x9e,0x09,0x18, 0x52,0x74,0xb2,0x31,0xa6,0x7e,0xa5,0x51,0x8d,0x8f,0x05,0x82,0x2a,0x51,0x17,0x09, 0xc0,0x77,0x89,0x54,0x48,0xfc,0x4d,0x24,0x3c,0x8a,0x2f,0x1b,0xb9,0x86,0xed,0xc0, 0xd1,0x7c,0xa8,0x06,0x38,0x6b,0x7c,0x92,0xe7,0xd4,0x21,0x37,0x9d,0x70,0x66,0xc8, 0xb1,0x64,0xc1,0x58,0xc9,0x29,0x79,0x6c,0x49,0x06,0x3e,0xae,0xf1,0x6d,0xaf,0x4a, 0x04,0x67,0xfd,0xc7,0x9d,0x50,0x3e,0xa0,0x72,0x00,0x35,0x48,0x23,0x98,0xb2,0x52, 0x54,0xe5,0xa0,0x70,0xb2,0xf1,0x6c,0x0a,0x09,0x6e,0x65,0x38,0x6b,0xac,0xa1,0x08, 0xa6,0x4e,0x9d,0x0a,0x01,0x54,0x5d,0x71,0x80,0x09,0x18,0x25,0x13,0x11,0x0c,0x95, 0xc3,0x03,0x58,0x6b,0x09,0xca,0x1b,0xb2,0xb0,0x44,0x44,0xa9,0xc0,0xe0,0x62,0xc2, 0x74,0x25,0x13,0x18,0x44,0x5d,0x7e,0x2f,0x60,0x42,0x12,0x40,0xd9,0xcc,0x6c,0xb1, 0x4e,0xbb,0xd5,0xb5,0xf2,0x86,0xcc,0xf6,0x2e,0x76,0x42,0x86,0x48,0x78,0x5d,0x77, 0x20,0xa4,0x90,0x58,0x46,0x0b,0x58,0x94,0xee,0x86,0xf5,0xd0,0xb8,0x2a,0x10,0x97, 0xda,0x8e,0xf6,0x02,0x7e,0xb7,0xea,0x84,0x40,0x78,0xd0,0x36,0x99,0x2a,0xec,0x51, 0x22,0x1b,0x60,0x67,0xdc,0x4c,0x40,0xa0,0x8b,0xdf,0x69,0xfe,0x8f,0xfb,0x79,0x82, 0xde,0x04,0x97,0xb4,0xe7,0x03,0x4f,0xab,0x7a,0xcc,0x1c,0x0b,0x94,0x25,0x8d,0x33, 0x06,0x21,0x01,0xa9,0x98,0x5c,0xbc,0x9f,0xef,0x9f,0x65,0x3d,0x17,0xf0,0xcf,0x09, 0xd6,0x0a,0x2d,0x0c,0xac,0x19,0x7f,0xa0,0xaa,0xce,0x2f,0xb4,0x5a,0x63,0x06,0x01, 0x80,0xaa,0x70,0x83,0x76,0x16,0x27,0xe5,0xf3,0xff,0xa2,0x9f,0x55,0xdc,0xcb,0x28, 0x4e,0xe5,0x8b,0x89,0xd7,0x0a,0xd9,0x12,0xd0,0x5e,0xd5,0x5a,0x21,0x3b,0x18,0x32, 0x65,0xb2,0x4d,0x75,0x64,0x80,0xe3,0x35,0xcb,0x58,0x29,0xa9,0x77,0xf9,0x19,0xcb, 0x38,0x8e,0x05,0x55,0xae,0x15,0xba,0x96,0x79,0x4c,0xc0,0xb0,0x91,0xc7,0x43,0x16, 0x21,0x19,0x10,0xb2,0xf3,0x01,0x71,0xd9,0xa3,0x3a,0x01,0xa1,0x54,0x00,0xf6,0x14, 0xff,0xbf,0xcd,0x72,0x1e,0x63,0x2a,0xdf,0xad,0x7a,0xad,0xd0,0xd3,0xdc,0xcf,0xe7, 0x78,0x1b,0x38,0x8e,0x33,0x79,0x9a,0x8e,0x2a,0x85,0xd7,0xdf,0xc9,0x54,0x19,0x79, 0xa9,0x9b,0x04,0x38,0xbe,0x0c,0x40,0xf1,0x02,0xaf,0x72,0x1f,0x2f,0x72,0x09,0x8f, 0xd6,0xb4,0x56,0x68,0x0c,0x37,0x24,0xf6,0xfa,0xe1,0xf3,0x86,0xb3,0xc2,0x95,0x92, 0x2f,0x83,0x4e,0x89,0xa5,0x7c,0x30,0x18,0x60,0x11,0x5b,0x58,0xcc,0x77,0xea,0xb0, 0x56,0xa8,0x96,0x75,0x80,0x84,0x66,0x87,0x87,0x38,0x2d,0x3e,0xa0,0x02,0x25,0xd7, 0xb3,0xa8,0x6e,0x6b,0x85,0x2a,0x09,0xaf,0x12,0xcc,0x1f,0x37,0x20,0x18,0x72,0x02, 0xc1,0xc5,0xa2,0x41,0x8f,0xec,0xe0,0x8a,0x63,0x01,0xad,0xf8,0x64,0x68,0x9d,0x12, 0x22,0xc6,0x95,0x80,0xd2,0xe9,0xda,0x38,0xb8,0x65,0xc0,0xf7,0x3b,0xb1,0x12,0x40, 0x7d,0x8d,0xa0,0xf1,0x99,0x1d,0x03,0x6c,0x8c,0xa8,0x33,0x89,0xad,0x83,0xcc,0xf7, 0x27,0x9d,0x37,0x18,0xeb,0x05,0x43,0x54,0xcc,0x2f,0xd6,0x49,0x05,0xd2,0xde,0x3a, 0x3b,0x85,0xd2,0xe2,0xf6,0x7c,0x4d,0xf2,0x98,0xbc,0xd2,0x94,0x59,0x78,0x3e,0xa0, 0x74,0x9e,0x54,0xa3,0xd6,0x07,0xf8,0x6d,0x40,0x38,0x23,0xef,0x8f,0xd3,0xc2,0xb9, 0xda,0x38,0x50,0x12,0x8c,0x28,0x4c,0x0c,0x9a,0x0b,0x07,0x53,0xf1,0x29,0xb9,0x6a, 0xb1,0x7f,0xd5,0x36,0xc0,0xf1,0x79,0x00,0x2c,0xf4,0x65,0x02,0x21,0x71,0xe5,0x49, 0x8a,0x7a,0xac,0x0f,0x88,0x4b,0xc5,0x0f,0xa1,0x1b,0xb4,0x63,0xf0,0x83,0xbd,0x3e, 0xc0,0x04,0x16,0x48,0x34,0x00,0x07,0x38,0x56,0x5e,0xc0,0x9f,0x09,0x2c,0xe1,0xb2, 0x46,0xae,0x0f,0x60,0x90,0x42,0x5f,0x13,0x12,0x34,0x11,0x70,0xc5,0x5e,0x28,0xd3, 0xa8,0xf5,0x01,0x4e,0x4c,0x36,0x69,0x88,0xd6,0x07,0x40,0x26,0x20,0x68,0x29,0x5f, 0x3e,0x40,0x81,0x89,0xd3,0xc3,0x72,0x7d,0x40,0x26,0x94,0xff,0x95,0xd7,0x08,0x13, 0x52,0x8c,0xc1,0xfa,0xf9,0x4a,0x78,0xc1,0xce,0x3e,0x36,0x24,0x16,0xc8,0x78,0x36, 0xa0,0x78,0xc1,0xd1,0x09,0xd2,0x5c,0x43,0x8b,0x04,0x4d,0xd9,0x65,0x19,0x75,0x9e, 0x1a,0x93,0x7b,0x97,0xef,0x80,0xd8,0xfd,0x31,0x22,0x67,0x1c,0x95,0x3a,0x1d,0x5a, 0xba,0xdf,0x23,0x85,0x17,0x50,0xab,0x2a,0xef,0x50,0x51,0x02,0x72,0xd6,0xa2,0x98, 0xe8,0x18,0xfd,0xe0,0xd0,0x1b,0x92,0x0f,0x28,0x2e,0x96,0x36,0x96,0x31,0xf3,0x5b, 0xf2,0xd2,0x77,0xe3,0xe9,0x0d,0x89,0x05,0x44,0x53,0xac,0x3d,0x35,0x01,0x30,0xd4, 0x68,0x7a,0x43,0x62,0x01,0x91,0xb1,0x02,0x1d,0x7b,0xab,0xe4,0x13,0x0e,0x0e,0x3d, 0x55,0x61,0xe4,0x77,0xf2,0x4f,0x34,0x27,0x4a,0xf9,0x56,0x54,0x01,0xc7,0x8d,0x09, 0x8d,0x97,0x8d,0x35,0x6e,0x98,0x64,0x0e,0x1a,0x1d,0xef,0x98,0x7f,0xf2,0xce,0x71, 0x03,0xb8,0x7d,0xfc,0x23,0x53,0xd8,0xca,0xdd,0x65,0xef,0x19,0x4b,0xa4,0x02,0x29, 0xb0,0xd6,0x04,0x84,0x0d,0xd2,0xc1,0xa1,0xc7,0x1b,0xc1,0x5e,0xee,0xe6,0xbb,0xe4, 0x59,0xc2,0x07,0x19,0x59,0xe1,0x61,0x0d,0x15,0x18,0x50,0x70,0xdf,0xbe,0xe0,0x5f, 0x1f,0x10,0x34,0x4b,0x3a,0x48,0xf4,0x68,0x1d,0xcf,0xf3,0x10,0x5f,0x45,0x4c,0xe5, 0x5c,0xda,0x69,0xa7,0x8d,0x26,0x37,0xab,0x55,0x33,0x03,0xe2,0x81,0xa7,0x42,0x71, 0x62,0x63,0xe9,0xe1,0xfb,0x04,0x1e,0xe3,0xeb,0x8c,0x62,0x09,0xad,0xe4,0x68,0xa5, 0x93,0xd1,0x8c,0xa2,0x2d,0x70,0xdb,0x4f,0x0d,0x0c,0x90,0x05,0x4a,0xa3,0x26,0xcd, 0x0e,0x0e,0xdd,0x4e,0x96,0xac,0xe2,0x26,0x0a,0x5c,0x46,0x27,0x59,0x9a,0x68,0xa5, 0x83,0x51,0x8c,0x62,0x24,0x2d,0x83,0x61,0x80,0x61,0x3f,0x59,0x9f,0x19,0x91,0x15, 0xf6,0x84,0xf1,0x79,0x23,0xe9,0x7e,0x09,0x78,0x89,0xaf,0xf1,0x47,0xe6,0x32,0x9a, 0x26,0x9a,0x69,0xa5,0x95,0x76,0x3a,0xe8,0xa4,0x9d,0x66,0xb2,0xb1,0xcf,0x0e,0x48, 0xc0,0x80,0x26,0x7e,0xcc,0xdf,0x86,0x02,0x93,0x4a,0x49,0xf1,0x46,0xd1,0x8b,0xdd, 0xda,0xc0,0x4d,0xac,0xe7,0x32,0x3e,0x41,0x13,0xad,0xb4,0xd1,0x4e,0x3b,0x23,0x68, 0xa5,0x8d,0x66,0x72,0xae,0x17,0x2b,0x73,0xbe,0xb8,0x47,0x68,0xf4,0xb3,0x9b,0x6e, 0xce,0xa4,0x95,0x5f,0x31,0xde,0xa7,0x69,0xfe,0x50,0x38,0x68,0xb3,0x1b,0x4b,0xcf, 0xd2,0xcf,0x9b,0xdc,0xcc,0x1a,0x2e,0x63,0x02,0x39,0x5a,0x18,0x41,0x07,0x9d,0x74, 0xb8,0x5d,0xcf,0x92,0x2e,0x6b,0xfe,0x2a,0x32,0x60,0x0f,0xdd,0xbc,0xc6,0x4b,0x3c, 0xc3,0xd3,0x4c,0x08,0xc1,0x10,0xff,0x0d,0xad,0x8a,0x80,0x29,0x43,0x4f,0x4f,0x73, 0x25,0x2b,0xf8,0x24,0x27,0xd2,0x44,0xb3,0xd7,0xf9,0x11,0xb4,0xd2,0x44,0xa6,0xcc, 0x43,0x33,0x12,0xab,0x80,0x43,0x9a,0x76,0x26,0x93,0xe7,0x1c,0x6e,0x64,0x01,0xad, 0xf4,0x97,0xfd,0xe4,0xe9,0x43,0x14,0x50,0xe0,0xdb,0xbf,0x57,0xf0,0xc1,0x1a,0xc7, 0x02,0x39,0xa5,0xef,0xe2,0x3d,0x8b,0x29,0xf7,0x29,0x44,0x69,0xf7,0x59,0x44,0x69, 0xdf,0xe7,0x00,0x6b,0xf9,0x17,0x1c,0x76,0xf1,0x65,0x9a,0x69,0x66,0x04,0xed,0x74, 0xd2,0xe1,0x3a,0xbd,0x8c,0x9b,0xca,0x4f,0x18,0x5e,0xc7,0xbd,0x68,0x29,0xcf,0x3e, 0xb6,0xd3,0x4d,0x37,0x3b,0xd8,0xc1,0x3a,0xd6,0xd2,0xe7,0x6b,0x42,0xca,0xfa,0x9f, 0xc2,0x71,0xb7,0x4d,0x00,0x9d,0x39,0xbe,0x85,0x4d,0xc6,0xf3,0xdf,0x05,0x70,0x59, 0x53,0xbc,0x4f,0x19,0xeb,0xb9,0x37,0x05,0xfa,0xc9,0x93,0xa7,0xdf,0xfb,0xeb,0x73, 0xff,0x0f,0x7c,0x52,0x7c,0x8c,0x8f,0x71,0x2c,0xcd,0xb4,0xd0,0x46,0x87,0x6b,0xee, 0xda,0x68,0x22,0x9b,0x78,0xe4,0xdd,0xd2,0x1b,0xfb,0xaa,0xad,0x02,0x7d,0xbc,0xcb, 0x76,0xb6,0xf1,0x0e,0x7f,0xe2,0x7d,0x7a,0x03,0x8f,0x40,0x8b,0x9e,0xa4,0x34,0x65, 0x12,0xe3,0x51,0xd1,0x3e,0x65,0x8f,0x2b,0xa6,0xae,0x43,0x8a,0x0c,0x39,0x5a,0x69, 0xa7,0xd3,0xd5,0xfa,0x26,0xb2,0xa4,0xab,0xeb,0x3c,0x40,0x77,0x9a,0x0d,0xd1,0x0c, 0x30,0xa4,0x69,0xe1,0x28,0x0c,0x69,0x72,0xec,0x66,0x1f,0xfd,0x14,0x08,0xdf,0xb8, 0x10,0x5e,0xcd,0x9b,0x6c,0x16,0x37,0xd8,0xad,0x60,0x67,0x65,0x6d,0xf9,0xbf,0x8b, 0x8f,0xe6,0x6b,0x76,0x5d,0x5d,0x07,0x6d,0xb4,0xd4,0xd6,0x79,0x80,0x0d,0x69,0x56, 0x07,0x1e,0x11,0xee,0x9b,0x12,0xc9,0x61,0x48,0x91,0xa5,0x85,0x0e,0xf6,0xd2,0xe7, 0xde,0x46,0x6b,0x62,0x67,0x76,0x4c,0x19,0x89,0x30,0x89,0xc7,0x59,0x81,0xbf,0xe0, 0x96,0x21,0x4d,0x96,0x16,0x5a,0x69,0x73,0xed,0x7d,0x12,0x6b,0x1f,0x53,0x56,0x57, 0x78,0xe1,0x62,0x81,0x3e,0x0e,0xb0,0x97,0x7d,0x1c,0xa0,0x3f,0xe4,0x81,0xe3,0xd7, 0xe7,0x27,0x19,0xff,0xa0,0x60,0xdb,0x8c,0x88,0x96,0x83,0x81,0xcc,0x74,0x86,0x1c, 0x4d,0xe4,0x06,0xd7,0x79,0xc8,0x33,0x29,0x6d,0xb6,0xe8,0x21,0x3e,0x1d,0xef,0x09, 0x32,0xa4,0xc8,0xd2,0xe6,0x2a,0xc0,0xa1,0x62,0x03,0x8a,0x46,0x37,0xe5,0x9b,0xb9, 0xac,0xa9,0x3c,0x64,0xb6,0x24,0x7a,0xe9,0xaa,0x12,0x3d,0x03,0xb2,0x7e,0x4f,0x07, 0x4b,0x72,0x2d,0x53,0x85,0xab,0x8b,0x29,0xbb,0x99,0x6c,0xba,0x87,0xfd,0x6b,0x77, 0x1d,0x00,0xb3,0x92,0x6b,0xc9,0x0f,0xb3,0xee,0x5f,0x5b,0x7c,0xf7,0xf4,0x91,0x57, 0x6f,0x7b,0x5a,0xb5,0x92,0xc9,0x2c,0x1f,0x06,0x72,0x90,0x67,0x39,0x93,0x07,0xba, 0x1f,0xb2,0x5c,0x1a,0xc7,0x7c,0x66,0x30,0x85,0xd1,0x87,0xdd,0x9b,0x48,0x7b,0xe9, 0x61,0x03,0xab,0x79,0xc4,0x6c,0xf1,0x1f,0xfe,0x7f,0x91,0xe5,0x29,0x5a,0xdd,0x82, 0x68,0xb0,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82, }; ippsample/README.md0000644000175000017500000000450213240604116013017 0ustar tilltill# IPP Sample Implementations This code provides sample implementations of IPP Clients, Printers, and Proxies. It is largely based upon the [CUPS](https://www.cups.org/) software, with substantial changes to the ippproxy and ippserver implementations to make them more general-purpose and configurable. [![Travis Build Status](https://travis-ci.org/istopwg/ippsample.svg?branch=master)](https://travis-ci.org/istopwg/ippsample) [![Snap Status](https://build.snapcraft.io/badge/istopwg/ippsample.svg)](https://build.snapcraft.io/user/istopwg/ippsample) ## ippfind The ippfind program implements Bonjour/DNS-SD discovery of IPP printers and can be used to find and test specific printers. Among other things, it is used as part of the IPP Everywhere Printer Self-Certification test tools. ## ipptool The ipptool program implements a generic IPP Client interface that allows a user to send different IPP requests and act based on the response from the Printer. Among other things, it is used as part of the IPP Everywhere Printer Self-Certification test tools. ## ippproxy The ippproxy program implements a generic IPP Proxy interface that allows you to connect a local IPP or PCL printer to an IPP Infrastructure Printer such as the ippserver program. ## ippserver The ippserver program implements a generic IPP Printer interface that allows you to host shared printers using the IPP Shared Infrastructure Extensions as well as support local printing or document processing. ## ipptransform The ipptransform program is a generic file conversion utility that is used primarily with ippserver to support rasterization of JPEG and PDF documents for IPP Everywhere and HP PCL printers. # Legal Stuff Copyright © 2014-2018 by the IEEE-ISTO Printer Working Group. Copyright © 2007-2018 by Apple Inc. Copyright © 1997-2007 by Easy Software Products. This software is provided under the terms of the Apache License, Version 2.0. A copy of this license can be found in the file `LICENSE`. Additional legal information is provided in the file `NOTICE`. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ippsample/xcode/0000755000175000017500000000000013240604116012641 5ustar tilltillippsample/xcode/ippsample.xcodeproj/0000755000175000017500000000000013240604116016627 5ustar tilltillippsample/xcode/ippsample.xcodeproj/project.pbxproj0000644000175000017500000037532013240604116021715 0ustar tilltill// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 48; objects = { /* Begin PBXAggregateTarget section */ 72E0060D1C5C0C48006CF057 /* All */ = { isa = PBXAggregateTarget; buildConfigurationList = 72E0060E1C5C0C48006CF057 /* Build configuration list for PBXAggregateTarget "All" */; buildPhases = ( ); dependencies = ( 7236871A202B669700973022 /* PBXTargetDependency */, 7236871C202B669700973022 /* PBXTargetDependency */, 7236871E202B669700973022 /* PBXTargetDependency */, 72368720202B669700973022 /* PBXTargetDependency */, 72368722202B669700973022 /* PBXTargetDependency */, 72368724202B669700973022 /* PBXTargetDependency */, 72368726202B669700973022 /* PBXTargetDependency */, 72368728202B669700973022 /* PBXTargetDependency */, 7236872A202B669700973022 /* PBXTargetDependency */, 72E006121C5C0C52006CF057 /* PBXTargetDependency */, 72E006141C5C0C52006CF057 /* PBXTargetDependency */, 72E006161C5C0C52006CF057 /* PBXTargetDependency */, 72E006181C5C0C52006CF057 /* PBXTargetDependency */, 72E0061A1C5C0C52006CF057 /* PBXTargetDependency */, 725C87C21C7664EF00FB3AD5 /* PBXTargetDependency */, 2778EBB21D2FF67B00DE72EC /* PBXTargetDependency */, ); name = All; productName = All; }; /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ 275C6BA11C8789E9000D2DE7 /* ippfind.man in CopyFiles */ = {isa = PBXBuildFile; fileRef = 72E006081C5C0BA8006CF057 /* ippfind.man */; }; 275C6BA41C878A74000D2DE7 /* ippproxy.man in CopyFiles */ = {isa = PBXBuildFile; fileRef = 72E0060C1C5C0BE3006CF057 /* ippproxy.man */; }; 275C6BA51C878A83000D2DE7 /* ippserver.man in CopyFiles */ = {isa = PBXBuildFile; fileRef = 72B402A81C0CE43D00139783 /* ippserver.man */; }; 275C6BA61C878A8E000D2DE7 /* ipptool.man in CopyFiles */ = {isa = PBXBuildFile; fileRef = 72E006091C5C0BA8006CF057 /* ipptool.man */; }; 275C6BA81C878AAE000D2DE7 /* ipptoolfile.man in CopyFiles */ = {isa = PBXBuildFile; fileRef = 72E0060A1C5C0BA8006CF057 /* ipptoolfile.man */; }; 275C6BA91C878AF5000D2DE7 /* ipptransform.man in CopyFiles */ = {isa = PBXBuildFile; fileRef = 275C6BA31C878A65000D2DE7 /* ipptransform.man */; }; 2778EBA21D2FF60E00DE72EC /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FB1C0CE8CE00139783 /* libiconv.dylib */; }; 2778EBA31D2FF60E00DE72EC /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FC1C0CE8CE00139783 /* libresolv.dylib */; }; 2778EBA41D2FF60E00DE72EC /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402F91C0CE87800139783 /* libz.dylib */; }; 2778EBA51D2FF60E00DE72EC /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402261C0CE0E100139783 /* libcups_static.a */; }; 2778EBA61D2FF60E00DE72EC /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402E91C0CE81900139783 /* ApplicationServices.framework */; }; 2778EBA71D2FF60E00DE72EC /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EA1C0CE81900139783 /* CoreFoundation.framework */; }; 2778EBA91D2FF60E00DE72EC /* ipptransform.man in CopyFiles */ = {isa = PBXBuildFile; fileRef = 275C6BA31C878A65000D2DE7 /* ipptransform.man */; }; 2778EBB01D2FF64300DE72EC /* ipptransform3d.c in Sources */ = {isa = PBXBuildFile; fileRef = 2778EBAE1D2FF62B00DE72EC /* ipptransform3d.c */; }; 27E2CC681C99C69400D203EC /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B403061C0DE7FC00139783 /* Security.framework */; }; 27E2CC691C99C6A000D203EC /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EB1C0CE81900139783 /* SystemConfiguration.framework */; }; 72368674202B657400973022 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FB1C0CE8CE00139783 /* libiconv.dylib */; }; 72368675202B657400973022 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FC1C0CE8CE00139783 /* libresolv.dylib */; }; 72368676202B657400973022 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402F91C0CE87800139783 /* libz.dylib */; }; 72368677202B657400973022 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402261C0CE0E100139783 /* libcups_static.a */; }; 72368678202B657400973022 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402E91C0CE81900139783 /* ApplicationServices.framework */; }; 72368679202B657400973022 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EA1C0CE81900139783 /* CoreFoundation.framework */; }; 72368686202B657800973022 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FB1C0CE8CE00139783 /* libiconv.dylib */; }; 72368687202B657800973022 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FC1C0CE8CE00139783 /* libresolv.dylib */; }; 72368688202B657800973022 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402F91C0CE87800139783 /* libz.dylib */; }; 72368689202B657800973022 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402261C0CE0E100139783 /* libcups_static.a */; }; 7236868A202B657800973022 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402E91C0CE81900139783 /* ApplicationServices.framework */; }; 7236868B202B657800973022 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EA1C0CE81900139783 /* CoreFoundation.framework */; }; 72368698202B657A00973022 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FB1C0CE8CE00139783 /* libiconv.dylib */; }; 72368699202B657A00973022 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FC1C0CE8CE00139783 /* libresolv.dylib */; }; 7236869A202B657A00973022 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402F91C0CE87800139783 /* libz.dylib */; }; 7236869B202B657A00973022 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402261C0CE0E100139783 /* libcups_static.a */; }; 7236869C202B657A00973022 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402E91C0CE81900139783 /* ApplicationServices.framework */; }; 7236869D202B657A00973022 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EA1C0CE81900139783 /* CoreFoundation.framework */; }; 723686AA202B657B00973022 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FB1C0CE8CE00139783 /* libiconv.dylib */; }; 723686AB202B657B00973022 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FC1C0CE8CE00139783 /* libresolv.dylib */; }; 723686AC202B657B00973022 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402F91C0CE87800139783 /* libz.dylib */; }; 723686AD202B657B00973022 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402261C0CE0E100139783 /* libcups_static.a */; }; 723686AE202B657B00973022 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402E91C0CE81900139783 /* ApplicationServices.framework */; }; 723686AF202B657B00973022 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EA1C0CE81900139783 /* CoreFoundation.framework */; }; 723686BC202B657D00973022 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FB1C0CE8CE00139783 /* libiconv.dylib */; }; 723686BD202B657D00973022 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FC1C0CE8CE00139783 /* libresolv.dylib */; }; 723686BE202B657D00973022 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402F91C0CE87800139783 /* libz.dylib */; }; 723686BF202B657D00973022 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402261C0CE0E100139783 /* libcups_static.a */; }; 723686C0202B657D00973022 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402E91C0CE81900139783 /* ApplicationServices.framework */; }; 723686C1202B657D00973022 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EA1C0CE81900139783 /* CoreFoundation.framework */; }; 723686CE202B657E00973022 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FB1C0CE8CE00139783 /* libiconv.dylib */; }; 723686CF202B657E00973022 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FC1C0CE8CE00139783 /* libresolv.dylib */; }; 723686D0202B657E00973022 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402F91C0CE87800139783 /* libz.dylib */; }; 723686D1202B657E00973022 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402261C0CE0E100139783 /* libcups_static.a */; }; 723686D2202B657E00973022 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402E91C0CE81900139783 /* ApplicationServices.framework */; }; 723686D3202B657E00973022 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EA1C0CE81900139783 /* CoreFoundation.framework */; }; 723686E0202B658000973022 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FB1C0CE8CE00139783 /* libiconv.dylib */; }; 723686E1202B658000973022 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FC1C0CE8CE00139783 /* libresolv.dylib */; }; 723686E2202B658000973022 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402F91C0CE87800139783 /* libz.dylib */; }; 723686E3202B658000973022 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402261C0CE0E100139783 /* libcups_static.a */; }; 723686E4202B658000973022 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402E91C0CE81900139783 /* ApplicationServices.framework */; }; 723686E5202B658000973022 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EA1C0CE81900139783 /* CoreFoundation.framework */; }; 723686F2202B658100973022 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FB1C0CE8CE00139783 /* libiconv.dylib */; }; 723686F3202B658100973022 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FC1C0CE8CE00139783 /* libresolv.dylib */; }; 723686F4202B658100973022 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402F91C0CE87800139783 /* libz.dylib */; }; 723686F5202B658100973022 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402261C0CE0E100139783 /* libcups_static.a */; }; 723686F6202B658100973022 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402E91C0CE81900139783 /* ApplicationServices.framework */; }; 723686F7202B658100973022 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EA1C0CE81900139783 /* CoreFoundation.framework */; }; 72368704202B65D300973022 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FB1C0CE8CE00139783 /* libiconv.dylib */; }; 72368705202B65D300973022 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FC1C0CE8CE00139783 /* libresolv.dylib */; }; 72368706202B65D300973022 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402F91C0CE87800139783 /* libz.dylib */; }; 72368707202B65D300973022 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402261C0CE0E100139783 /* libcups_static.a */; }; 72368708202B65D300973022 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402E91C0CE81900139783 /* ApplicationServices.framework */; }; 72368709202B65D300973022 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EA1C0CE81900139783 /* CoreFoundation.framework */; }; 72368710202B65E700973022 /* testraster.c in Sources */ = {isa = PBXBuildFile; fileRef = 7236866C202B652700973022 /* testraster.c */; }; 72368711202B65F300973022 /* testoptions.c in Sources */ = {isa = PBXBuildFile; fileRef = 72368669202B652700973022 /* testoptions.c */; }; 72368712202B65FE00973022 /* testipp.c in Sources */ = {isa = PBXBuildFile; fileRef = 72368668202B652700973022 /* testipp.c */; }; 72368713202B660900973022 /* testi18n.c in Sources */ = {isa = PBXBuildFile; fileRef = 72368665202B652600973022 /* testi18n.c */; }; 72368714202B661200973022 /* testhttp.c in Sources */ = {isa = PBXBuildFile; fileRef = 7236866B202B652700973022 /* testhttp.c */; }; 72368715202B661E00973022 /* testfile.c in Sources */ = {isa = PBXBuildFile; fileRef = 7236866A202B652700973022 /* testfile.c */; }; 72368716202B662900973022 /* testdest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7236866D202B652700973022 /* testdest.c */; }; 72368717202B663200973022 /* testclient.c in Sources */ = {isa = PBXBuildFile; fileRef = 72368666202B652700973022 /* testclient.c */; }; 72368718202B663A00973022 /* testarray.c in Sources */ = {isa = PBXBuildFile; fileRef = 72368667202B652700973022 /* testarray.c */; }; 72530E352028BCF30035FF65 /* ipp-file.c in Sources */ = {isa = PBXBuildFile; fileRef = 72530E332028BCF20035FF65 /* ipp-file.c */; }; 72530E362028BCF30035FF65 /* ipp-vars.c in Sources */ = {isa = PBXBuildFile; fileRef = 72530E342028BCF30035FF65 /* ipp-vars.c */; }; 725C87B61C7664DE00FB3AD5 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FB1C0CE8CE00139783 /* libiconv.dylib */; }; 725C87B71C7664DE00FB3AD5 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FC1C0CE8CE00139783 /* libresolv.dylib */; }; 725C87B81C7664DE00FB3AD5 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402F91C0CE87800139783 /* libz.dylib */; }; 725C87B91C7664DE00FB3AD5 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402261C0CE0E100139783 /* libcups_static.a */; }; 725C87BA1C7664DE00FB3AD5 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402E91C0CE81900139783 /* ApplicationServices.framework */; }; 725C87BB1C7664DE00FB3AD5 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EA1C0CE81900139783 /* CoreFoundation.framework */; }; 725C87C41C767CF800FB3AD5 /* ipptransform.c in Sources */ = {isa = PBXBuildFile; fileRef = 725C87C31C767CF800FB3AD5 /* ipptransform.c */; }; 72737CF61C24BA4F007CBEF6 /* dest-job.c in Sources */ = {isa = PBXBuildFile; fileRef = 72737CEF1C24BA4F007CBEF6 /* dest-job.c */; }; 72737CF71C24BA4F007CBEF6 /* dest-localization.c in Sources */ = {isa = PBXBuildFile; fileRef = 72737CF01C24BA4F007CBEF6 /* dest-localization.c */; }; 72737CF81C24BA4F007CBEF6 /* dest-options.c in Sources */ = {isa = PBXBuildFile; fileRef = 72737CF11C24BA4F007CBEF6 /* dest-options.c */; }; 72737CF91C24BA4F007CBEF6 /* dest.c in Sources */ = {isa = PBXBuildFile; fileRef = 72737CF21C24BA4F007CBEF6 /* dest.c */; }; 72737CFB1C24BA4F007CBEF6 /* notify.c in Sources */ = {isa = PBXBuildFile; fileRef = 72737CF41C24BA4F007CBEF6 /* notify.c */; }; 72737CFC1C24BA4F007CBEF6 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 72737CF51C24BA4F007CBEF6 /* util.c */; }; 72A0D4531E6864EB0092958D /* printer3d-png.h in Headers */ = {isa = PBXBuildFile; fileRef = 72A0D4521E6864EB0092958D /* printer3d-png.h */; }; 72B402681C0CE27900139783 /* array-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B4022F1C0CE27800139783 /* array-private.h */; }; 72B402691C0CE27900139783 /* array.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402301C0CE27800139783 /* array.c */; }; 72B4026A1C0CE27900139783 /* array.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B402311C0CE27800139783 /* array.h */; settings = {ATTRIBUTES = (Public, ); }; }; 72B4026B1C0CE27900139783 /* auth.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402321C0CE27800139783 /* auth.c */; }; 72B4026C1C0CE27900139783 /* cups-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B402331C0CE27800139783 /* cups-private.h */; }; 72B4026D1C0CE27900139783 /* cups.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B402341C0CE27800139783 /* cups.h */; settings = {ATTRIBUTES = (Public, ); }; }; 72B4026E1C0CE27900139783 /* debug-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B402351C0CE27800139783 /* debug-private.h */; }; 72B4026F1C0CE27900139783 /* debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402361C0CE27800139783 /* debug.c */; }; 72B402701C0CE27900139783 /* dir.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402371C0CE27800139783 /* dir.c */; }; 72B402711C0CE27900139783 /* dir.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B402381C0CE27800139783 /* dir.h */; settings = {ATTRIBUTES = (Public, ); }; }; 72B402721C0CE27900139783 /* encode.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402391C0CE27800139783 /* encode.c */; }; 72B402731C0CE27900139783 /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B4023A1C0CE27800139783 /* error.c */; }; 72B402741C0CE27900139783 /* file-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B4023B1C0CE27800139783 /* file-private.h */; }; 72B402751C0CE27900139783 /* file.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B4023C1C0CE27800139783 /* file.c */; }; 72B402761C0CE27900139783 /* file.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B4023D1C0CE27800139783 /* file.h */; settings = {ATTRIBUTES = (Public, ); }; }; 72B402771C0CE27900139783 /* getputfile.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B4023E1C0CE27800139783 /* getputfile.c */; }; 72B402781C0CE27900139783 /* globals.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B4023F1C0CE27800139783 /* globals.c */; }; 72B402791C0CE27900139783 /* hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402401C0CE27800139783 /* hash.c */; }; 72B4027A1C0CE27900139783 /* http-addr.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402411C0CE27800139783 /* http-addr.c */; }; 72B4027B1C0CE27900139783 /* http-addrlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402421C0CE27800139783 /* http-addrlist.c */; }; 72B4027C1C0CE27900139783 /* http-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B402431C0CE27800139783 /* http-private.h */; }; 72B4027D1C0CE27900139783 /* http-support.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402441C0CE27800139783 /* http-support.c */; }; 72B4027E1C0CE27900139783 /* http.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402451C0CE27800139783 /* http.c */; }; 72B4027F1C0CE27900139783 /* http.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B402461C0CE27800139783 /* http.h */; settings = {ATTRIBUTES = (Public, ); }; }; 72B402801C0CE27900139783 /* ipp-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B402471C0CE27800139783 /* ipp-private.h */; }; 72B402811C0CE27900139783 /* ipp-support.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402481C0CE27800139783 /* ipp-support.c */; }; 72B402821C0CE27900139783 /* ipp.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402491C0CE27800139783 /* ipp.c */; }; 72B402831C0CE27900139783 /* ipp.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B4024A1C0CE27800139783 /* ipp.h */; settings = {ATTRIBUTES = (Public, ); }; }; 72B402841C0CE27900139783 /* langprintf.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B4024B1C0CE27800139783 /* langprintf.c */; }; 72B402851C0CE27900139783 /* language-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B4024C1C0CE27800139783 /* language-private.h */; }; 72B402861C0CE27900139783 /* language.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B4024D1C0CE27800139783 /* language.c */; }; 72B402871C0CE27900139783 /* language.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B4024E1C0CE27800139783 /* language.h */; settings = {ATTRIBUTES = (Public, ); }; }; 72B402881C0CE27900139783 /* md5-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B4024F1C0CE27800139783 /* md5-private.h */; }; 72B402891C0CE27900139783 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402501C0CE27800139783 /* md5.c */; }; 72B4028A1C0CE27900139783 /* md5passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402511C0CE27800139783 /* md5passwd.c */; }; 72B4028B1C0CE27900139783 /* options.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402521C0CE27800139783 /* options.c */; }; 72B4028C1C0CE27900139783 /* pwg-media.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402531C0CE27800139783 /* pwg-media.c */; }; 72B4028D1C0CE27900139783 /* pwg-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B402541C0CE27800139783 /* pwg-private.h */; settings = {ATTRIBUTES = (Public, ); }; }; 72B4028E1C0CE27900139783 /* pwg.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B402551C0CE27800139783 /* pwg.h */; settings = {ATTRIBUTES = (Public, ); }; }; 72B4028F1C0CE27900139783 /* raster-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B402561C0CE27800139783 /* raster-private.h */; }; 72B402901C0CE27900139783 /* raster.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402571C0CE27800139783 /* raster.c */; }; 72B402911C0CE27900139783 /* raster.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B402581C0CE27800139783 /* raster.h */; settings = {ATTRIBUTES = (Public, ); }; }; 72B402921C0CE27900139783 /* request.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402591C0CE27800139783 /* request.c */; }; 72B402931C0CE27900139783 /* snprintf.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B4025A1C0CE27800139783 /* snprintf.c */; }; 72B402941C0CE27900139783 /* string-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B4025B1C0CE27800139783 /* string-private.h */; }; 72B402951C0CE27900139783 /* string.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B4025C1C0CE27800139783 /* string.c */; }; 72B402961C0CE27900139783 /* tempfile.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B4025D1C0CE27800139783 /* tempfile.c */; }; 72B402971C0CE27900139783 /* thread-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B4025E1C0CE27800139783 /* thread-private.h */; }; 72B402981C0CE27900139783 /* thread.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B4025F1C0CE27800139783 /* thread.c */; }; 72B4029C1C0CE27900139783 /* tls.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402631C0CE27900139783 /* tls.c */; }; 72B4029D1C0CE27900139783 /* transcode.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402641C0CE27900139783 /* transcode.c */; }; 72B4029E1C0CE27900139783 /* transcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B402651C0CE27900139783 /* transcode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 72B4029F1C0CE27900139783 /* usersys.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402661C0CE27900139783 /* usersys.c */; }; 72B402A01C0CE27900139783 /* versioning.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B402671C0CE27900139783 /* versioning.h */; settings = {ATTRIBUTES = (Public, ); }; }; 72B402BB1C0CE45A00139783 /* client.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402A31C0CE43D00139783 /* client.c */; }; 72B402BC1C0CE45F00139783 /* conf.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402A41C0CE43D00139783 /* conf.c */; }; 72B402BD1C0CE45F00139783 /* device.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402A51C0CE43D00139783 /* device.c */; }; 72B402BE1C0CE45F00139783 /* ipp.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402A61C0CE43D00139783 /* ipp.c */; }; 72B402BF1C0CE46800139783 /* job.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402A91C0CE43D00139783 /* job.c */; }; 72B402C01C0CE46800139783 /* log.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402AA1C0CE43D00139783 /* log.c */; }; 72B402C11C0CE46800139783 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402AB1C0CE43D00139783 /* main.c */; }; 72B402C21C0CE46800139783 /* printer.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402AC1C0CE43D00139783 /* printer.c */; }; 72B402C31C0CE46800139783 /* subscription.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402AE1C0CE43D00139783 /* subscription.c */; }; 72B402C41C0CE46800139783 /* transform.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402AF1C0CE43D00139783 /* transform.c */; }; 72B402D41C0CE60800139783 /* ipptool.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402D11C0CE60400139783 /* ipptool.c */; }; 72B402E01C0CE62C00139783 /* ippfind.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B402D01C0CE60400139783 /* ippfind.c */; }; 72B402E81C0CE81900139783 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402261C0CE0E100139783 /* libcups_static.a */; }; 72B402EC1C0CE81900139783 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402E91C0CE81900139783 /* ApplicationServices.framework */; }; 72B402ED1C0CE81900139783 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EA1C0CE81900139783 /* CoreFoundation.framework */; }; 72B402EE1C0CE81900139783 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EB1C0CE81900139783 /* SystemConfiguration.framework */; }; 72B402F11C0CE83200139783 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402261C0CE0E100139783 /* libcups_static.a */; }; 72B402F21C0CE83200139783 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402E91C0CE81900139783 /* ApplicationServices.framework */; }; 72B402F31C0CE83200139783 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EA1C0CE81900139783 /* CoreFoundation.framework */; }; 72B402F61C0CE84700139783 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402261C0CE0E100139783 /* libcups_static.a */; }; 72B402F71C0CE84700139783 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402E91C0CE81900139783 /* ApplicationServices.framework */; }; 72B402F81C0CE84700139783 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EA1C0CE81900139783 /* CoreFoundation.framework */; }; 72B402FA1C0CE87800139783 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402F91C0CE87800139783 /* libz.dylib */; }; 72B402FD1C0CE8CE00139783 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FB1C0CE8CE00139783 /* libiconv.dylib */; }; 72B402FE1C0CE8CE00139783 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FC1C0CE8CE00139783 /* libresolv.dylib */; }; 72B402FF1C0CE8FE00139783 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FB1C0CE8CE00139783 /* libiconv.dylib */; }; 72B403001C0CE8FE00139783 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FC1C0CE8CE00139783 /* libresolv.dylib */; }; 72B403011C0CE8FE00139783 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402F91C0CE87800139783 /* libz.dylib */; }; 72B403021C0CE92400139783 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FB1C0CE8CE00139783 /* libiconv.dylib */; }; 72B403031C0CE92400139783 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FC1C0CE8CE00139783 /* libresolv.dylib */; }; 72B403041C0CE92400139783 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402F91C0CE87800139783 /* libz.dylib */; }; 72B403071C0DE7FC00139783 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B403061C0DE7FC00139783 /* Security.framework */; }; 72E005F81C5C0B10006CF057 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FB1C0CE8CE00139783 /* libiconv.dylib */; }; 72E005F91C5C0B10006CF057 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402FC1C0CE8CE00139783 /* libresolv.dylib */; }; 72E005FA1C5C0B10006CF057 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402F91C0CE87800139783 /* libz.dylib */; }; 72E005FB1C5C0B10006CF057 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402261C0CE0E100139783 /* libcups_static.a */; }; 72E005FC1C5C0B10006CF057 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402E91C0CE81900139783 /* ApplicationServices.framework */; }; 72E005FD1C5C0B10006CF057 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B402EA1C0CE81900139783 /* CoreFoundation.framework */; }; 72E006071C5C0B65006CF057 /* ippproxy.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E006031C5C0B49006CF057 /* ippproxy.c */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 2778EB9E1D2FF60E00DE72EC /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 2778EBB11D2FF67B00DE72EC /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 2778EB9C1D2FF60E00DE72EC; remoteInfo = ipptransform3d; }; 72368670202B657400973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 72368682202B657800973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 72368694202B657A00973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 723686A6202B657B00973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 723686B8202B657D00973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 723686CA202B657E00973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 723686DC202B658000973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 723686EE202B658100973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 72368700202B65D300973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 72368719202B669700973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 7236866E202B657400973022; remoteInfo = testarray; }; 7236871B202B669700973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72368680202B657800973022; remoteInfo = testclient; }; 7236871D202B669700973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72368692202B657A00973022; remoteInfo = testdest; }; 7236871F202B669700973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 723686A4202B657B00973022; remoteInfo = testfile; }; 72368721202B669700973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 723686B6202B657D00973022; remoteInfo = testhttp; }; 72368723202B669700973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 723686C8202B657E00973022; remoteInfo = testi18n; }; 72368725202B669700973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 723686DA202B658000973022; remoteInfo = testipp; }; 72368727202B669700973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 723686EC202B658100973022; remoteInfo = testoptions; }; 72368729202B669700973022 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 723686FE202B65D300973022; remoteInfo = testraster; }; 725C87B21C7664DE00FB3AD5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 725C87C11C7664EF00FB3AD5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 725C87B01C7664DE00FB3AD5; remoteInfo = ipptransform; }; 72B402E61C0CE7EA00139783 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 72B402EF1C0CE82100139783 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 72B402F41C0CE83A00139783 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 72E005F41C5C0B10006CF057 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 72E006111C5C0C52006CF057 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402251C0CE0E100139783; remoteInfo = libcups; }; 72E006131C5C0C52006CF057 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402D81C0CE61D00139783; remoteInfo = ippfind; }; 72E006151C5C0C52006CF057 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72E005F21C5C0B10006CF057; remoteInfo = ippproxy; }; 72E006171C5C0C52006CF057 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402171C0CDFB400139783; remoteInfo = ippserver; }; 72E006191C5C0C52006CF057 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72B402101C0CDFB400139783 /* Project object */; proxyType = 1; remoteGlobalIDString = 72B402C81C0CE5EC00139783; remoteInfo = ipptool; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 275C6BA71C878A98000D2DE7 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; dstPath = /usr/local/share/man/man5; dstSubfolderSpec = 0; files = ( 275C6BA81C878AAE000D2DE7 /* ipptoolfile.man in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 1; }; 2778EBA81D2FF60E00DE72EC /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = /usr/local/share/man/man1; dstSubfolderSpec = 0; files = ( 2778EBA91D2FF60E00DE72EC /* ipptransform.man in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 1; }; 725C87BC1C7664DE00FB3AD5 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = /usr/local/share/man/man1; dstSubfolderSpec = 0; files = ( 275C6BA91C878AF5000D2DE7 /* ipptransform.man in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 1; }; 72B402161C0CDFB400139783 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = /usr/local/share/man/man1; dstSubfolderSpec = 0; files = ( 275C6BA51C878A83000D2DE7 /* ippserver.man in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 1; }; 72B402C71C0CE5EC00139783 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = /usr/local/share/man/man1; dstSubfolderSpec = 0; files = ( 275C6BA61C878A8E000D2DE7 /* ipptool.man in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 1; }; 72B402D71C0CE61D00139783 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = /usr/local/share/man/man1; dstSubfolderSpec = 0; files = ( 275C6BA11C8789E9000D2DE7 /* ippfind.man in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 1; }; 72E005FE1C5C0B10006CF057 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = /usr/local/share/man/man1; dstSubfolderSpec = 0; files = ( 275C6BA41C878A74000D2DE7 /* ippproxy.man in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 1; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 275C6BA21C878A65000D2DE7 /* ipptransform.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = ipptransform.html; path = ../doc/ipptransform.html; sourceTree = ""; }; 275C6BA31C878A65000D2DE7 /* ipptransform.man */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ipptransform.man; path = ../doc/ipptransform.man; sourceTree = ""; }; 275C6BAA1C87D907000D2DE7 /* dither.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dither.h; path = ../tools/dither.h; sourceTree = ""; }; 2778EBAD1D2FF60E00DE72EC /* ipptransform3d */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ipptransform3d; sourceTree = BUILT_PRODUCTS_DIR; }; 2778EBAE1D2FF62B00DE72EC /* ipptransform3d.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ipptransform3d.c; path = ../tools/ipptransform3d.c; sourceTree = ""; }; 279C01D61D1B0F9700F06A84 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 279C01D71D1B0F9700F06A84 /* PI.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = PI.md; path = ../PI.md; sourceTree = ""; }; 27FDC5F61D7F497500246F95 /* ipptransform3d.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = ipptransform3d.html; path = ../doc/ipptransform3d.html; sourceTree = ""; }; 27FDC5F71D7F497500246F95 /* ipptransform3d.man */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ipptransform3d.man; path = ../doc/ipptransform3d.man; sourceTree = ""; }; 72368665202B652600973022 /* testi18n.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = testi18n.c; path = ../cups/testi18n.c; sourceTree = ""; }; 72368666202B652700973022 /* testclient.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = testclient.c; path = ../cups/testclient.c; sourceTree = ""; }; 72368667202B652700973022 /* testarray.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = testarray.c; path = ../cups/testarray.c; sourceTree = ""; }; 72368668202B652700973022 /* testipp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = testipp.c; path = ../cups/testipp.c; sourceTree = ""; }; 72368669202B652700973022 /* testoptions.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = testoptions.c; path = ../cups/testoptions.c; sourceTree = ""; }; 7236866A202B652700973022 /* testfile.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = testfile.c; path = ../cups/testfile.c; sourceTree = ""; }; 7236866B202B652700973022 /* testhttp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = testhttp.c; path = ../cups/testhttp.c; sourceTree = ""; }; 7236866C202B652700973022 /* testraster.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = testraster.c; path = ../cups/testraster.c; sourceTree = ""; }; 7236866D202B652700973022 /* testdest.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = testdest.c; path = ../cups/testdest.c; sourceTree = ""; }; 7236867F202B657400973022 /* testarray */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testarray; sourceTree = BUILT_PRODUCTS_DIR; }; 72368691202B657800973022 /* testclient */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testclient; sourceTree = BUILT_PRODUCTS_DIR; }; 723686A3202B657A00973022 /* testdest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testdest; sourceTree = BUILT_PRODUCTS_DIR; }; 723686B5202B657B00973022 /* testfile */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testfile; sourceTree = BUILT_PRODUCTS_DIR; }; 723686C7202B657D00973022 /* testhttp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testhttp; sourceTree = BUILT_PRODUCTS_DIR; }; 723686D9202B657E00973022 /* testi18n */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testi18n; sourceTree = BUILT_PRODUCTS_DIR; }; 723686EB202B658000973022 /* testipp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testipp; sourceTree = BUILT_PRODUCTS_DIR; }; 723686FD202B658100973022 /* testoptions */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testoptions; sourceTree = BUILT_PRODUCTS_DIR; }; 7236870F202B65D300973022 /* testraster */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testraster; sourceTree = BUILT_PRODUCTS_DIR; }; 723D66D41C723CB70078B537 /* CONTRIBUTING.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = CONTRIBUTING.md; path = ../CONTRIBUTING.md; sourceTree = ""; }; 723D66D51C723CB70078B537 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 723D66D81C723CC20078B537 /* DESIGN.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = DESIGN.md; path = ../server/DESIGN.md; sourceTree = ""; }; 72530E332028BCF20035FF65 /* ipp-file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "ipp-file.c"; path = "../cups/ipp-file.c"; sourceTree = ""; }; 72530E342028BCF30035FF65 /* ipp-vars.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "ipp-vars.c"; path = "../cups/ipp-vars.c"; sourceTree = ""; }; 725C87C01C7664DE00FB3AD5 /* ipptransform */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ipptransform; sourceTree = BUILT_PRODUCTS_DIR; }; 725C87C31C767CF800FB3AD5 /* ipptransform.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ipptransform.c; path = ../tools/ipptransform.c; sourceTree = ""; }; 72737CEF1C24BA4F007CBEF6 /* dest-job.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "dest-job.c"; path = "../cups/dest-job.c"; sourceTree = ""; }; 72737CF01C24BA4F007CBEF6 /* dest-localization.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "dest-localization.c"; path = "../cups/dest-localization.c"; sourceTree = ""; }; 72737CF11C24BA4F007CBEF6 /* dest-options.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "dest-options.c"; path = "../cups/dest-options.c"; sourceTree = ""; }; 72737CF21C24BA4F007CBEF6 /* dest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dest.c; path = ../cups/dest.c; sourceTree = ""; }; 72737CF41C24BA4F007CBEF6 /* notify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = notify.c; path = ../cups/notify.c; sourceTree = ""; }; 72737CF51C24BA4F007CBEF6 /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = util.c; path = ../cups/util.c; sourceTree = ""; }; 729181C42011828E005E7560 /* NOTICE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = NOTICE; path = ../NOTICE; sourceTree = ""; }; 72A0D4521E6864EB0092958D /* printer3d-png.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "printer3d-png.h"; path = "../server/printer3d-png.h"; sourceTree = ""; }; 72B402181C0CDFB400139783 /* ippserver */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ippserver; sourceTree = BUILT_PRODUCTS_DIR; }; 72B402261C0CE0E100139783 /* libcups_static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libcups_static.a; sourceTree = BUILT_PRODUCTS_DIR; }; 72B4022F1C0CE27800139783 /* array-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "array-private.h"; path = "../cups/array-private.h"; sourceTree = ""; }; 72B402301C0CE27800139783 /* array.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = array.c; path = ../cups/array.c; sourceTree = ""; }; 72B402311C0CE27800139783 /* array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = array.h; path = ../cups/array.h; sourceTree = ""; }; 72B402321C0CE27800139783 /* auth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = auth.c; path = ../cups/auth.c; sourceTree = ""; }; 72B402331C0CE27800139783 /* cups-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "cups-private.h"; path = "../cups/cups-private.h"; sourceTree = ""; }; 72B402341C0CE27800139783 /* cups.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cups.h; path = ../cups/cups.h; sourceTree = ""; }; 72B402351C0CE27800139783 /* debug-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "debug-private.h"; path = "../cups/debug-private.h"; sourceTree = ""; }; 72B402361C0CE27800139783 /* debug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = debug.c; path = ../cups/debug.c; sourceTree = ""; }; 72B402371C0CE27800139783 /* dir.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dir.c; path = ../cups/dir.c; sourceTree = ""; }; 72B402381C0CE27800139783 /* dir.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dir.h; path = ../cups/dir.h; sourceTree = ""; }; 72B402391C0CE27800139783 /* encode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = encode.c; path = ../cups/encode.c; sourceTree = ""; }; 72B4023A1C0CE27800139783 /* error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = error.c; path = ../cups/error.c; sourceTree = ""; }; 72B4023B1C0CE27800139783 /* file-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "file-private.h"; path = "../cups/file-private.h"; sourceTree = ""; }; 72B4023C1C0CE27800139783 /* file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = file.c; path = ../cups/file.c; sourceTree = ""; }; 72B4023D1C0CE27800139783 /* file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = file.h; path = ../cups/file.h; sourceTree = ""; }; 72B4023E1C0CE27800139783 /* getputfile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = getputfile.c; path = ../cups/getputfile.c; sourceTree = ""; }; 72B4023F1C0CE27800139783 /* globals.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = globals.c; path = ../cups/globals.c; sourceTree = ""; }; 72B402401C0CE27800139783 /* hash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hash.c; path = ../cups/hash.c; sourceTree = ""; }; 72B402411C0CE27800139783 /* http-addr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "http-addr.c"; path = "../cups/http-addr.c"; sourceTree = ""; }; 72B402421C0CE27800139783 /* http-addrlist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "http-addrlist.c"; path = "../cups/http-addrlist.c"; sourceTree = ""; }; 72B402431C0CE27800139783 /* http-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "http-private.h"; path = "../cups/http-private.h"; sourceTree = ""; }; 72B402441C0CE27800139783 /* http-support.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "http-support.c"; path = "../cups/http-support.c"; sourceTree = ""; }; 72B402451C0CE27800139783 /* http.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = http.c; path = ../cups/http.c; sourceTree = ""; }; 72B402461C0CE27800139783 /* http.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = http.h; path = ../cups/http.h; sourceTree = ""; }; 72B402471C0CE27800139783 /* ipp-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "ipp-private.h"; path = "../cups/ipp-private.h"; sourceTree = ""; }; 72B402481C0CE27800139783 /* ipp-support.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "ipp-support.c"; path = "../cups/ipp-support.c"; sourceTree = ""; }; 72B402491C0CE27800139783 /* ipp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ipp.c; path = ../cups/ipp.c; sourceTree = ""; }; 72B4024A1C0CE27800139783 /* ipp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ipp.h; path = ../cups/ipp.h; sourceTree = ""; }; 72B4024B1C0CE27800139783 /* langprintf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = langprintf.c; path = ../cups/langprintf.c; sourceTree = ""; }; 72B4024C1C0CE27800139783 /* language-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "language-private.h"; path = "../cups/language-private.h"; sourceTree = ""; }; 72B4024D1C0CE27800139783 /* language.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = language.c; path = ../cups/language.c; sourceTree = ""; }; 72B4024E1C0CE27800139783 /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = language.h; path = ../cups/language.h; sourceTree = ""; }; 72B4024F1C0CE27800139783 /* md5-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "md5-private.h"; path = "../cups/md5-private.h"; sourceTree = ""; }; 72B402501C0CE27800139783 /* md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md5.c; path = ../cups/md5.c; sourceTree = ""; }; 72B402511C0CE27800139783 /* md5passwd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md5passwd.c; path = ../cups/md5passwd.c; sourceTree = ""; }; 72B402521C0CE27800139783 /* options.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = options.c; path = ../cups/options.c; sourceTree = ""; }; 72B402531C0CE27800139783 /* pwg-media.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "pwg-media.c"; path = "../cups/pwg-media.c"; sourceTree = ""; }; 72B402541C0CE27800139783 /* pwg-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "pwg-private.h"; path = "../cups/pwg-private.h"; sourceTree = ""; }; 72B402551C0CE27800139783 /* pwg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pwg.h; path = ../cups/pwg.h; sourceTree = ""; }; 72B402561C0CE27800139783 /* raster-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "raster-private.h"; path = "../cups/raster-private.h"; sourceTree = ""; }; 72B402571C0CE27800139783 /* raster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = raster.c; path = ../cups/raster.c; sourceTree = ""; }; 72B402581C0CE27800139783 /* raster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = raster.h; path = ../cups/raster.h; sourceTree = ""; }; 72B402591C0CE27800139783 /* request.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = request.c; path = ../cups/request.c; sourceTree = ""; }; 72B4025A1C0CE27800139783 /* snprintf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = snprintf.c; path = ../cups/snprintf.c; sourceTree = ""; }; 72B4025B1C0CE27800139783 /* string-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "string-private.h"; path = "../cups/string-private.h"; sourceTree = ""; }; 72B4025C1C0CE27800139783 /* string.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = string.c; path = ../cups/string.c; sourceTree = ""; }; 72B4025D1C0CE27800139783 /* tempfile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tempfile.c; path = ../cups/tempfile.c; sourceTree = ""; }; 72B4025E1C0CE27800139783 /* thread-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "thread-private.h"; path = "../cups/thread-private.h"; sourceTree = ""; }; 72B4025F1C0CE27800139783 /* thread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = thread.c; path = ../cups/thread.c; sourceTree = ""; }; 72B402601C0CE27800139783 /* tls-darwin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tls-darwin.c"; path = "../cups/tls-darwin.c"; sourceTree = ""; }; 72B402611C0CE27800139783 /* tls-gnutls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tls-gnutls.c"; path = "../cups/tls-gnutls.c"; sourceTree = ""; }; 72B402621C0CE27900139783 /* tls-sspi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tls-sspi.c"; path = "../cups/tls-sspi.c"; sourceTree = ""; }; 72B402631C0CE27900139783 /* tls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tls.c; path = ../cups/tls.c; sourceTree = ""; }; 72B402641C0CE27900139783 /* transcode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = transcode.c; path = ../cups/transcode.c; sourceTree = ""; }; 72B402651C0CE27900139783 /* transcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = transcode.h; path = ../cups/transcode.h; sourceTree = ""; }; 72B402661C0CE27900139783 /* usersys.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = usersys.c; path = ../cups/usersys.c; sourceTree = ""; }; 72B402671C0CE27900139783 /* versioning.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = versioning.h; path = ../cups/versioning.h; sourceTree = ""; }; 72B402A11C0CE3AC00139783 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; 72B402A31C0CE43D00139783 /* client.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = client.c; path = ../server/client.c; sourceTree = ""; }; 72B402A41C0CE43D00139783 /* conf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = conf.c; path = ../server/conf.c; sourceTree = ""; }; 72B402A51C0CE43D00139783 /* device.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = device.c; path = ../server/device.c; sourceTree = ""; }; 72B402A61C0CE43D00139783 /* ipp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ipp.c; path = ../server/ipp.c; sourceTree = ""; }; 72B402A71C0CE43D00139783 /* ippserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ippserver.h; path = ../server/ippserver.h; sourceTree = ""; }; 72B402A81C0CE43D00139783 /* ippserver.man */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ippserver.man; path = ../doc/ippserver.man; sourceTree = ""; }; 72B402A91C0CE43D00139783 /* job.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = job.c; path = ../server/job.c; sourceTree = ""; }; 72B402AA1C0CE43D00139783 /* log.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = log.c; path = ../server/log.c; sourceTree = ""; }; 72B402AB1C0CE43D00139783 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = ../server/main.c; sourceTree = ""; }; 72B402AC1C0CE43D00139783 /* printer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = printer.c; path = ../server/printer.c; sourceTree = ""; }; 72B402AE1C0CE43D00139783 /* subscription.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = subscription.c; path = ../server/subscription.c; sourceTree = ""; }; 72B402AF1C0CE43D00139783 /* transform.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = transform.c; path = ../server/transform.c; sourceTree = ""; }; 72B402C91C0CE5EC00139783 /* ipptool */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ipptool; sourceTree = BUILT_PRODUCTS_DIR; }; 72B402D01C0CE60400139783 /* ippfind.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ippfind.c; path = ../tools/ippfind.c; sourceTree = ""; }; 72B402D11C0CE60400139783 /* ipptool.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ipptool.c; path = ../tools/ipptool.c; sourceTree = ""; }; 72B402D91C0CE61D00139783 /* ippfind */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ippfind; sourceTree = BUILT_PRODUCTS_DIR; }; 72B402E21C0CE66200139783 /* ippfind.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = ippfind.html; path = ../doc/ippfind.html; sourceTree = ""; }; 72B402E31C0CE66200139783 /* ippserver.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = ippserver.html; path = ../doc/ippserver.html; sourceTree = ""; }; 72B402E41C0CE66200139783 /* ipptool.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = ipptool.html; path = ../doc/ipptool.html; sourceTree = ""; }; 72B402E51C0CE66200139783 /* ipptoolfile.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = ipptoolfile.html; path = ../doc/ipptoolfile.html; sourceTree = ""; }; 72B402E91C0CE81900139783 /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = System/Library/Frameworks/ApplicationServices.framework; sourceTree = SDKROOT; }; 72B402EA1C0CE81900139783 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 72B402EB1C0CE81900139783 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 72B402F91C0CE87800139783 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; 72B402FB1C0CE8CE00139783 /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = usr/lib/libiconv.dylib; sourceTree = SDKROOT; }; 72B402FC1C0CE8CE00139783 /* libresolv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libresolv.dylib; path = usr/lib/libresolv.dylib; sourceTree = SDKROOT; }; 72B403061C0DE7FC00139783 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 72B589F51D1C6628007117DA /* printer-png.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "printer-png.h"; path = "../server/printer-png.h"; sourceTree = ""; }; 72E006021C5C0B10006CF057 /* ippproxy */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ippproxy; sourceTree = BUILT_PRODUCTS_DIR; }; 72E006031C5C0B49006CF057 /* ippproxy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ippproxy.c; path = ../tools/ippproxy.c; sourceTree = ""; }; 72E006081C5C0BA8006CF057 /* ippfind.man */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ippfind.man; path = ../doc/ippfind.man; sourceTree = ""; }; 72E006091C5C0BA8006CF057 /* ipptool.man */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ipptool.man; path = ../doc/ipptool.man; sourceTree = ""; }; 72E0060A1C5C0BA8006CF057 /* ipptoolfile.man */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ipptoolfile.man; path = ../doc/ipptoolfile.man; sourceTree = ""; }; 72E0060B1C5C0BE3006CF057 /* ippproxy.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = ippproxy.html; path = ../doc/ippproxy.html; sourceTree = ""; }; 72E0060C1C5C0BE3006CF057 /* ippproxy.man */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ippproxy.man; path = ../doc/ippproxy.man; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 2778EBA11D2FF60E00DE72EC /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 2778EBA21D2FF60E00DE72EC /* libiconv.dylib in Frameworks */, 2778EBA31D2FF60E00DE72EC /* libresolv.dylib in Frameworks */, 2778EBA41D2FF60E00DE72EC /* libz.dylib in Frameworks */, 2778EBA51D2FF60E00DE72EC /* libcups_static.a in Frameworks */, 2778EBA61D2FF60E00DE72EC /* ApplicationServices.framework in Frameworks */, 2778EBA71D2FF60E00DE72EC /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 72368673202B657400973022 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 72368674202B657400973022 /* libiconv.dylib in Frameworks */, 72368675202B657400973022 /* libresolv.dylib in Frameworks */, 72368676202B657400973022 /* libz.dylib in Frameworks */, 72368677202B657400973022 /* libcups_static.a in Frameworks */, 72368678202B657400973022 /* ApplicationServices.framework in Frameworks */, 72368679202B657400973022 /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 72368685202B657800973022 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 72368686202B657800973022 /* libiconv.dylib in Frameworks */, 72368687202B657800973022 /* libresolv.dylib in Frameworks */, 72368688202B657800973022 /* libz.dylib in Frameworks */, 72368689202B657800973022 /* libcups_static.a in Frameworks */, 7236868A202B657800973022 /* ApplicationServices.framework in Frameworks */, 7236868B202B657800973022 /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 72368697202B657A00973022 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 72368698202B657A00973022 /* libiconv.dylib in Frameworks */, 72368699202B657A00973022 /* libresolv.dylib in Frameworks */, 7236869A202B657A00973022 /* libz.dylib in Frameworks */, 7236869B202B657A00973022 /* libcups_static.a in Frameworks */, 7236869C202B657A00973022 /* ApplicationServices.framework in Frameworks */, 7236869D202B657A00973022 /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 723686A9202B657B00973022 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 723686AA202B657B00973022 /* libiconv.dylib in Frameworks */, 723686AB202B657B00973022 /* libresolv.dylib in Frameworks */, 723686AC202B657B00973022 /* libz.dylib in Frameworks */, 723686AD202B657B00973022 /* libcups_static.a in Frameworks */, 723686AE202B657B00973022 /* ApplicationServices.framework in Frameworks */, 723686AF202B657B00973022 /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 723686BB202B657D00973022 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 723686BC202B657D00973022 /* libiconv.dylib in Frameworks */, 723686BD202B657D00973022 /* libresolv.dylib in Frameworks */, 723686BE202B657D00973022 /* libz.dylib in Frameworks */, 723686BF202B657D00973022 /* libcups_static.a in Frameworks */, 723686C0202B657D00973022 /* ApplicationServices.framework in Frameworks */, 723686C1202B657D00973022 /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 723686CD202B657E00973022 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 723686CE202B657E00973022 /* libiconv.dylib in Frameworks */, 723686CF202B657E00973022 /* libresolv.dylib in Frameworks */, 723686D0202B657E00973022 /* libz.dylib in Frameworks */, 723686D1202B657E00973022 /* libcups_static.a in Frameworks */, 723686D2202B657E00973022 /* ApplicationServices.framework in Frameworks */, 723686D3202B657E00973022 /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 723686DF202B658000973022 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 723686E0202B658000973022 /* libiconv.dylib in Frameworks */, 723686E1202B658000973022 /* libresolv.dylib in Frameworks */, 723686E2202B658000973022 /* libz.dylib in Frameworks */, 723686E3202B658000973022 /* libcups_static.a in Frameworks */, 723686E4202B658000973022 /* ApplicationServices.framework in Frameworks */, 723686E5202B658000973022 /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 723686F1202B658100973022 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 723686F2202B658100973022 /* libiconv.dylib in Frameworks */, 723686F3202B658100973022 /* libresolv.dylib in Frameworks */, 723686F4202B658100973022 /* libz.dylib in Frameworks */, 723686F5202B658100973022 /* libcups_static.a in Frameworks */, 723686F6202B658100973022 /* ApplicationServices.framework in Frameworks */, 723686F7202B658100973022 /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 72368703202B65D300973022 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 72368704202B65D300973022 /* libiconv.dylib in Frameworks */, 72368705202B65D300973022 /* libresolv.dylib in Frameworks */, 72368706202B65D300973022 /* libz.dylib in Frameworks */, 72368707202B65D300973022 /* libcups_static.a in Frameworks */, 72368708202B65D300973022 /* ApplicationServices.framework in Frameworks */, 72368709202B65D300973022 /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 725C87B51C7664DE00FB3AD5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 725C87B61C7664DE00FB3AD5 /* libiconv.dylib in Frameworks */, 725C87B71C7664DE00FB3AD5 /* libresolv.dylib in Frameworks */, 725C87B81C7664DE00FB3AD5 /* libz.dylib in Frameworks */, 725C87B91C7664DE00FB3AD5 /* libcups_static.a in Frameworks */, 725C87BA1C7664DE00FB3AD5 /* ApplicationServices.framework in Frameworks */, 725C87BB1C7664DE00FB3AD5 /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 72B402151C0CDFB400139783 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 72B403071C0DE7FC00139783 /* Security.framework in Frameworks */, 72B403021C0CE92400139783 /* libiconv.dylib in Frameworks */, 72B403031C0CE92400139783 /* libresolv.dylib in Frameworks */, 72B403041C0CE92400139783 /* libz.dylib in Frameworks */, 72B402EC1C0CE81900139783 /* ApplicationServices.framework in Frameworks */, 72B402ED1C0CE81900139783 /* CoreFoundation.framework in Frameworks */, 72B402EE1C0CE81900139783 /* SystemConfiguration.framework in Frameworks */, 72B402E81C0CE81900139783 /* libcups_static.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 72B402231C0CE0E100139783 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 72B402C61C0CE5EC00139783 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 72B402FD1C0CE8CE00139783 /* libiconv.dylib in Frameworks */, 72B402FE1C0CE8CE00139783 /* libresolv.dylib in Frameworks */, 72B402FA1C0CE87800139783 /* libz.dylib in Frameworks */, 72B402F11C0CE83200139783 /* libcups_static.a in Frameworks */, 72B402F21C0CE83200139783 /* ApplicationServices.framework in Frameworks */, 72B402F31C0CE83200139783 /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 72B402D61C0CE61D00139783 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 72B402FF1C0CE8FE00139783 /* libiconv.dylib in Frameworks */, 72B403001C0CE8FE00139783 /* libresolv.dylib in Frameworks */, 72B403011C0CE8FE00139783 /* libz.dylib in Frameworks */, 72B402F61C0CE84700139783 /* libcups_static.a in Frameworks */, 72B402F71C0CE84700139783 /* ApplicationServices.framework in Frameworks */, 72B402F81C0CE84700139783 /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 72E005F71C5C0B10006CF057 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 72E005F81C5C0B10006CF057 /* libiconv.dylib in Frameworks */, 72E005F91C5C0B10006CF057 /* libresolv.dylib in Frameworks */, 72E005FA1C5C0B10006CF057 /* libz.dylib in Frameworks */, 72E005FB1C5C0B10006CF057 /* libcups_static.a in Frameworks */, 72E005FC1C5C0B10006CF057 /* ApplicationServices.framework in Frameworks */, 72E005FD1C5C0B10006CF057 /* CoreFoundation.framework in Frameworks */, 27E2CC681C99C69400D203EC /* Security.framework in Frameworks */, 27E2CC691C99C6A000D203EC /* SystemConfiguration.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 72368664202B64DE00973022 /* tests */ = { isa = PBXGroup; children = ( 72368667202B652700973022 /* testarray.c */, 72368666202B652700973022 /* testclient.c */, 7236866D202B652700973022 /* testdest.c */, 7236866A202B652700973022 /* testfile.c */, 7236866B202B652700973022 /* testhttp.c */, 72368665202B652600973022 /* testi18n.c */, 72368668202B652700973022 /* testipp.c */, 72368669202B652700973022 /* testoptions.c */, 7236866C202B652700973022 /* testraster.c */, ); name = tests; sourceTree = ""; }; 72B4020F1C0CDFB400139783 = { isa = PBXGroup; children = ( 72B402A11C0CE3AC00139783 /* config.h */, 72B4022A1C0CE16200139783 /* libcups */, 72B4022D1C0CE21C00139783 /* ippserver */, 72368664202B64DE00973022 /* tests */, 72B4022E1C0CE22300139783 /* tools */, 72B402E11C0CE64000139783 /* Documentation */, 72B403051C0DE49600139783 /* Frameworks */, 72B402191C0CDFB400139783 /* Products */, ); sourceTree = ""; }; 72B402191C0CDFB400139783 /* Products */ = { isa = PBXGroup; children = ( 72B402181C0CDFB400139783 /* ippserver */, 72B402261C0CE0E100139783 /* libcups_static.a */, 72B402C91C0CE5EC00139783 /* ipptool */, 72B402D91C0CE61D00139783 /* ippfind */, 72E006021C5C0B10006CF057 /* ippproxy */, 725C87C01C7664DE00FB3AD5 /* ipptransform */, 2778EBAD1D2FF60E00DE72EC /* ipptransform3d */, 7236867F202B657400973022 /* testarray */, 72368691202B657800973022 /* testclient */, 723686A3202B657A00973022 /* testdest */, 723686B5202B657B00973022 /* testfile */, 723686C7202B657D00973022 /* testhttp */, 723686D9202B657E00973022 /* testi18n */, 723686EB202B658000973022 /* testipp */, 723686FD202B658100973022 /* testoptions */, 7236870F202B65D300973022 /* testraster */, ); name = Products; sourceTree = ""; }; 72B4022A1C0CE16200139783 /* libcups */ = { isa = PBXGroup; children = ( 72B4022F1C0CE27800139783 /* array-private.h */, 72B402301C0CE27800139783 /* array.c */, 72B402311C0CE27800139783 /* array.h */, 72B402321C0CE27800139783 /* auth.c */, 72B402331C0CE27800139783 /* cups-private.h */, 72B402341C0CE27800139783 /* cups.h */, 72B402351C0CE27800139783 /* debug-private.h */, 72B402361C0CE27800139783 /* debug.c */, 72737CEF1C24BA4F007CBEF6 /* dest-job.c */, 72737CF01C24BA4F007CBEF6 /* dest-localization.c */, 72737CF11C24BA4F007CBEF6 /* dest-options.c */, 72737CF21C24BA4F007CBEF6 /* dest.c */, 72B402371C0CE27800139783 /* dir.c */, 72B402381C0CE27800139783 /* dir.h */, 72B402391C0CE27800139783 /* encode.c */, 72B4023A1C0CE27800139783 /* error.c */, 72B4023B1C0CE27800139783 /* file-private.h */, 72B4023C1C0CE27800139783 /* file.c */, 72B4023D1C0CE27800139783 /* file.h */, 72B4023E1C0CE27800139783 /* getputfile.c */, 72B4023F1C0CE27800139783 /* globals.c */, 72B402401C0CE27800139783 /* hash.c */, 72B402411C0CE27800139783 /* http-addr.c */, 72B402421C0CE27800139783 /* http-addrlist.c */, 72B402431C0CE27800139783 /* http-private.h */, 72B402441C0CE27800139783 /* http-support.c */, 72B402451C0CE27800139783 /* http.c */, 72B402461C0CE27800139783 /* http.h */, 72530E332028BCF20035FF65 /* ipp-file.c */, 72B402471C0CE27800139783 /* ipp-private.h */, 72B402481C0CE27800139783 /* ipp-support.c */, 72530E342028BCF30035FF65 /* ipp-vars.c */, 72B402491C0CE27800139783 /* ipp.c */, 72B4024A1C0CE27800139783 /* ipp.h */, 72B4024B1C0CE27800139783 /* langprintf.c */, 72B4024C1C0CE27800139783 /* language-private.h */, 72B4024D1C0CE27800139783 /* language.c */, 72B4024E1C0CE27800139783 /* language.h */, 72B4024F1C0CE27800139783 /* md5-private.h */, 72B402501C0CE27800139783 /* md5.c */, 72B402511C0CE27800139783 /* md5passwd.c */, 72737CF41C24BA4F007CBEF6 /* notify.c */, 72B402521C0CE27800139783 /* options.c */, 72B402531C0CE27800139783 /* pwg-media.c */, 72B402541C0CE27800139783 /* pwg-private.h */, 72B402551C0CE27800139783 /* pwg.h */, 72B402561C0CE27800139783 /* raster-private.h */, 72B402571C0CE27800139783 /* raster.c */, 72B402581C0CE27800139783 /* raster.h */, 72B402591C0CE27800139783 /* request.c */, 72B4025A1C0CE27800139783 /* snprintf.c */, 72B4025B1C0CE27800139783 /* string-private.h */, 72B4025C1C0CE27800139783 /* string.c */, 72B4025D1C0CE27800139783 /* tempfile.c */, 72B4025E1C0CE27800139783 /* thread-private.h */, 72B4025F1C0CE27800139783 /* thread.c */, 72B402601C0CE27800139783 /* tls-darwin.c */, 72B402611C0CE27800139783 /* tls-gnutls.c */, 72B402621C0CE27900139783 /* tls-sspi.c */, 72B402631C0CE27900139783 /* tls.c */, 72B402641C0CE27900139783 /* transcode.c */, 72B402651C0CE27900139783 /* transcode.h */, 72B402661C0CE27900139783 /* usersys.c */, 72737CF51C24BA4F007CBEF6 /* util.c */, 72B402671C0CE27900139783 /* versioning.h */, ); name = libcups; sourceTree = ""; }; 72B4022D1C0CE21C00139783 /* ippserver */ = { isa = PBXGroup; children = ( 72B402A31C0CE43D00139783 /* client.c */, 72B402A41C0CE43D00139783 /* conf.c */, 72B402A51C0CE43D00139783 /* device.c */, 72B402A61C0CE43D00139783 /* ipp.c */, 72B402A71C0CE43D00139783 /* ippserver.h */, 72B402A91C0CE43D00139783 /* job.c */, 72B402AA1C0CE43D00139783 /* log.c */, 72B402AB1C0CE43D00139783 /* main.c */, 72B402AC1C0CE43D00139783 /* printer.c */, 72B589F51D1C6628007117DA /* printer-png.h */, 72A0D4521E6864EB0092958D /* printer3d-png.h */, 72B402AE1C0CE43D00139783 /* subscription.c */, 72B402AF1C0CE43D00139783 /* transform.c */, ); name = ippserver; sourceTree = ""; }; 72B4022E1C0CE22300139783 /* tools */ = { isa = PBXGroup; children = ( 275C6BAA1C87D907000D2DE7 /* dither.h */, 72B402D01C0CE60400139783 /* ippfind.c */, 72E006031C5C0B49006CF057 /* ippproxy.c */, 72B402D11C0CE60400139783 /* ipptool.c */, 725C87C31C767CF800FB3AD5 /* ipptransform.c */, 2778EBAE1D2FF62B00DE72EC /* ipptransform3d.c */, ); name = tools; sourceTree = ""; }; 72B402E11C0CE64000139783 /* Documentation */ = { isa = PBXGroup; children = ( 723D66D41C723CB70078B537 /* CONTRIBUTING.md */, 723D66D81C723CC20078B537 /* DESIGN.md */, 72B402E21C0CE66200139783 /* ippfind.html */, 72E006081C5C0BA8006CF057 /* ippfind.man */, 72E0060B1C5C0BE3006CF057 /* ippproxy.html */, 72E0060C1C5C0BE3006CF057 /* ippproxy.man */, 72B402E31C0CE66200139783 /* ippserver.html */, 72B402A81C0CE43D00139783 /* ippserver.man */, 72B402E41C0CE66200139783 /* ipptool.html */, 72E006091C5C0BA8006CF057 /* ipptool.man */, 72B402E51C0CE66200139783 /* ipptoolfile.html */, 72E0060A1C5C0BA8006CF057 /* ipptoolfile.man */, 275C6BA21C878A65000D2DE7 /* ipptransform.html */, 275C6BA31C878A65000D2DE7 /* ipptransform.man */, 27FDC5F61D7F497500246F95 /* ipptransform3d.html */, 27FDC5F71D7F497500246F95 /* ipptransform3d.man */, 279C01D61D1B0F9700F06A84 /* LICENSE */, 729181C42011828E005E7560 /* NOTICE */, 279C01D71D1B0F9700F06A84 /* PI.md */, 723D66D51C723CB70078B537 /* README.md */, ); name = Documentation; sourceTree = ""; }; 72B403051C0DE49600139783 /* Frameworks */ = { isa = PBXGroup; children = ( 72B403061C0DE7FC00139783 /* Security.framework */, 72B402FB1C0CE8CE00139783 /* libiconv.dylib */, 72B402FC1C0CE8CE00139783 /* libresolv.dylib */, 72B402F91C0CE87800139783 /* libz.dylib */, 72B402E91C0CE81900139783 /* ApplicationServices.framework */, 72B402EA1C0CE81900139783 /* CoreFoundation.framework */, 72B402EB1C0CE81900139783 /* SystemConfiguration.framework */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 72B402241C0CE0E100139783 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 72B4028E1C0CE27900139783 /* pwg.h in Headers */, 72B402831C0CE27900139783 /* ipp.h in Headers */, 72A0D4531E6864EB0092958D /* printer3d-png.h in Headers */, 72B4027F1C0CE27900139783 /* http.h in Headers */, 72B402711C0CE27900139783 /* dir.h in Headers */, 72B4026A1C0CE27900139783 /* array.h in Headers */, 72B402A01C0CE27900139783 /* versioning.h in Headers */, 72B402761C0CE27900139783 /* file.h in Headers */, 72B402871C0CE27900139783 /* language.h in Headers */, 72B4028D1C0CE27900139783 /* pwg-private.h in Headers */, 72B4029E1C0CE27900139783 /* transcode.h in Headers */, 72B4026D1C0CE27900139783 /* cups.h in Headers */, 72B402911C0CE27900139783 /* raster.h in Headers */, 72B402971C0CE27900139783 /* thread-private.h in Headers */, 72B4026C1C0CE27900139783 /* cups-private.h in Headers */, 72B4027C1C0CE27900139783 /* http-private.h in Headers */, 72B4026E1C0CE27900139783 /* debug-private.h in Headers */, 72B402851C0CE27900139783 /* language-private.h in Headers */, 72B402681C0CE27900139783 /* array-private.h in Headers */, 72B402941C0CE27900139783 /* string-private.h in Headers */, 72B402881C0CE27900139783 /* md5-private.h in Headers */, 72B402741C0CE27900139783 /* file-private.h in Headers */, 72B402801C0CE27900139783 /* ipp-private.h in Headers */, 72B4028F1C0CE27900139783 /* raster-private.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 2778EB9C1D2FF60E00DE72EC /* ipptransform3d */ = { isa = PBXNativeTarget; buildConfigurationList = 2778EBAA1D2FF60E00DE72EC /* Build configuration list for PBXNativeTarget "ipptransform3d" */; buildPhases = ( 2778EB9F1D2FF60E00DE72EC /* Sources */, 2778EBA11D2FF60E00DE72EC /* Frameworks */, 2778EBA81D2FF60E00DE72EC /* CopyFiles */, ); buildRules = ( ); dependencies = ( 2778EB9D1D2FF60E00DE72EC /* PBXTargetDependency */, ); name = ipptransform3d; productName = ipptool; productReference = 2778EBAD1D2FF60E00DE72EC /* ipptransform3d */; productType = "com.apple.product-type.tool"; }; 7236866E202B657400973022 /* testarray */ = { isa = PBXNativeTarget; buildConfigurationList = 7236867C202B657400973022 /* Build configuration list for PBXNativeTarget "testarray" */; buildPhases = ( 72368671202B657400973022 /* Sources */, 72368673202B657400973022 /* Frameworks */, ); buildRules = ( ); dependencies = ( 7236866F202B657400973022 /* PBXTargetDependency */, ); name = testarray; productName = ippfind; productReference = 7236867F202B657400973022 /* testarray */; productType = "com.apple.product-type.tool"; }; 72368680202B657800973022 /* testclient */ = { isa = PBXNativeTarget; buildConfigurationList = 7236868E202B657800973022 /* Build configuration list for PBXNativeTarget "testclient" */; buildPhases = ( 72368683202B657800973022 /* Sources */, 72368685202B657800973022 /* Frameworks */, ); buildRules = ( ); dependencies = ( 72368681202B657800973022 /* PBXTargetDependency */, ); name = testclient; productName = ippfind; productReference = 72368691202B657800973022 /* testclient */; productType = "com.apple.product-type.tool"; }; 72368692202B657A00973022 /* testdest */ = { isa = PBXNativeTarget; buildConfigurationList = 723686A0202B657A00973022 /* Build configuration list for PBXNativeTarget "testdest" */; buildPhases = ( 72368695202B657A00973022 /* Sources */, 72368697202B657A00973022 /* Frameworks */, ); buildRules = ( ); dependencies = ( 72368693202B657A00973022 /* PBXTargetDependency */, ); name = testdest; productName = ippfind; productReference = 723686A3202B657A00973022 /* testdest */; productType = "com.apple.product-type.tool"; }; 723686A4202B657B00973022 /* testfile */ = { isa = PBXNativeTarget; buildConfigurationList = 723686B2202B657B00973022 /* Build configuration list for PBXNativeTarget "testfile" */; buildPhases = ( 723686A7202B657B00973022 /* Sources */, 723686A9202B657B00973022 /* Frameworks */, ); buildRules = ( ); dependencies = ( 723686A5202B657B00973022 /* PBXTargetDependency */, ); name = testfile; productName = ippfind; productReference = 723686B5202B657B00973022 /* testfile */; productType = "com.apple.product-type.tool"; }; 723686B6202B657D00973022 /* testhttp */ = { isa = PBXNativeTarget; buildConfigurationList = 723686C4202B657D00973022 /* Build configuration list for PBXNativeTarget "testhttp" */; buildPhases = ( 723686B9202B657D00973022 /* Sources */, 723686BB202B657D00973022 /* Frameworks */, ); buildRules = ( ); dependencies = ( 723686B7202B657D00973022 /* PBXTargetDependency */, ); name = testhttp; productName = ippfind; productReference = 723686C7202B657D00973022 /* testhttp */; productType = "com.apple.product-type.tool"; }; 723686C8202B657E00973022 /* testi18n */ = { isa = PBXNativeTarget; buildConfigurationList = 723686D6202B657E00973022 /* Build configuration list for PBXNativeTarget "testi18n" */; buildPhases = ( 723686CB202B657E00973022 /* Sources */, 723686CD202B657E00973022 /* Frameworks */, ); buildRules = ( ); dependencies = ( 723686C9202B657E00973022 /* PBXTargetDependency */, ); name = testi18n; productName = ippfind; productReference = 723686D9202B657E00973022 /* testi18n */; productType = "com.apple.product-type.tool"; }; 723686DA202B658000973022 /* testipp */ = { isa = PBXNativeTarget; buildConfigurationList = 723686E8202B658000973022 /* Build configuration list for PBXNativeTarget "testipp" */; buildPhases = ( 723686DD202B658000973022 /* Sources */, 723686DF202B658000973022 /* Frameworks */, ); buildRules = ( ); dependencies = ( 723686DB202B658000973022 /* PBXTargetDependency */, ); name = testipp; productName = ippfind; productReference = 723686EB202B658000973022 /* testipp */; productType = "com.apple.product-type.tool"; }; 723686EC202B658100973022 /* testoptions */ = { isa = PBXNativeTarget; buildConfigurationList = 723686FA202B658100973022 /* Build configuration list for PBXNativeTarget "testoptions" */; buildPhases = ( 723686EF202B658100973022 /* Sources */, 723686F1202B658100973022 /* Frameworks */, ); buildRules = ( ); dependencies = ( 723686ED202B658100973022 /* PBXTargetDependency */, ); name = testoptions; productName = ippfind; productReference = 723686FD202B658100973022 /* testoptions */; productType = "com.apple.product-type.tool"; }; 723686FE202B65D300973022 /* testraster */ = { isa = PBXNativeTarget; buildConfigurationList = 7236870C202B65D300973022 /* Build configuration list for PBXNativeTarget "testraster" */; buildPhases = ( 72368701202B65D300973022 /* Sources */, 72368703202B65D300973022 /* Frameworks */, ); buildRules = ( ); dependencies = ( 723686FF202B65D300973022 /* PBXTargetDependency */, ); name = testraster; productName = ippfind; productReference = 7236870F202B65D300973022 /* testraster */; productType = "com.apple.product-type.tool"; }; 725C87B01C7664DE00FB3AD5 /* ipptransform */ = { isa = PBXNativeTarget; buildConfigurationList = 725C87BD1C7664DE00FB3AD5 /* Build configuration list for PBXNativeTarget "ipptransform" */; buildPhases = ( 725C87B31C7664DE00FB3AD5 /* Sources */, 725C87B51C7664DE00FB3AD5 /* Frameworks */, 725C87BC1C7664DE00FB3AD5 /* CopyFiles */, ); buildRules = ( ); dependencies = ( 725C87B11C7664DE00FB3AD5 /* PBXTargetDependency */, ); name = ipptransform; productName = ipptool; productReference = 725C87C01C7664DE00FB3AD5 /* ipptransform */; productType = "com.apple.product-type.tool"; }; 72B402171C0CDFB400139783 /* ippserver */ = { isa = PBXNativeTarget; buildConfigurationList = 72B4021F1C0CDFB400139783 /* Build configuration list for PBXNativeTarget "ippserver" */; buildPhases = ( 72B402141C0CDFB400139783 /* Sources */, 72B402151C0CDFB400139783 /* Frameworks */, 72B402161C0CDFB400139783 /* CopyFiles */, ); buildRules = ( ); dependencies = ( 72B402E71C0CE7EA00139783 /* PBXTargetDependency */, ); name = ippserver; productName = ippsample; productReference = 72B402181C0CDFB400139783 /* ippserver */; productType = "com.apple.product-type.tool"; }; 72B402251C0CE0E100139783 /* libcups_static */ = { isa = PBXNativeTarget; buildConfigurationList = 72B402271C0CE0E100139783 /* Build configuration list for PBXNativeTarget "libcups_static" */; buildPhases = ( 72B402221C0CE0E100139783 /* Sources */, 72B402231C0CE0E100139783 /* Frameworks */, 72B402241C0CE0E100139783 /* Headers */, ); buildRules = ( ); dependencies = ( ); name = libcups_static; productName = libcups; productReference = 72B402261C0CE0E100139783 /* libcups_static.a */; productType = "com.apple.product-type.library.static"; }; 72B402C81C0CE5EC00139783 /* ipptool */ = { isa = PBXNativeTarget; buildConfigurationList = 72B402CD1C0CE5EC00139783 /* Build configuration list for PBXNativeTarget "ipptool" */; buildPhases = ( 72B402C51C0CE5EC00139783 /* Sources */, 72B402C61C0CE5EC00139783 /* Frameworks */, 72B402C71C0CE5EC00139783 /* CopyFiles */, 275C6BA71C878A98000D2DE7 /* CopyFiles */, ); buildRules = ( ); dependencies = ( 72B402F01C0CE82100139783 /* PBXTargetDependency */, ); name = ipptool; productName = ipptool; productReference = 72B402C91C0CE5EC00139783 /* ipptool */; productType = "com.apple.product-type.tool"; }; 72B402D81C0CE61D00139783 /* ippfind */ = { isa = PBXNativeTarget; buildConfigurationList = 72B402DD1C0CE61D00139783 /* Build configuration list for PBXNativeTarget "ippfind" */; buildPhases = ( 72B402D51C0CE61D00139783 /* Sources */, 72B402D61C0CE61D00139783 /* Frameworks */, 72B402D71C0CE61D00139783 /* CopyFiles */, ); buildRules = ( ); dependencies = ( 72B402F51C0CE83A00139783 /* PBXTargetDependency */, ); name = ippfind; productName = ippfind; productReference = 72B402D91C0CE61D00139783 /* ippfind */; productType = "com.apple.product-type.tool"; }; 72E005F21C5C0B10006CF057 /* ippproxy */ = { isa = PBXNativeTarget; buildConfigurationList = 72E005FF1C5C0B10006CF057 /* Build configuration list for PBXNativeTarget "ippproxy" */; buildPhases = ( 72E005F51C5C0B10006CF057 /* Sources */, 72E005F71C5C0B10006CF057 /* Frameworks */, 72E005FE1C5C0B10006CF057 /* CopyFiles */, ); buildRules = ( ); dependencies = ( 72E005F31C5C0B10006CF057 /* PBXTargetDependency */, ); name = ippproxy; productName = ipptool; productReference = 72E006021C5C0B10006CF057 /* ippproxy */; productType = "com.apple.product-type.tool"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 72B402101C0CDFB400139783 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0930; ORGANIZATIONNAME = "IEEE-ISTO Printer Working Group"; TargetAttributes = { 72B402171C0CDFB400139783 = { CreatedOnToolsVersion = 7.1; }; 72B402251C0CE0E100139783 = { CreatedOnToolsVersion = 7.1; }; 72B402C81C0CE5EC00139783 = { CreatedOnToolsVersion = 7.1; }; 72B402D81C0CE61D00139783 = { CreatedOnToolsVersion = 7.1; }; 72E0060D1C5C0C48006CF057 = { CreatedOnToolsVersion = 7.3; }; }; }; buildConfigurationList = 72B402131C0CDFB400139783 /* Build configuration list for PBXProject "ippsample" */; compatibilityVersion = "Xcode 8.0"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = 72B4020F1C0CDFB400139783; productRefGroup = 72B402191C0CDFB400139783 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 72E0060D1C5C0C48006CF057 /* All */, 72B402251C0CE0E100139783 /* libcups_static */, 72B402D81C0CE61D00139783 /* ippfind */, 72E005F21C5C0B10006CF057 /* ippproxy */, 72B402171C0CDFB400139783 /* ippserver */, 72B402C81C0CE5EC00139783 /* ipptool */, 725C87B01C7664DE00FB3AD5 /* ipptransform */, 2778EB9C1D2FF60E00DE72EC /* ipptransform3d */, 7236866E202B657400973022 /* testarray */, 72368680202B657800973022 /* testclient */, 72368692202B657A00973022 /* testdest */, 723686A4202B657B00973022 /* testfile */, 723686B6202B657D00973022 /* testhttp */, 723686C8202B657E00973022 /* testi18n */, 723686DA202B658000973022 /* testipp */, 723686EC202B658100973022 /* testoptions */, 723686FE202B65D300973022 /* testraster */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ 2778EB9F1D2FF60E00DE72EC /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 2778EBB01D2FF64300DE72EC /* ipptransform3d.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 72368671202B657400973022 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 72368718202B663A00973022 /* testarray.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 72368683202B657800973022 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 72368717202B663200973022 /* testclient.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 72368695202B657A00973022 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 72368716202B662900973022 /* testdest.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 723686A7202B657B00973022 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 72368715202B661E00973022 /* testfile.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 723686B9202B657D00973022 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 72368714202B661200973022 /* testhttp.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 723686CB202B657E00973022 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 72368713202B660900973022 /* testi18n.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 723686DD202B658000973022 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 72368712202B65FE00973022 /* testipp.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 723686EF202B658100973022 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 72368711202B65F300973022 /* testoptions.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 72368701202B65D300973022 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 72368710202B65E700973022 /* testraster.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 725C87B31C7664DE00FB3AD5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 725C87C41C767CF800FB3AD5 /* ipptransform.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 72B402141C0CDFB400139783 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 72B402C01C0CE46800139783 /* log.c in Sources */, 72B402C31C0CE46800139783 /* subscription.c in Sources */, 72B402C41C0CE46800139783 /* transform.c in Sources */, 72B402BD1C0CE45F00139783 /* device.c in Sources */, 72B402BF1C0CE46800139783 /* job.c in Sources */, 72B402BB1C0CE45A00139783 /* client.c in Sources */, 72B402BC1C0CE45F00139783 /* conf.c in Sources */, 72B402BE1C0CE45F00139783 /* ipp.c in Sources */, 72B402C21C0CE46800139783 /* printer.c in Sources */, 72B402C11C0CE46800139783 /* main.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 72B402221C0CE0E100139783 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 72B402731C0CE27900139783 /* error.c in Sources */, 72B4026F1C0CE27900139783 /* debug.c in Sources */, 72B402751C0CE27900139783 /* file.c in Sources */, 72B402861C0CE27900139783 /* language.c in Sources */, 72B402901C0CE27900139783 /* raster.c in Sources */, 72B4028B1C0CE27900139783 /* options.c in Sources */, 72B402781C0CE27900139783 /* globals.c in Sources */, 72B402891C0CE27900139783 /* md5.c in Sources */, 72B4027D1C0CE27900139783 /* http-support.c in Sources */, 72B4029C1C0CE27900139783 /* tls.c in Sources */, 72737CF91C24BA4F007CBEF6 /* dest.c in Sources */, 72B4027B1C0CE27900139783 /* http-addrlist.c in Sources */, 72B4027A1C0CE27900139783 /* http-addr.c in Sources */, 72B402701C0CE27900139783 /* dir.c in Sources */, 72B402811C0CE27900139783 /* ipp-support.c in Sources */, 72B402791C0CE27900139783 /* hash.c in Sources */, 72B4028A1C0CE27900139783 /* md5passwd.c in Sources */, 72B402691C0CE27900139783 /* array.c in Sources */, 72B402721C0CE27900139783 /* encode.c in Sources */, 72737CF71C24BA4F007CBEF6 /* dest-localization.c in Sources */, 72530E362028BCF30035FF65 /* ipp-vars.c in Sources */, 72B4029D1C0CE27900139783 /* transcode.c in Sources */, 72737CFC1C24BA4F007CBEF6 /* util.c in Sources */, 72737CF61C24BA4F007CBEF6 /* dest-job.c in Sources */, 72B4027E1C0CE27900139783 /* http.c in Sources */, 72B402841C0CE27900139783 /* langprintf.c in Sources */, 72B402961C0CE27900139783 /* tempfile.c in Sources */, 72B402921C0CE27900139783 /* request.c in Sources */, 72B402771C0CE27900139783 /* getputfile.c in Sources */, 72B402931C0CE27900139783 /* snprintf.c in Sources */, 72B402951C0CE27900139783 /* string.c in Sources */, 72737CFB1C24BA4F007CBEF6 /* notify.c in Sources */, 72B4028C1C0CE27900139783 /* pwg-media.c in Sources */, 72B402981C0CE27900139783 /* thread.c in Sources */, 72530E352028BCF30035FF65 /* ipp-file.c in Sources */, 72B4026B1C0CE27900139783 /* auth.c in Sources */, 72B4029F1C0CE27900139783 /* usersys.c in Sources */, 72737CF81C24BA4F007CBEF6 /* dest-options.c in Sources */, 72B402821C0CE27900139783 /* ipp.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 72B402C51C0CE5EC00139783 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 72B402D41C0CE60800139783 /* ipptool.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 72B402D51C0CE61D00139783 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 72B402E01C0CE62C00139783 /* ippfind.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 72E005F51C5C0B10006CF057 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 72E006071C5C0B65006CF057 /* ippproxy.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 2778EB9D1D2FF60E00DE72EC /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 2778EB9E1D2FF60E00DE72EC /* PBXContainerItemProxy */; }; 2778EBB21D2FF67B00DE72EC /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 2778EB9C1D2FF60E00DE72EC /* ipptransform3d */; targetProxy = 2778EBB11D2FF67B00DE72EC /* PBXContainerItemProxy */; }; 7236866F202B657400973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 72368670202B657400973022 /* PBXContainerItemProxy */; }; 72368681202B657800973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 72368682202B657800973022 /* PBXContainerItemProxy */; }; 72368693202B657A00973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 72368694202B657A00973022 /* PBXContainerItemProxy */; }; 723686A5202B657B00973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 723686A6202B657B00973022 /* PBXContainerItemProxy */; }; 723686B7202B657D00973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 723686B8202B657D00973022 /* PBXContainerItemProxy */; }; 723686C9202B657E00973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 723686CA202B657E00973022 /* PBXContainerItemProxy */; }; 723686DB202B658000973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 723686DC202B658000973022 /* PBXContainerItemProxy */; }; 723686ED202B658100973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 723686EE202B658100973022 /* PBXContainerItemProxy */; }; 723686FF202B65D300973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 72368700202B65D300973022 /* PBXContainerItemProxy */; }; 7236871A202B669700973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 7236866E202B657400973022 /* testarray */; targetProxy = 72368719202B669700973022 /* PBXContainerItemProxy */; }; 7236871C202B669700973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72368680202B657800973022 /* testclient */; targetProxy = 7236871B202B669700973022 /* PBXContainerItemProxy */; }; 7236871E202B669700973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72368692202B657A00973022 /* testdest */; targetProxy = 7236871D202B669700973022 /* PBXContainerItemProxy */; }; 72368720202B669700973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 723686A4202B657B00973022 /* testfile */; targetProxy = 7236871F202B669700973022 /* PBXContainerItemProxy */; }; 72368722202B669700973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 723686B6202B657D00973022 /* testhttp */; targetProxy = 72368721202B669700973022 /* PBXContainerItemProxy */; }; 72368724202B669700973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 723686C8202B657E00973022 /* testi18n */; targetProxy = 72368723202B669700973022 /* PBXContainerItemProxy */; }; 72368726202B669700973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 723686DA202B658000973022 /* testipp */; targetProxy = 72368725202B669700973022 /* PBXContainerItemProxy */; }; 72368728202B669700973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 723686EC202B658100973022 /* testoptions */; targetProxy = 72368727202B669700973022 /* PBXContainerItemProxy */; }; 7236872A202B669700973022 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 723686FE202B65D300973022 /* testraster */; targetProxy = 72368729202B669700973022 /* PBXContainerItemProxy */; }; 725C87B11C7664DE00FB3AD5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 725C87B21C7664DE00FB3AD5 /* PBXContainerItemProxy */; }; 725C87C21C7664EF00FB3AD5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 725C87B01C7664DE00FB3AD5 /* ipptransform */; targetProxy = 725C87C11C7664EF00FB3AD5 /* PBXContainerItemProxy */; }; 72B402E71C0CE7EA00139783 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 72B402E61C0CE7EA00139783 /* PBXContainerItemProxy */; }; 72B402F01C0CE82100139783 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 72B402EF1C0CE82100139783 /* PBXContainerItemProxy */; }; 72B402F51C0CE83A00139783 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 72B402F41C0CE83A00139783 /* PBXContainerItemProxy */; }; 72E005F31C5C0B10006CF057 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 72E005F41C5C0B10006CF057 /* PBXContainerItemProxy */; }; 72E006121C5C0C52006CF057 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402251C0CE0E100139783 /* libcups_static */; targetProxy = 72E006111C5C0C52006CF057 /* PBXContainerItemProxy */; }; 72E006141C5C0C52006CF057 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402D81C0CE61D00139783 /* ippfind */; targetProxy = 72E006131C5C0C52006CF057 /* PBXContainerItemProxy */; }; 72E006161C5C0C52006CF057 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72E005F21C5C0B10006CF057 /* ippproxy */; targetProxy = 72E006151C5C0C52006CF057 /* PBXContainerItemProxy */; }; 72E006181C5C0C52006CF057 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402171C0CDFB400139783 /* ippserver */; targetProxy = 72E006171C5C0C52006CF057 /* PBXContainerItemProxy */; }; 72E0061A1C5C0C52006CF057 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72B402C81C0CE5EC00139783 /* ipptool */; targetProxy = 72E006191C5C0C52006CF057 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 2778EBAB1D2FF60E00DE72EC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 2778EBAC1D2FF60E00DE72EC /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 7236867D202B657400973022 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Debug; }; 7236867E202B657400973022 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Release; }; 7236868F202B657800973022 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Debug; }; 72368690202B657800973022 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Release; }; 723686A1202B657A00973022 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Debug; }; 723686A2202B657A00973022 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Release; }; 723686B3202B657B00973022 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Debug; }; 723686B4202B657B00973022 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Release; }; 723686C5202B657D00973022 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Debug; }; 723686C6202B657D00973022 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Release; }; 723686D7202B657E00973022 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Debug; }; 723686D8202B657E00973022 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Release; }; 723686E9202B658000973022 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Debug; }; 723686EA202B658000973022 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Release; }; 723686FB202B658100973022 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Debug; }; 723686FC202B658100973022 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Release; }; 7236870D202B65D300973022 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Debug; }; 7236870E202B65D300973022 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Release; }; 725C87BE1C7664DE00FB3AD5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 725C87BF1C7664DE00FB3AD5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 72B4021D1C0CDFB400139783 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPRESSION = lossless; CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1.0; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( _CUPS_SOURCE, "DEBUG=1", "$(inherited)", ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_PEDANTIC = YES; GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_PARAMETER = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ( ., .., ); MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; RUN_CLANG_STATIC_ANALYZER = YES; SDKROOT = macosx; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 72B4021E1C0CDFB400139783 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPRESSION = "respect-asset-catalog"; CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "Developer ID Application"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1.0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = _CUPS_SOURCE; GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_PEDANTIC = YES; GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_PARAMETER = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ( ., .., ); MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; RUN_CLANG_STATIC_ANALYZER = YES; SDKROOT = macosx; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; 72B402201C0CDFB400139783 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 72B402211C0CDFB400139783 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 72B402281C0CE0E100139783 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; COMBINE_HIDPI_IMAGES = YES; EXECUTABLE_PREFIX = ""; PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/cups; PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/cups; }; name = Debug; }; 72B402291C0CE0E100139783 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; COMBINE_HIDPI_IMAGES = YES; EXECUTABLE_PREFIX = ""; PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/cups; PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/cups; }; name = Release; }; 72B402CE1C0CE5EC00139783 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 72B402CF1C0CE5EC00139783 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 72B402DE1C0CE61D00139783 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 72B402DF1C0CE61D00139783 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 72E006001C5C0B10006CF057 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 72E006011C5C0B10006CF057 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; GCC_C_LANGUAGE_STANDARD = gnu99; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 72E0060F1C5C0C48006CF057 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 72E006101C5C0C48006CF057 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_WEAK = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 2778EBAA1D2FF60E00DE72EC /* Build configuration list for PBXNativeTarget "ipptransform3d" */ = { isa = XCConfigurationList; buildConfigurations = ( 2778EBAB1D2FF60E00DE72EC /* Debug */, 2778EBAC1D2FF60E00DE72EC /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 7236867C202B657400973022 /* Build configuration list for PBXNativeTarget "testarray" */ = { isa = XCConfigurationList; buildConfigurations = ( 7236867D202B657400973022 /* Debug */, 7236867E202B657400973022 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 7236868E202B657800973022 /* Build configuration list for PBXNativeTarget "testclient" */ = { isa = XCConfigurationList; buildConfigurations = ( 7236868F202B657800973022 /* Debug */, 72368690202B657800973022 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 723686A0202B657A00973022 /* Build configuration list for PBXNativeTarget "testdest" */ = { isa = XCConfigurationList; buildConfigurations = ( 723686A1202B657A00973022 /* Debug */, 723686A2202B657A00973022 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 723686B2202B657B00973022 /* Build configuration list for PBXNativeTarget "testfile" */ = { isa = XCConfigurationList; buildConfigurations = ( 723686B3202B657B00973022 /* Debug */, 723686B4202B657B00973022 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 723686C4202B657D00973022 /* Build configuration list for PBXNativeTarget "testhttp" */ = { isa = XCConfigurationList; buildConfigurations = ( 723686C5202B657D00973022 /* Debug */, 723686C6202B657D00973022 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 723686D6202B657E00973022 /* Build configuration list for PBXNativeTarget "testi18n" */ = { isa = XCConfigurationList; buildConfigurations = ( 723686D7202B657E00973022 /* Debug */, 723686D8202B657E00973022 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 723686E8202B658000973022 /* Build configuration list for PBXNativeTarget "testipp" */ = { isa = XCConfigurationList; buildConfigurations = ( 723686E9202B658000973022 /* Debug */, 723686EA202B658000973022 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 723686FA202B658100973022 /* Build configuration list for PBXNativeTarget "testoptions" */ = { isa = XCConfigurationList; buildConfigurations = ( 723686FB202B658100973022 /* Debug */, 723686FC202B658100973022 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 7236870C202B65D300973022 /* Build configuration list for PBXNativeTarget "testraster" */ = { isa = XCConfigurationList; buildConfigurations = ( 7236870D202B65D300973022 /* Debug */, 7236870E202B65D300973022 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 725C87BD1C7664DE00FB3AD5 /* Build configuration list for PBXNativeTarget "ipptransform" */ = { isa = XCConfigurationList; buildConfigurations = ( 725C87BE1C7664DE00FB3AD5 /* Debug */, 725C87BF1C7664DE00FB3AD5 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 72B402131C0CDFB400139783 /* Build configuration list for PBXProject "ippsample" */ = { isa = XCConfigurationList; buildConfigurations = ( 72B4021D1C0CDFB400139783 /* Debug */, 72B4021E1C0CDFB400139783 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 72B4021F1C0CDFB400139783 /* Build configuration list for PBXNativeTarget "ippserver" */ = { isa = XCConfigurationList; buildConfigurations = ( 72B402201C0CDFB400139783 /* Debug */, 72B402211C0CDFB400139783 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 72B402271C0CE0E100139783 /* Build configuration list for PBXNativeTarget "libcups_static" */ = { isa = XCConfigurationList; buildConfigurations = ( 72B402281C0CE0E100139783 /* Debug */, 72B402291C0CE0E100139783 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 72B402CD1C0CE5EC00139783 /* Build configuration list for PBXNativeTarget "ipptool" */ = { isa = XCConfigurationList; buildConfigurations = ( 72B402CE1C0CE5EC00139783 /* Debug */, 72B402CF1C0CE5EC00139783 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 72B402DD1C0CE61D00139783 /* Build configuration list for PBXNativeTarget "ippfind" */ = { isa = XCConfigurationList; buildConfigurations = ( 72B402DE1C0CE61D00139783 /* Debug */, 72B402DF1C0CE61D00139783 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 72E005FF1C5C0B10006CF057 /* Build configuration list for PBXNativeTarget "ippproxy" */ = { isa = XCConfigurationList; buildConfigurations = ( 72E006001C5C0B10006CF057 /* Debug */, 72E006011C5C0B10006CF057 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 72E0060E1C5C0C48006CF057 /* Build configuration list for PBXAggregateTarget "All" */ = { isa = XCConfigurationList; buildConfigurations = ( 72E0060F1C5C0C48006CF057 /* Debug */, 72E006101C5C0C48006CF057 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 72B402101C0CDFB400139783 /* Project object */; } ippsample/xcode/config.h0000644000175000017500000001522513240604116014264 0ustar tilltill/* * Configuration file for the IPP samples. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright * law. Distribution and use rights are outlined in the file "LICENSE.txt" * which should have been included with this file. If this file is * missing or damaged, see the license at "http://www.cups.org/". */ #ifndef _CUPS_CONFIG_H_ #define _CUPS_CONFIG_H_ /* * Version of software... */ #define CUPS_SVERSION "IPPSAMPLE v1.0b1" #define CUPS_MINIMAL "IPPSAMPLE/1.0b1" /* * Default IPP port... */ #define CUPS_DEFAULT_IPP_PORT 631 /* * Do we have domain socket support, and if so what is the default one? */ #define CUPS_DEFAULT_DOMAINSOCKET "${prefix}/var/run/cupsd" /* * Where are files stored? * * Note: These are defaults, which can be overridden by environment * variables at run-time... */ #define CUPS_CACHEDIR "/var/cache/cups" #define CUPS_DATADIR "/usr/share/cups" #define CUPS_LOCALEDIR "/usr/share/locale" #define CUPS_SERVERBIN "" #define CUPS_SERVERROOT "/etc/cups" #define CUPS_STATEDIR "/var/run/cups" /* * Do we have posix_spawn? */ #define HAVE_POSIX_SPAWN 1 /* * Do we have ZLIB? */ #define HAVE_LIBZ 1 #define HAVE_INFLATECOPY 1 /* * Use ? */ #define HAVE_STDINT_H 1 /* * Use , , and/or ? */ #define HAVE_STRING_H 1 #define HAVE_STRINGS_H 1 /* #undef HAVE_BSTRING_H */ /* * Do we have the long long type? */ #define HAVE_LONG_LONG 1 #ifdef HAVE_LONG_LONG # define CUPS_LLFMT "%lld" # define CUPS_LLCAST (long long) #else # define CUPS_LLFMT "%ld" # define CUPS_LLCAST (long) #endif /* HAVE_LONG_LONG */ /* * Do we have the strtoll() function? */ #define HAVE_STRTOLL 1 #ifndef HAVE_STRTOLL # define strtoll(nptr,endptr,base) strtol((nptr), (endptr), (base)) #endif /* !HAVE_STRTOLL */ /* * Do we have the strXXX() functions? */ #define HAVE_STRDUP 1 #define HAVE_STRLCAT 1 #define HAVE_STRLCPY 1 /* * Do we have the (v)snprintf() functions? */ #define HAVE_SNPRINTF 1 #define HAVE_VSNPRINTF 1 /* * What signal functions to use? */ #define HAVE_SIGSET 1 #define HAVE_SIGACTION 1 /* * What wait functions to use? */ #define HAVE_WAITPID 1 #define HAVE_WAIT3 1 /* * Do we have the langinfo.h header file? */ #define HAVE_LANGINFO_H 1 /* * Which encryption libraries do we have? */ #define HAVE_CDSASSL 1 /* #undef HAVE_GNUTLS */ /* #undef HAVE_SSPISSL */ #define HAVE_SSL 1 /* * Do we have the gnutls_transport_set_pull_timeout_function function? */ /* #undef HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION */ /* * Do we have the gnutls_priority_set_direct function? */ /* #undef HAVE_GNUTLS_PRIORITY_SET_DIRECT */ /* * What Security framework headers do we have? */ /* #undef HAVE_AUTHORIZATION_H */ /* #undef HAVE_SECBASEPRIV_H */ #define HAVE_SECCERTIFICATE_H 1 /* #undef HAVE_SECIDENTITYSEARCHPRIV_H */ #define HAVE_SECITEM_H 1 /* #undef HAVE_SECITEMPRIV_H */ #define HAVE_SECPOLICY_H 1 /* #undef HAVE_SECPOLICYPRIV_H */ /* #undef HAVE_SECURETRANSPORTPRIV_H */ /* * Do we have the cssmErrorString function? */ #define HAVE_CSSMERRORSTRING 1 /* * Do we have the SecGenerateSelfSignedCertificate function? */ /* #undef HAVE_SECGENERATESELFSIGNEDCERTIFICATE */ /* * Do we have the SecKeychainOpen function? */ #define HAVE_SECKEYCHAINOPEN 1 /* * Do we have (a working) SSLSetEnabledCiphers function? */ #define HAVE_SSLSETENABLEDCIPHERS 1 /* * Do we have mDNSResponder for DNS Service Discovery (aka Bonjour)? */ #define HAVE_DNSSD 1 /* * Do we have Avahi for DNS Service Discovery (aka Bonjour)? */ /* #undef HAVE_AVAHI */ /* * Does the "stat" structure contain the "st_gen" member? */ #define HAVE_ST_GEN 1 /* * Does the "tm" structure contain the "tm_gmtoff" member? */ #define HAVE_TM_GMTOFF 1 /* * Do we have getaddrinfo()? */ #define HAVE_GETADDRINFO 1 /* * Do we have getnameinfo()? */ #define HAVE_GETNAMEINFO 1 /* * Do we have getifaddrs()? */ #define HAVE_GETIFADDRS 1 /* * Do we have hstrerror()? */ #define HAVE_HSTRERROR 1 /* * Do we have res_init()? */ #define HAVE_RES_INIT 1 /* * Do we have */ #define HAVE_RESOLV_H 1 /* * Do we have the header file? */ #define HAVE_SYS_SOCKIO_H 1 /* * Does the sockaddr structure contain an sa_len parameter? */ /* #undef HAVE_STRUCT_SOCKADDR_SA_LEN */ /* * Do we have pthread support? */ #define HAVE_PTHREAD_H 1 /* * Do we have CoreFoundation public and private headers? */ #define HAVE_COREFOUNDATION_H 1 /* #undef HAVE_CFPRIV_H */ /* #undef HAVE_CFBUNDLEPRIV_H */ /* * Do we have ApplicationServices public headers? */ #define HAVE_APPLICATIONSERVICES_H 1 /* * Do we have the MuPDF library? */ /* #undef HAVE_MUPDF */ /* * Select/poll interfaces... */ #define HAVE_POLL 1 /* #undef HAVE_EPOLL */ #define HAVE_KQUEUE 1 /* * Do we have ? */ #define HAVE_SYS_PARAM_H 1 /* * Do we have ? */ #define HAVE_SYS_UCRED_H 1 /* * Do we have removefile()? */ /* #undef HAVE_REMOVEFILE */ /* * Which random number generator function to use... */ #define HAVE_ARC4RANDOM 1 #define HAVE_RANDOM 1 #define HAVE_LRAND48 1 #ifdef HAVE_ARC4RANDOM # define CUPS_RAND() arc4random() # define CUPS_SRAND(v) #elif defined(HAVE_RANDOM) # define CUPS_RAND() random() # define CUPS_SRAND(v) srandom(v) #elif defined(HAVE_LRAND48) # define CUPS_RAND() lrand48() # define CUPS_SRAND(v) srand48(v) #else # define CUPS_RAND() rand() # define CUPS_SRAND(v) srand(v) #endif /* HAVE_ARC4RANDOM */ /* * Do we have ? */ #define HAVE_ICONV_H 1 /* * Do we have statfs or statvfs and one of the corresponding headers? */ #define HAVE_STATFS 1 #define HAVE_STATVFS 1 #define HAVE_SYS_MOUNT_H 1 /* #undef HAVE_SYS_STATFS_H */ #define HAVE_SYS_STATVFS_H 1 /* #undef HAVE_SYS_VFS_H */ /* * Location of macOS localization bundle, if any. */ /* #undef CUPS_BUNDLEDIR */ /* * Do we have the C99 abs() function? */ #define HAVE_ABS 1 #if !defined(HAVE_ABS) && !defined(abs) # if defined(__GNUC__) || __STDC_VERSION__ >= 199901L # define abs(x) _cups_abs(x) static inline int _cups_abs(int i) { return (i < 0 ? -i : i); } # elif defined(_MSC_VER) # define abs(x) _cups_abs(x) static __inline int _cups_abs(int i) { return (i < 0 ? -i : i); } # else # define abs(x) ((x) < 0 ? -(x) : (x)) # endif /* __GNUC__ || __STDC_VERSION__ */ #endif /* !HAVE_ABS && !abs */ /* * Do we have the Cura software? */ #define CURAENGINE "/Applications/Cura/Cura.app/Contents/Resources/CuraEngine" #endif /* !_CUPS_CONFIG_H_ */ ippsample/DEVELOPING.md0000644000175000017500000004744713240604116013535 0ustar tilltillDeveloping for the IPP Sample Code Project ========================================== Please see the file `CONTRIBUTING.md` for information on contributing to the IPP sample code project. How To Contact The Developers ----------------------------- The IPP workgroup mailing list is the primary means of asking questions and informally discussing issues and feature requests with the developers. The IPP workgroup home page provides more information and links: https://www.pwg.org/ipp Build System ------------ The build system uses GNU autoconf to tailor the library to the local operating system. Project files for the current release of Microsoft Visual Studio are also provided for Microsoft Windows®. To improve portability, makefiles must not make use of features unique to GNU make. See the MAKEFILE GUIDELINES section for a description of the allowed make features and makefile guidelines. Additional GNU build programs such as GNU automake and GNU libtool must not be used. GNU automake produces non-portable makefiles which depend on GNU- specific extensions, and GNU libtool is not portable or reliable enough for the IPP Sample Code. Version Numbering ----------------- The IPP sample code uses a three-part version number separated by periods to represent the major, minor, and patch release numbers. Major release numbers indicate large design changes or backwards-incompatible changes to the client library. Minor release numbers indicate new features and other smaller changes which are backwards-compatible with previous releases. Patch numbers indicate bug fixes to the previous feature or patch release. > Note: > > When we talk about compatibility, we are talking about binary compatibility > for public APIs and output format compatibility for program interfaces. > Changes to configuration file formats or the default behavior of programs > are not generally considered incompatible as the upgrade process can > normally address such changes gracefully. Production releases use the plain version numbers: MAJOR.MINOR.PATCH 1.0.0 ... 1.1.0 ... 1.1.23 ... 2.0.0 ... 2.1.0 2.1.1 2.1.2 2.1.3 The first production release in a MAJOR.MINOR series (MAJOR.MINOR.0) is called a feature release. Feature releases are the only releases that may contain new features. Subsequent production releases in a MAJOR.MINOR series may only contain bug fixes. Beta-test releases are identified by appending the letter B to the major and minor version numbers followed by the beta release number: MAJOR.MINORbNUMBER 2.2b1 Release candidates are identified by appending the letters RC to the major and minor version numbers followed by the release candidate number: MAJOR.MINORrcNUMBER 2.2rc1 Coding Guidelines ----------------- Contributed source code must follow the guidelines below. While the examples are for C and C++ source files, source code for other languages should conform to the same guidelines as allowed by the language. ### Source Files All source files names must be 16 characters or less in length to ensure compatibility with older UNIX filesystems. Source files containing functions have an extension of ".c" for C and ".cxx" for C++ source files. All other "include" files have an extension of ".h". Tabs are set to 8 characters or columns. > Note: > > The ".cxx" extension is used because it is the only common C++ extension > between Linux, macOS, UNIX, and Windows. The top of each source file contains a header giving the purpose or nature of the source file and the copyright and licensing notice: /* * Description of file contents. * * Copyright 2017 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ ### Header Files Private API header files must be named with the suffix "-private", for example the "cups.h" header file defines all of the public APIs while the "cups-private.h" header file defines all of the private APIs. Typically a private API header file will include the corresponding public API header file. ### Comments All source code utilizes block comments within functions to describe the operations being performed by a group of statements; avoid putting a comment per line unless absolutely necessary, and then consider refactoring the code so that it is not necessary. C source files use the block comment format ("/* comment */") since many vendor C compilers still do not support C99/C++ comments ("// comment"): /* * Clear the state array before we begin... */ for (i = 0; i < (sizeof(array) / sizeof(sizeof(array[0])); i ++) array[i] = IPP_STATE_IDLE; /* * Wait for state changes on another thread... */ do { for (i = 0; i < (sizeof(array) / sizeof(sizeof(array[0])); i ++) if (array[i] != IPP_STATE_IDLE) break; if (i == (sizeof(array) / sizeof(array[0]))) sleep(1); } while (i == (sizeof(array) / sizeof(array[0]))); ### Indentation All code blocks enclosed by brackets begin with the opening brace on a new line. The code then follows starting on a new line after the brace and is indented 2 spaces. The closing brace is then placed on a new line following the code at the original indentation: { int i; /* Looping var */ /* * Process foobar values from 0 to 999... */ for (i = 0; i < 1000; i ++) { do_this(i); do_that(i); } } Single-line statements following "do", "else", "for", "if", and "while" are indented 2 spaces as well. Blocks of code in a "switch" block are indented 4 spaces after each "case" and "default" case: switch (array[i]) { case IPP_STATE_IDLE : do_this(i); do_that(i); break; default : do_nothing(i); break; } ### Spacing A space follows each reserved word such as `if`, `while`, etc. Spaces are not inserted between a function name and the arguments in parenthesis. ### Return Values Parenthesis surround values returned from a function: return (IPP_STATE_IDLE); ### Functions Functions with a global scope have a lowercase prefix followed by capitalized words, e.g., `ippDoThis`, `ippDoThat`, `ippDoSomethingElse`, etc. Private global functions begin with a leading underscore, e.g., `_ippDoThis`, `_ippDoThat`, etc. Functions with a local scope are declared static with lowercase names and underscores between words, e.g., `do_this`, `do_that`, `do_something_else`, etc. Each function begins with a comment header describing what the function does, the possible input limits (if any), the possible output values (if any), and any special information needed: /* * 'do_this()' - Compute y = this(x). * * Notes: none. */ static float /* O - Inverse power value, 0.0 <= y <= 1.1 */ do_this(float x) /* I - Power value (0.0 <= x <= 1.1) */ { ... return (y); } Return/output values are indicated using an "O" prefix, input values are indicated using the "I" prefix, and values that are both input and output use the "IO" prefix for the corresponding in-line comment. The Mini-XML documentation generator also understands the following special text in the function description comment: @deprecated@ - Marks the function as deprecated (not recommended for new development and scheduled for removal) @since version@ - Marks the function as new in the specified version. @private@ - Marks the function as private (same as starting the function name with an underscore) ### Variables Variables with a global scope are capitalized, e.g., `ThisVariable`, `ThatVariable`, `ThisStateVariable`, etc. Globals in the client library are either part of the per-thread global values managed by the `_cupsGlobals` function or are suitably protected for concurrent access. Global variables should be replaced by function arguments whenever possible. Variables with a local scope are lowercase with underscores between words, e.g., `this_variable`, `that_variable`, etc. Any "local global" variables shared by functions within a source file are declared static. As for global variables, local static variables are suitably protected for concurrent access. Each variable is declared on a separate line and is immediately followed by a comment block describing the variable: int ThisVariable; /* The current state of this */ static int that_variable; /* The current state of that */ ### Types All type names are lowercase with underscores between words and `_t` appended to the end of the name, e.g., `ipp_this_type_t`, `ipp_that_type_t`, etc. Type names start with a prefix, typically `ipp` or the name of the program, to avoid conflicts with system types. Private type names start with an underscore, e.g., `_ipp_this_t`, `_ipp_that_t`, etc. Each type has a comment block immediately after the typedef: typedef int ipp_this_type_t; /* This type is for foobar options. */ ### Structures All structure names are lowercase with underscores between words and `_s` appended to the end of the name, e.g., `ipp_this_s`, `ipp_that_s`, etc. Structure names start with a prefix, typically `ipp` or the name of the program, to avoid conflicts with system types. Private structure names start with an underscore, e.g., `_ipp_this_s`, `_ipp_that_s`, etc. Each structure has a comment block immediately after the struct and each member is documented similar to the variable naming policy above: struct ipp_this_struct_s /* This structure is for foobar options. */ { int this_member; /* Current state for this */ int that_member; /* Current state for that */ }; ### Constants All constant names are uppercase with underscores between words, e.g., `IPP_THIS_CONSTANT`, `IPP_THAT_CONSTANT`, etc. Constants begin with an uppercase prefix, typically `IPP_` or the program or type name. Private constants start with an underscore, e.g., `_IPP_THIS_CONSTANT`, `_IPP_THAT_CONSTANT`, etc. Typed enumerations should be used whenever possible to allow for type checking by the compiler. Comment blocks immediately follow each constant: typedef enum ipp_tray_e /* Tray enumerations */ { IPP_TRAY_THIS, /* This tray */ IPP_TRAY_THAT /* That tray */ } ipp_tray_t; ## Makefile Guidelines The following is a guide to the makefile-based build system. These standards have been developed over the years to allow the IPP sample code to be built on as many systems and environments as possible. ### General Organization The source code is organized functionally into a top-level makefile, include file, and subdirectories each with their own makefile and dependencies files. The ".in" files are template files for the autoconf software and are used to generate a static version of the corresponding file. ### Makefile Documentation Each makefile starts with the standard header containing the description of the file, and CUPS copyright and license notice: # # Makefile for ... # # Copyright 2017 by the IEEE-ISTO Printer Working Group. # # Licensed under Apache License v2.0. See the file "LICENSE" for more # information. # ### Portable Makefile Construction We use a common subset of make program syntax to ensure that the software can be compiled "out of the box" on as many systems as possible. The following is a list of assumptions we follow when constructing makefiles: - Targets; we assume that the make program supports the notion of simple targets of the form "name:" that perform tab-indented commands that follow the target, e.g.: target: TAB target commands - Dependencies; we assume that the make program supports recursive dependencies on targets, e.g.: target: foo bar TAB target commands foo: bla TAB foo commands bar: TAB bar commands bla: TAB bla commands - Variable Definition; we assume that the make program supports variable definition on the command-line or in the makefile using the following form: name=value - Variable Substitution; we assume that the make program supports variable substitution using the following forms: - `$(name)`; substitutes the value of "name", - `$(name:.old=.new)`; substitutes the value of "name" with the filename extension ".old" changed to ".new", - `$(MAKEFLAGS)`; substitutes the command-line options passed to the program without the leading hyphen (-), - `$$`; substitutes a single $ character, - `$<`; substitutes the current source file or dependency, and - `$@`; substitutes the current target name. - Suffixes; we assume that the make program supports filename suffixes with assumed dependencies, e.g.: .SUFFIXES: .c .o .c.o: TAB $(CC) $(CFLAGS) -o $@ -c $< - Include Files; we assume that the make program supports the include directive, e.g.: include ../Makedefs include Dependencies - Comments; we assume that comments begin with a # character and proceed to the end of the current line. - Line Length; we assume that there is no practical limit to the length of lines. - Continuation of long lines; we assume that the `\` character may be placed at the end of a line to concatenate two or more lines in a makefile to form a single long line. - Shell; we assume a POSIX-compatible shell is present on the build system. ### Standard Variables The following variables are defined in the "Makedefs" file generated by the autoconf software: - `ALL_CFLAGS`; the combined C compiler options, - `ALL_CXXFLAGS`; the combined C++ compiler options, - `AMANDIR`; the administrative man page installation directory (section 8/1m depending on the platform), - `AR`; the library archiver command, - `ARFLAGS`; options for the library archiver command, - `AWK`; the local awk command, - `BINDIR`; the binary installation directory, - `BUILDROOT`; optional installation prefix (defaults to DSTROOT), - `CC`; the C compiler command, - `CFLAGS`; options for the C compiler command, - `CHMOD`; the chmod command, - `CXX`; the C++ compiler command, - `CXXFLAGS`; options for the C++ compiler command, - `DATADIR`; the data file installation directory, - `DSO`; the C shared library building command, - `DSOXX`; the C++ shared library building command, - `DSOFLAGS`; options for the shared library building command, - `INCLUDEDIR`; the public header file installation directory, - `INSTALL`; the install command, - `INSTALL_BIN`; the program installation command, - `INSTALL_COMPDATA`; the compressed data file installation command, - `INSTALL_CONFIG`; the configuration file installation command, - `INSTALL_DATA`; the data file installation command, - `INSTALL_DIR`; the directory installation command, - `INSTALL_LIB`; the library installation command, - `INSTALL_MAN`; the documentation installation command, - `INSTALL_SCRIPT`; the shell script installation command, - `LD`; the linker command, - `LDFLAGS`; options for the linker, - `LIBDIR`; the library installation directory, - `LIBS`; libraries for all programs, - `LN`; the ln command, - `MAN1EXT`; extension for man pages in section 1, - `MAN3EXT`; extension for man pages in section 3, - `MAN5EXT`; extension for man pages in section 5, - `MAN7EXT`; extension for man pages in section 7, - `MAN8DIR`; subdirectory for man pages in section 8, - `MAN8EXT`; extension for man pages in section 8, - `MANDIR`; the man page installation directory, - `OPTIM`; common compiler optimization options, - `PRIVATEINCLUDE`; the private header file installation directory, - `RM`; the rm command, - `SHELL`; the sh (POSIX shell) command, - `STRIP`; the strip command, - `srcdir`; the source directory. ### Standard Targets The following standard targets are defined in each makefile: - `all`; creates all target programs, libraries, and documentation files, - `clean`; removes all target programs libraries, documentation files, and object files, - `depend`; generates automatic dependencies for any C or C++ source files (also see "DEPENDENCIES"), - `distclean`; removes autoconf-generated files in addition to those removed by the "clean" target, - `install`; installs all distribution files in their corresponding locations (also see "INSTALL/UNINSTALL SUPPORT"), - `install-data`; installs all data files in their corresponding locations (also see "INSTALL/UNINSTALL SUPPORT"), - `install-exec`; installs all executable files in their corresponding locations (also see "INSTALL/UNINSTALL SUPPORT"), - `install-headers`; installs all include files in their corresponding locations (also see "INSTALL/UNINSTALL SUPPORT"), - `install-libs`; installs all library files in their corresponding locations (also see "INSTALL/UNINSTALL SUPPORT"), and - `uninstall`; removes all distribution files from their corresponding locations (also see "INSTALL/UNINSTALL SUPPORT"). ### Object Files Object files (the result of compiling a C or C++ source file) have the extension ".o". ### Programs Program files are the result of linking object files and libraries together to form an executable file. A typical program target looks like: program: $(OBJS) TAB echo Linking $@... TAB $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) ### Static Libraries Static libraries have a prefix of "lib" and the extension ".a". A typical static library target looks like: libname.a: $(OBJECTS) TAB echo Creating $@... TAB $(RM) $@ TAB $(AR) $(ARFLAGS) $@ $(OBJECTS) TAB $(RANLIB) $@ ### Shared Libraries Shared libraries have a prefix of "lib" and the extension ".dylib" or ".so" depending on the operating system. A typical shared library is composed of several targets that look like: libname.so: $(OBJECTS) TAB echo $(DSOCOMMAND) libname.so.$(DSOVERSION) ... TAB $(DSOCOMMAND) libname.so.$(DSOVERSION) $(OBJECTS) TAB $(RM) libname.so libname.so.$(DSOMAJOR) TAB $(LN) libname.so.$(DSOVERSION) libname.so.$(DSOMAJOR) TAB $(LN) libname.so.$(DSOVERSION) libname.so libname.dylib: $(OBJECTS) TAB echo $(DSOCOMMAND) libname.$(DSOVERSION).dylib ... TAB $(DSOCOMMAND) libname.$(DSOVERSION).dylib \ TAB TAB -install_name $(libdir)/libname.$(DSOMAJOR).dylib \ TAB TAB -current_version libname.$(DSOVERSION).dylib \ TAB TAB -compatibility_version $(DSOMAJOR).0 \ TAB TAB $(OBJECTS) $(LIBS) TAB $(RM) libname.dylib TAB $(RM) libname.$(DSOMAJOR).dylib TAB $(LN) libname.$(DSOVERSION).dylib libname.$(DSOMAJOR).dylib TAB $(LN) libname.$(DSOVERSION).dylib libname.dylib ### Dependencies Static dependencies are expressed in each makefile following the target, for example: foo: bar Static dependencies are only used when it is not possible to automatically generate them. Automatic dependencies are stored in a file named "Dependencies" and included at the end of the makefile. The following "depend" target rule is used to create the automatic dependencies: depend: TAB $(CC) -MM $(ALL_CFLAGS) $(OBJS:.o=.c) >Dependencies We regenerate the automatic dependencies on an macOS system and express any non-macOS dependencies statically in the makefile. ### Install/Uninstall Support All makefiles contains install and uninstall rules which install or remove the corresponding software. These rules must use the $(BUILDROOT) variable as a prefix to any installation directory so that the IPP sample code can be installed in a temporary location for packaging by programs like rpmbuild. The `INSTALL_BIN`, `INSTALL_COMPDATA`, `INSTALL_CONFIG`, `INSTALL_DATA`, `INSTALL_DIR`, `INSTALL_LIB`, `INSTALL_MAN`, and `INSTALL_SCRIPT` variables must be used when installing files so that the proper ownership and permissions are set on the installed files. The `$(RANLIB)` command must be run on any static libraries after installation since the symbol table is invalidated when the library is copied on some platforms. ippsample/CONTRIBUTING.md0000644000175000017500000000054513240604116013774 0ustar tilltill# Contributing to the IPP Sample Implementations The IPP sample implementations are developed and distributed as open source software under the Apache License, Version 2.0. Contributions should be submitted as pull requests on the Github site: http://github.com/istopwg/ippsample/pulls Developer guidelines can be found in the file `DEVELOPING.md`. ippsample/cups/0000755000175000017500000000000013240604116012511 5ustar tilltillippsample/cups/language-private.h0000644000175000017500000000451113240604116016116 0ustar tilltill/* * Private localization support for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_LANGUAGE_PRIVATE_H_ # define _CUPS_LANGUAGE_PRIVATE_H_ /* * Include necessary headers... */ # include # include # ifdef __APPLE__ # include # endif /* __APPLE__ */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Macro for localized text... */ # define _(x) x /* * Constants... */ # define _CUPS_MESSAGE_PO 0 /* Message file is in GNU .po format */ # define _CUPS_MESSAGE_UNQUOTE 1 /* Unescape \foo in strings? */ # define _CUPS_MESSAGE_STRINGS 2 /* Message file is in Apple .strings format */ /* * Types... */ typedef struct _cups_message_s /**** Message catalog entry ****/ { char *msg, /* Original string */ *str; /* Localized string */ } _cups_message_t; /* * Prototypes... */ # ifdef __APPLE__ extern const char *_cupsAppleLanguage(const char *locale, char *language, size_t langsize); extern const char *_cupsAppleLocale(CFStringRef languageName, char *locale, size_t localesize); # endif /* __APPLE__ */ extern void _cupsCharmapFlush(void); extern const char *_cupsEncodingName(cups_encoding_t encoding); extern void _cupsLangPrintError(const char *prefix, const char *message); extern int _cupsLangPrintFilter(FILE *fp, const char *prefix, const char *message, ...) __attribute__ ((__format__ (__printf__, 3, 4))); extern int _cupsLangPrintf(FILE *fp, const char *message, ...) __attribute__ ((__format__ (__printf__, 2, 3))); extern int _cupsLangPuts(FILE *fp, const char *message); extern const char *_cupsLangString(cups_lang_t *lang, const char *message); extern void _cupsMessageFree(cups_array_t *a); extern cups_array_t *_cupsMessageLoad(const char *filename, int flags); extern const char *_cupsMessageLookup(cups_array_t *a, const char *m); extern cups_array_t *_cupsMessageNew(void *context); extern int _cupsMessageSave(const char *filename, int flags, cups_array_t *a); extern void _cupsSetLocale(char *argv[]); # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_LANGUAGE_PRIVATE_H_ */ ippsample/cups/transcode.h0000644000175000017500000000321013240604116014640 0ustar tilltill/* * Transcoding definitions for CUPS. * * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_TRANSCODE_H_ # define _CUPS_TRANSCODE_H_ /* * Include necessary headers... */ # include "language.h" # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Constants... */ # define CUPS_MAX_USTRING 8192 /* Max size of Unicode string */ /* * Types... */ typedef unsigned char cups_utf8_t; /* UTF-8 Unicode/ISO-10646 unit */ typedef unsigned long cups_utf32_t; /* UTF-32 Unicode/ISO-10646 unit */ typedef unsigned short cups_ucs2_t; /* UCS-2 Unicode/ISO-10646 unit */ typedef unsigned long cups_ucs4_t; /* UCS-4 Unicode/ISO-10646 unit */ typedef unsigned char cups_sbcs_t; /* SBCS Legacy 8-bit unit */ typedef unsigned short cups_dbcs_t; /* DBCS Legacy 16-bit unit */ typedef unsigned long cups_vbcs_t; /* VBCS Legacy 32-bit unit */ /* EUC uses 8, 16, 24, 32-bit */ /* * Prototypes... */ extern int cupsCharsetToUTF8(cups_utf8_t *dest, const char *src, const int maxout, const cups_encoding_t encoding) _CUPS_API_1_2; extern int cupsUTF8ToCharset(char *dest, const cups_utf8_t *src, const int maxout, const cups_encoding_t encoding) _CUPS_API_1_2; extern int cupsUTF8ToUTF32(cups_utf32_t *dest, const cups_utf8_t *src, const int maxout) _CUPS_API_1_2; extern int cupsUTF32ToUTF8(cups_utf8_t *dest, const cups_utf32_t *src, const int maxout) _CUPS_API_1_2; # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_TRANSCODE_H_ */ ippsample/cups/file.h0000644000175000017500000000673413240604116013613 0ustar tilltill/* * Public file definitions for CUPS. * * Since stdio files max out at 256 files on many systems, we have to * write similar functions without this limit. At the same time, using * our own file functions allows us to provide transparent support of * different line endings, gzip'd print files, PPD files, etc. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_FILE_H_ # define _CUPS_FILE_H_ /* * Include necessary headers... */ # include "versioning.h" # include # include # if defined(WIN32) && !defined(__CUPS_SSIZE_T_DEFINED) # define __CUPS_SSIZE_T_DEFINED /* Windows does not support the ssize_t type, so map it to off_t... */ typedef off_t ssize_t; /* @private@ */ # endif /* WIN32 && !__CUPS_SSIZE_T_DEFINED */ /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * CUPS file definitions... */ # define CUPS_FILE_NONE 0 /* No compression */ # define CUPS_FILE_GZIP 1 /* GZIP compression */ /* * Types and structures... */ typedef struct _cups_file_s cups_file_t;/**** CUPS file type ****/ /* * Prototypes... */ extern int cupsFileClose(cups_file_t *fp) _CUPS_API_1_2; extern int cupsFileCompression(cups_file_t *fp) _CUPS_API_1_2; extern int cupsFileEOF(cups_file_t *fp) _CUPS_API_1_2; extern const char *cupsFileFind(const char *filename, const char *path, int executable, char *buffer, int bufsize) _CUPS_API_1_2; extern int cupsFileFlush(cups_file_t *fp) _CUPS_API_1_2; extern int cupsFileGetChar(cups_file_t *fp) _CUPS_API_1_2; extern char *cupsFileGetConf(cups_file_t *fp, char *buf, size_t buflen, char **value, int *linenum) _CUPS_API_1_2; extern size_t cupsFileGetLine(cups_file_t *fp, char *buf, size_t buflen) _CUPS_API_1_2; extern char *cupsFileGets(cups_file_t *fp, char *buf, size_t buflen) _CUPS_API_1_2; extern int cupsFileLock(cups_file_t *fp, int block) _CUPS_API_1_2; extern int cupsFileNumber(cups_file_t *fp) _CUPS_API_1_2; extern cups_file_t *cupsFileOpen(const char *filename, const char *mode) _CUPS_API_1_2; extern cups_file_t *cupsFileOpenFd(int fd, const char *mode) _CUPS_API_1_2; extern int cupsFilePeekChar(cups_file_t *fp) _CUPS_API_1_2; extern int cupsFilePrintf(cups_file_t *fp, const char *format, ...) __attribute__((__format__ (__printf__, 2, 3))) _CUPS_API_1_2; extern int cupsFilePutChar(cups_file_t *fp, int c) _CUPS_API_1_2; extern ssize_t cupsFilePutConf(cups_file_t *fp, const char *directive, const char *value) _CUPS_API_1_4; extern int cupsFilePuts(cups_file_t *fp, const char *s) _CUPS_API_1_2; extern ssize_t cupsFileRead(cups_file_t *fp, char *buf, size_t bytes) _CUPS_API_1_2; extern off_t cupsFileRewind(cups_file_t *fp) _CUPS_API_1_2; extern off_t cupsFileSeek(cups_file_t *fp, off_t pos) _CUPS_API_1_2; extern cups_file_t *cupsFileStderr(void) _CUPS_API_1_2; extern cups_file_t *cupsFileStdin(void) _CUPS_API_1_2; extern cups_file_t *cupsFileStdout(void) _CUPS_API_1_2; extern off_t cupsFileTell(cups_file_t *fp) _CUPS_API_1_2; extern int cupsFileUnlock(cups_file_t *fp) _CUPS_API_1_2; extern ssize_t cupsFileWrite(cups_file_t *fp, const char *buf, size_t bytes) _CUPS_API_1_2; # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_FILE_H_ */ ippsample/cups/http-private.h0000644000175000017500000003634013240604116015317 0ustar tilltill/* * Private HTTP definitions for CUPS. * * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ #ifndef _CUPS_HTTP_PRIVATE_H_ # define _CUPS_HTTP_PRIVATE_H_ /* * Include necessary headers... */ # include "config.h" # include # include # include # ifdef __sun # include # endif /* __sun */ # include # ifdef WIN32 # include # include # define CUPS_SOCAST (const char *) # else # include # include # include # define CUPS_SOCAST # endif /* WIN32 */ # ifdef HAVE_GSSAPI # ifdef HAVE_GSS_GSSAPI_H # include # elif defined(HAVE_GSSAPI_GSSAPI_H) # include # elif defined(HAVE_GSSAPI_H) # include # endif /* HAVE_GSS_GSSAPI_H */ # ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE # define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name # endif /* !HAVE_GSS_C_NT_HOSTBASED_SERVICE */ # endif /* HAVE_GSSAPI */ # ifdef HAVE_AUTHORIZATION_H # include # endif /* HAVE_AUTHORIZATION_H */ # if defined(__APPLE__) && !defined(_SOCKLEN_T) /* * macOS 10.2.x does not define socklen_t, and in fact uses an int instead of * unsigned type for length values... */ typedef int socklen_t; # endif /* __APPLE__ && !_SOCKLEN_T */ # include # include "ipp-private.h" # ifdef HAVE_GNUTLS # include # include # elif defined(HAVE_CDSASSL) # include # include # include # ifdef HAVE_SECURETRANSPORTPRIV_H # include # endif /* HAVE_SECURETRANSPORTPRIV_H */ # ifdef HAVE_SECITEM_H # include # endif /* HAVE_SECITEM_H */ # ifdef HAVE_SECBASEPRIV_H # include # endif /* HAVE_SECBASEPRIV_H */ # ifdef HAVE_SECCERTIFICATE_H # include # include # endif /* HAVE_SECCERTIFICATE_H */ # ifdef HAVE_SECCERTIFICATEPRIV_H # include # else # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ # ifndef _SECURITY_VERSION_GREATER_THAN_57610_ typedef CF_OPTIONS(uint32_t, SecKeyUsage) { kSecKeyUsageAll = 0x7FFFFFFF }; # endif /* !_SECURITY_VERSION_GREATER_THAN_57610_ */ extern const void * kSecCSRChallengePassword; extern const void * kSecSubjectAltName; extern const void * kSecCertificateKeyUsage; extern const void * kSecCSRBasicContraintsPathLen; extern const void * kSecCertificateExtensions; extern const void * kSecCertificateExtensionsEncoded; extern const void * kSecOidCommonName; extern const void * kSecOidCountryName; extern const void * kSecOidStateProvinceName; extern const void * kSecOidLocalityName; extern const void * kSecOidOrganization; extern const void * kSecOidOrganizationalUnit; extern SecCertificateRef SecCertificateCreateWithBytes(CFAllocatorRef allocator, const UInt8 *bytes, CFIndex length); extern bool SecCertificateIsValid(SecCertificateRef certificate, CFAbsoluteTime verifyTime); extern CFAbsoluteTime SecCertificateNotValidAfter(SecCertificateRef certificate); extern SecCertificateRef SecGenerateSelfSignedCertificate(CFArrayRef subject, CFDictionaryRef parameters, SecKeyRef publicKey, SecKeyRef privateKey); extern SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator, SecCertificateRef certificate, SecKeyRef privateKey); # ifdef __cplusplus } # endif /* __cplusplus */ # endif /* HAVE_SECCERTIFICATEPRIV_H */ # ifdef HAVE_SECITEMPRIV_H # include # endif /* HAVE_SECITEMPRIV_H */ # ifdef HAVE_SECIDENTITYSEARCHPRIV_H # include # endif /* HAVE_SECIDENTITYSEARCHPRIV_H */ # ifdef HAVE_SECPOLICYPRIV_H # include # endif /* HAVE_SECPOLICYPRIV_H */ # elif defined(HAVE_SSPISSL) # include # include # include # define SECURITY_WIN32 # include # include # endif /* HAVE_GNUTLS */ # ifndef WIN32 # include # include # ifdef HAVE_GETIFADDRS # include # else # include # ifdef HAVE_SYS_SOCKIO_H # include # endif /* HAVE_SYS_SOCKIO_H */ # endif /* HAVE_GETIFADDRS */ # endif /* !WIN32 */ # ifdef HAVE_LIBZ # include # endif /* HAVE_LIBZ */ /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Constants... */ # define _HTTP_MAX_SBUFFER 65536 /* Size of (de)compression buffer */ # define _HTTP_RESOLVE_DEFAULT 0 /* Just resolve with default options */ # define _HTTP_RESOLVE_STDERR 1 /* Log resolve progress to stderr */ # define _HTTP_RESOLVE_FQDN 2 /* Resolve to a FQDN */ # define _HTTP_RESOLVE_FAXOUT 4 /* Resolve FaxOut service? */ # define _HTTP_TLS_NONE 0 /* No TLS options */ # define _HTTP_TLS_ALLOW_RC4 1 /* Allow RC4 cipher suites */ # define _HTTP_TLS_ALLOW_DH 2 /* Allow DH/DHE key negotiation */ # define _HTTP_TLS_DENY_CBC 4 /* Deny CBC cipher suites */ # define _HTTP_TLS_SET_DEFAULT 128 /* Setting the default TLS options */ # define _HTTP_TLS_SSL3 0 /* Min/max version is SSL/3.0 */ # define _HTTP_TLS_1_0 1 /* Min/max version is TLS/1.0 */ # define _HTTP_TLS_1_1 2 /* Min/max version is TLS/1.1 */ # define _HTTP_TLS_1_2 3 /* Min/max version is TLS/1.2 */ # define _HTTP_TLS_1_3 4 /* Min/max version is TLS/1.3 */ # define _HTTP_TLS_MAX 5 /* Highest known TLS version */ /* * Types and functions for SSL support... */ # ifdef HAVE_GNUTLS /* * The GNU TLS library is more of a "bare metal" SSL/TLS library... */ typedef gnutls_session_t http_tls_t; typedef gnutls_certificate_credentials_t *http_tls_credentials_t; # elif defined(HAVE_CDSASSL) /* * Darwin's Security framework provides its own SSL/TLS context structure * for its IO and protocol management... */ # if !defined(HAVE_SECBASEPRIV_H) && defined(HAVE_CSSMERRORSTRING) /* Declare prototype for function in that header... */ extern const char *cssmErrorString(int error); # endif /* !HAVE_SECBASEPRIV_H && HAVE_CSSMERRORSTRING */ # if !defined(HAVE_SECIDENTITYSEARCHPRIV_H) && defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY) /* Declare prototype for function in that header... */ extern OSStatus SecIdentitySearchCreateWithPolicy(SecPolicyRef policy, CFStringRef idString, CSSM_KEYUSE keyUsage, CFTypeRef keychainOrArray, Boolean returnOnlyValidIdentities, SecIdentitySearchRef* searchRef); # endif /* !HAVE_SECIDENTITYSEARCHPRIV_H && HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY */ # if !defined(HAVE_SECPOLICYPRIV_H) && defined(HAVE_SECPOLICYSETVALUE) /* Declare prototype for function in that header... */ extern OSStatus SecPolicySetValue(SecPolicyRef policyRef, const CSSM_DATA *value); # endif /* !HAVE_SECPOLICYPRIV_H && HAVE_SECPOLICYSETVALUE */ typedef SSLContextRef http_tls_t; typedef CFArrayRef http_tls_credentials_t; # elif defined(HAVE_SSPISSL) /* * Windows' SSPI library gets a CUPS wrapper... */ typedef struct _http_sspi_s /**** SSPI/SSL data structure ****/ { CredHandle creds; /* Credentials */ CtxtHandle context; /* SSL context */ BOOL contextInitialized; /* Is context init'd? */ SecPkgContext_StreamSizes streamSizes;/* SSL data stream sizes */ BYTE *decryptBuffer; /* Data pre-decryption*/ size_t decryptBufferLength; /* Length of decrypt buffer */ size_t decryptBufferUsed; /* Bytes used in buffer */ BYTE *readBuffer; /* Data post-decryption */ int readBufferLength; /* Length of read buffer */ int readBufferUsed; /* Bytes used in buffer */ BYTE *writeBuffer; /* Data pre-encryption */ int writeBufferLength; /* Length of write buffer */ PCCERT_CONTEXT localCert, /* Local certificate */ remoteCert; /* Remote (peer's) certificate */ char error[256]; /* Most recent error message */ } _http_sspi_t; typedef _http_sspi_t *http_tls_t; typedef PCCERT_CONTEXT http_tls_credentials_t; # else /* * Otherwise define stub types since we have no SSL support... */ typedef void *http_tls_t; typedef void *http_tls_credentials_t; # endif /* HAVE_GNUTLS */ typedef enum _http_coding_e /**** HTTP content coding enumeration ****/ { _HTTP_CODING_IDENTITY, /* No content coding */ _HTTP_CODING_GZIP, /* LZ77+gzip decompression */ _HTTP_CODING_DEFLATE, /* LZ77+zlib compression */ _HTTP_CODING_GUNZIP, /* LZ77+gzip decompression */ _HTTP_CODING_INFLATE /* LZ77+zlib decompression */ } _http_coding_t; typedef enum _http_mode_e /**** HTTP mode enumeration ****/ { _HTTP_MODE_CLIENT, /* Client connected to server */ _HTTP_MODE_SERVER /* Server connected (accepted) from client */ } _http_mode_t; # ifndef _HTTP_NO_PRIVATE struct _http_s /**** HTTP connection structure ****/ { int fd; /* File descriptor for this socket */ int blocking; /* To block or not to block */ int error; /* Last error on read */ time_t activity; /* Time since last read/write */ http_state_t state; /* State of client */ http_status_t status; /* Status of last request */ http_version_t version; /* Protocol version */ http_keepalive_t keep_alive; /* Keep-alive supported? */ struct sockaddr_in _hostaddr; /* Address of connected host (deprecated) */ char hostname[HTTP_MAX_HOST], /* Name of connected host */ _fields[HTTP_FIELD_ACCEPT_ENCODING][HTTP_MAX_VALUE]; /* Field values up to Accept-Encoding (deprecated) */ char *data; /* Pointer to data buffer */ http_encoding_t data_encoding; /* Chunked or not */ int _data_remaining;/* Number of bytes left (deprecated) */ int used; /* Number of bytes used in buffer */ char buffer[HTTP_MAX_BUFFER]; /* Buffer for incoming data */ int _auth_type; /* Authentication in use (deprecated) */ unsigned char _md5_state[88]; /* MD5 state (deprecated) */ char nonce[HTTP_MAX_VALUE]; /* Nonce value */ unsigned nonce_count; /* Nonce count */ http_tls_t tls; /* TLS state information */ http_encryption_t encryption; /* Encryption requirements */ /**** New in CUPS 1.1.19 ****/ fd_set *input_set; /* select() set for httpWait() (deprecated) */ http_status_t expect; /* Expect: header */ char *cookie; /* Cookie value(s) */ /**** New in CUPS 1.1.20 ****/ char _authstring[HTTP_MAX_VALUE], /* Current Authorization value (deprecated) */ userpass[HTTP_MAX_VALUE]; /* Username:password string */ int digest_tries; /* Number of tries for digest auth */ /**** New in CUPS 1.2 ****/ off_t data_remaining; /* Number of bytes left */ http_addr_t *hostaddr; /* Current host address and port */ http_addrlist_t *addrlist; /* List of valid addresses */ char wbuffer[HTTP_MAX_BUFFER]; /* Buffer for outgoing data */ int wused; /* Write buffer bytes used */ /**** New in CUPS 1.3 ****/ char *authstring; /* Current Authorization field */ # ifdef HAVE_GSSAPI gss_OID gssmech; /* Authentication mechanism */ gss_ctx_id_t gssctx; /* Authentication context */ gss_name_t gssname; /* Authentication server name */ # endif /* HAVE_GSSAPI */ # ifdef HAVE_AUTHORIZATION_H AuthorizationRef auth_ref; /* Authorization ref */ # endif /* HAVE_AUTHORIZATION_H */ /**** New in CUPS 1.5 ****/ http_tls_credentials_t tls_credentials; /* TLS credentials */ http_timeout_cb_t timeout_cb; /* Timeout callback */ void *timeout_data; /* User data pointer */ double timeout_value; /* Timeout in seconds */ int wait_value; /* httpWait value for timeout */ # ifdef HAVE_GSSAPI char gsshost[256]; /* Hostname for Kerberos */ # endif /* HAVE_GSSAPI */ /**** New in CUPS 1.7 ****/ int tls_upgrade; /* Non-zero if we are doing an upgrade */ _http_mode_t mode; /* _HTTP_MODE_CLIENT or _HTTP_MODE_SERVER */ # ifdef HAVE_LIBZ _http_coding_t coding; /* _HTTP_CODING_xxx */ z_stream stream; /* (De)compression stream */ Bytef *sbuffer; /* (De)compression buffer */ # endif /* HAVE_LIBZ */ /**** New in CUPS 2.3 ****/ char *fields[HTTP_FIELD_MAX], /* Allocated field values */ *default_fields[HTTP_FIELD_MAX]; /* Default field values, if any */ }; # endif /* !_HTTP_NO_PRIVATE */ /* * Some OS's don't have hstrerror(), most notably Solaris... */ # ifndef HAVE_HSTRERROR extern const char *_cups_hstrerror(int error); # define hstrerror _cups_hstrerror # endif /* !HAVE_HSTRERROR */ /* * Some OS's don't have getifaddrs() and freeifaddrs()... */ # if !defined(WIN32) && !defined(HAVE_GETIFADDRS) # ifdef ifa_dstaddr # undef ifa_dstaddr # endif /* ifa_dstaddr */ # ifndef ifr_netmask # define ifr_netmask ifr_addr # endif /* !ifr_netmask */ struct ifaddrs /**** Interface Structure ****/ { struct ifaddrs *ifa_next; /* Next interface in list */ char *ifa_name; /* Name of interface */ unsigned int ifa_flags; /* Flags (up, point-to-point, etc.) */ struct sockaddr *ifa_addr, /* Network address */ *ifa_netmask; /* Address mask */ union { struct sockaddr *ifu_broadaddr; /* Broadcast address of this interface. */ struct sockaddr *ifu_dstaddr; /* Point-to-point destination address. */ } ifa_ifu; void *ifa_data; /* Interface statistics */ }; # ifndef ifa_broadaddr # define ifa_broadaddr ifa_ifu.ifu_broadaddr # endif /* !ifa_broadaddr */ # ifndef ifa_dstaddr # define ifa_dstaddr ifa_ifu.ifu_dstaddr # endif /* !ifa_dstaddr */ extern int _cups_getifaddrs(struct ifaddrs **addrs); # define getifaddrs _cups_getifaddrs extern void _cups_freeifaddrs(struct ifaddrs *addrs); # define freeifaddrs _cups_freeifaddrs # endif /* !WIN32 && !HAVE_GETIFADDRS */ /* * Prototypes... */ extern void _httpAddrSetPort(http_addr_t *addr, int port); extern http_tls_credentials_t _httpCreateCredentials(cups_array_t *credentials); extern char *_httpDecodeURI(char *dst, const char *src, size_t dstsize); extern void _httpDisconnect(http_t *http); extern char *_httpEncodeURI(char *dst, const char *src, size_t dstsize); extern void _httpFreeCredentials(http_tls_credentials_t credentials); extern const char *_httpResolveURI(const char *uri, char *resolved_uri, size_t resolved_size, int options, int (*cb)(void *context), void *context); extern const char *_httpStatus(cups_lang_t *lang, http_status_t status); extern void _httpTLSInitialize(void); extern size_t _httpTLSPending(http_t *http); extern int _httpTLSRead(http_t *http, char *buf, int len); extern int _httpTLSSetCredentials(http_t *http); extern void _httpTLSSetOptions(int options, int min_version, int max_version); extern int _httpTLSStart(http_t *http); extern void _httpTLSStop(http_t *http); extern int _httpTLSWrite(http_t *http, const char *buf, int len); extern int _httpUpdate(http_t *http, http_status_t *status); extern int _httpWait(http_t *http, int msec, int usessl); /* * C++ magic... */ # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_HTTP_PRIVATE_H_ */ ippsample/cups/ipp-private.h0000644000175000017500000000676613240604116015141 0ustar tilltill/* * Private IPP definitions for CUPS. * * Copyright © 2007-2018 by Apple Inc. * Copyright © 1997-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ #ifndef _CUPS_IPP_PRIVATE_H_ # define _CUPS_IPP_PRIVATE_H_ /* * Include necessary headers... */ # include /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Constants... */ # define IPP_BUF_SIZE (IPP_MAX_LENGTH + 2) /* Size of buffer */ /* * Structures... */ typedef struct /**** Attribute mapping data ****/ { int multivalue; /* Option has multiple values? */ const char *name; /* Option/attribute name */ ipp_tag_t value_tag; /* Value tag for this attribute */ ipp_tag_t group_tag; /* Group tag for this attribute */ ipp_tag_t alt_group_tag; /* Alternate group tag for this * attribute */ const ipp_op_t *operations; /* Allowed operations for this attr */ } _ipp_option_t; typedef struct _ipp_file_s _ipp_file_t;/**** File Parser ****/ typedef struct _ipp_vars_s _ipp_vars_t;/**** Variables ****/ typedef int (*_ipp_fattr_cb_t)(_ipp_file_t *f, void *user_data, const char *attr); /**** File Attribute (Filter) Callback ****/ typedef int (*_ipp_ferror_cb_t)(_ipp_file_t *f, void *user_data, const char *error); /**** File Parser Error Callback ****/ typedef int (*_ipp_ftoken_cb_t)(_ipp_file_t *f, _ipp_vars_t *v, void *user_data, const char *token); /**** File Parser Token Callback ****/ struct _ipp_vars_s /**** Variables ****/ { char *uri, /* URI for printer */ scheme[64], /* Scheme from URI */ username[256], /* Username from URI */ *password, /* Password from URI (if any) */ host[256], /* Hostname from URI */ portstr[32], /* Port number string */ resource[1024]; /* Resource path from URI */ int port; /* Port number from URI */ int num_vars; /* Number of variables */ cups_option_t *vars; /* Array of variables */ int password_tries; /* Number of retries for password */ _ipp_fattr_cb_t attrcb; /* Attribute (filter) callback */ _ipp_ferror_cb_t errorcb; /* Error callback */ _ipp_ftoken_cb_t tokencb; /* Token callback */ }; struct _ipp_file_s /**** File Parser */ { const char *filename; /* Filename */ cups_file_t *fp; /* File pointer */ int linenum; /* Current line number */ ipp_t *attrs; /* Attributes */ ipp_tag_t group_tag; /* Current group for new attributes */ }; /* * Prototypes for private functions... */ /* encode.c */ #ifdef DEBUG extern const char *_ippCheckOptions(void); #endif /* DEBUG */ extern _ipp_option_t *_ippFindOption(const char *name); /* ipp-file.c */ extern ipp_t *_ippFileParse(_ipp_vars_t *v, const char *filename, void *user_data); extern int _ippFileReadToken(_ipp_file_t *f, char *token, size_t tokensize); /* ipp-vars.c */ extern void _ippVarsDeinit(_ipp_vars_t *v); extern void _ippVarsExpand(_ipp_vars_t *v, char *dst, const char *src, size_t dstsize) __attribute__((nonnull(1,2,3))); extern const char *_ippVarsGet(_ipp_vars_t *v, const char *name); extern void _ippVarsInit(_ipp_vars_t *v, _ipp_fattr_cb_t attrcb, _ipp_ferror_cb_t errorcb, _ipp_ftoken_cb_t tokencb); extern const char *_ippVarsPasswordCB(const char *prompt, http_t *http, const char *method, const char *resource, void *user_data); extern int _ippVarsSet(_ipp_vars_t *v, const char *name, const char *value); /* * C++ magic... */ # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_IPP_H_ */ ippsample/cups/testipp.c0000644000175000017500000006067413240604116014362 0ustar tilltill/* * IPP test program for CUPS. * * Copyright © 2007-2018 by Apple Inc. * Copyright © 1997-2005 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "file.h" #include "string-private.h" #include "ipp-private.h" #ifdef WIN32 # include #else # include # include #endif /* WIN32 */ /* * Local types... */ typedef struct _ippdata_t { size_t rpos, /* Read position */ wused, /* Bytes used */ wsize; /* Max size of buffer */ ipp_uchar_t *wbuffer; /* Buffer */ } _ippdata_t; /* * Local globals... */ static ipp_uchar_t collection[] = /* Collection buffer */ { 0x01, 0x01, /* IPP version */ 0x00, 0x02, /* Print-Job operation */ 0x00, 0x00, 0x00, 0x01, /* Request ID */ IPP_TAG_OPERATION, IPP_TAG_CHARSET, 0x00, 0x12, /* Name length + name */ 'a','t','t','r','i','b','u','t','e','s','-', 'c','h','a','r','s','e','t', 0x00, 0x05, /* Value length + value */ 'u','t','f','-','8', IPP_TAG_LANGUAGE, 0x00, 0x1b, /* Name length + name */ 'a','t','t','r','i','b','u','t','e','s','-', 'n','a','t','u','r','a','l','-','l','a','n', 'g','u','a','g','e', 0x00, 0x02, /* Value length + value */ 'e','n', IPP_TAG_URI, 0x00, 0x0b, /* Name length + name */ 'p','r','i','n','t','e','r','-','u','r','i', 0x00, 0x1c, /* Value length + value */ 'i','p','p',':','/','/','l','o','c','a','l', 'h','o','s','t','/','p','r','i','n','t','e', 'r','s','/','f','o','o', IPP_TAG_JOB, /* job group tag */ IPP_TAG_BEGIN_COLLECTION, /* begCollection tag */ 0x00, 0x09, /* Name length + name */ 'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 0x00, 0x00, /* No value */ IPP_TAG_MEMBERNAME, /* memberAttrName tag */ 0x00, 0x00, /* No name */ 0x00, 0x0a, /* Value length + value */ 'm', 'e', 'd', 'i', 'a', '-', 's', 'i', 'z', 'e', IPP_TAG_BEGIN_COLLECTION, /* begCollection tag */ 0x00, 0x00, /* Name length + name */ 0x00, 0x00, /* No value */ IPP_TAG_MEMBERNAME, /* memberAttrName tag */ 0x00, 0x00, /* No name */ 0x00, 0x0b, /* Value length + value */ 'x', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n', IPP_TAG_INTEGER, /* integer tag */ 0x00, 0x00, /* No name */ 0x00, 0x04, /* Value length + value */ 0x00, 0x00, 0x54, 0x56, IPP_TAG_MEMBERNAME, /* memberAttrName tag */ 0x00, 0x00, /* No name */ 0x00, 0x0b, /* Value length + value */ 'y', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n', IPP_TAG_INTEGER, /* integer tag */ 0x00, 0x00, /* No name */ 0x00, 0x04, /* Value length + value */ 0x00, 0x00, 0x6d, 0x24, IPP_TAG_END_COLLECTION, /* endCollection tag */ 0x00, 0x00, /* No name */ 0x00, 0x00, /* No value */ IPP_TAG_MEMBERNAME, /* memberAttrName tag */ 0x00, 0x00, /* No name */ 0x00, 0x0b, /* Value length + value */ 'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 'o', 'r', IPP_TAG_KEYWORD, /* keyword tag */ 0x00, 0x00, /* No name */ 0x00, 0x04, /* Value length + value */ 'b', 'l', 'u', 'e', IPP_TAG_MEMBERNAME, /* memberAttrName tag */ 0x00, 0x00, /* No name */ 0x00, 0x0a, /* Value length + value */ 'm', 'e', 'd', 'i', 'a', '-', 't', 'y', 'p', 'e', IPP_TAG_KEYWORD, /* keyword tag */ 0x00, 0x00, /* No name */ 0x00, 0x05, /* Value length + value */ 'p', 'l', 'a', 'i', 'n', IPP_TAG_END_COLLECTION, /* endCollection tag */ 0x00, 0x00, /* No name */ 0x00, 0x00, /* No value */ IPP_TAG_BEGIN_COLLECTION, /* begCollection tag */ 0x00, 0x00, /* No name */ 0x00, 0x00, /* No value */ IPP_TAG_MEMBERNAME, /* memberAttrName tag */ 0x00, 0x00, /* No name */ 0x00, 0x0a, /* Value length + value */ 'm', 'e', 'd', 'i', 'a', '-', 's', 'i', 'z', 'e', IPP_TAG_BEGIN_COLLECTION, /* begCollection tag */ 0x00, 0x00, /* Name length + name */ 0x00, 0x00, /* No value */ IPP_TAG_MEMBERNAME, /* memberAttrName tag */ 0x00, 0x00, /* No name */ 0x00, 0x0b, /* Value length + value */ 'x', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n', IPP_TAG_INTEGER, /* integer tag */ 0x00, 0x00, /* No name */ 0x00, 0x04, /* Value length + value */ 0x00, 0x00, 0x52, 0x08, IPP_TAG_MEMBERNAME, /* memberAttrName tag */ 0x00, 0x00, /* No name */ 0x00, 0x0b, /* Value length + value */ 'y', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n', IPP_TAG_INTEGER, /* integer tag */ 0x00, 0x00, /* No name */ 0x00, 0x04, /* Value length + value */ 0x00, 0x00, 0x74, 0x04, IPP_TAG_END_COLLECTION, /* endCollection tag */ 0x00, 0x00, /* No name */ 0x00, 0x00, /* No value */ IPP_TAG_MEMBERNAME, /* memberAttrName tag */ 0x00, 0x00, /* No name */ 0x00, 0x0b, /* Value length + value */ 'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 'o', 'r', IPP_TAG_KEYWORD, /* keyword tag */ 0x00, 0x00, /* No name */ 0x00, 0x05, /* Value length + value */ 'p', 'l', 'a', 'i', 'd', IPP_TAG_MEMBERNAME, /* memberAttrName tag */ 0x00, 0x00, /* No name */ 0x00, 0x0a, /* Value length + value */ 'm', 'e', 'd', 'i', 'a', '-', 't', 'y', 'p', 'e', IPP_TAG_KEYWORD, /* keyword tag */ 0x00, 0x00, /* No name */ 0x00, 0x06, /* Value length + value */ 'g', 'l', 'o', 's', 's', 'y', IPP_TAG_END_COLLECTION, /* endCollection tag */ 0x00, 0x00, /* No name */ 0x00, 0x00, /* No value */ IPP_TAG_END /* end tag */ }; static ipp_uchar_t mixed[] = /* Mixed value buffer */ { 0x01, 0x01, /* IPP version */ 0x00, 0x02, /* Print-Job operation */ 0x00, 0x00, 0x00, 0x01, /* Request ID */ IPP_TAG_OPERATION, IPP_TAG_INTEGER, /* integer tag */ 0x00, 0x1f, /* Name length + name */ 'n', 'o', 't', 'i', 'f', 'y', '-', 'l', 'e', 'a', 's', 'e', '-', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '-', 's', 'u', 'p', 'p', 'o', 'r', 't', 'e', 'd', 0x00, 0x04, /* Value length + value */ 0x00, 0x00, 0x00, 0x01, IPP_TAG_RANGE, /* rangeOfInteger tag */ 0x00, 0x00, /* No name */ 0x00, 0x08, /* Value length + value */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, IPP_TAG_END /* end tag */ }; /* * Local functions... */ void hex_dump(const char *title, ipp_uchar_t *buffer, size_t bytes); void print_attributes(ipp_t *ipp, int indent); ssize_t read_cb(_ippdata_t *data, ipp_uchar_t *buffer, size_t bytes); int token_cb(_ipp_file_t *f, _ipp_vars_t *v, void *user_data, const char *token); ssize_t write_cb(_ippdata_t *data, ipp_uchar_t *buffer, size_t bytes); /* * 'main()' - Main entry. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { _ippdata_t data; /* IPP buffer */ ipp_uchar_t buffer[8192]; /* Write buffer data */ ipp_t *cols[2], /* Collections */ *size; /* media-size collection */ ipp_t *request; /* Request */ ipp_attribute_t *media_col, /* media-col attribute */ *media_size, /* media-size attribute */ *attr; /* Other attribute */ ipp_state_t state; /* State */ size_t length; /* Length of data */ cups_file_t *fp; /* File pointer */ size_t i; /* Looping var */ int status; /* Status of tests (0 = success, 1 = fail) */ #ifdef DEBUG const char *name; /* Option name */ #endif /* DEBUG */ status = 0; if (argc == 1) { /* * Test request generation code... */ printf("Create Sample Request: "); request = ippNew(); request->request.op.version[0] = 0x01; request->request.op.version[1] = 0x01; request->request.op.operation_id = IPP_OP_PRINT_JOB; request->request.op.request_id = 1; ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, "utf-8"); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, "en"); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, "ipp://localhost/printers/foo"); cols[0] = ippNew(); size = ippNew(); ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "x-dimension", 21590); ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "y-dimension", 27940); ippAddCollection(cols[0], IPP_TAG_JOB, "media-size", size); ippDelete(size); ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL, "blue"); ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL, "plain"); cols[1] = ippNew(); size = ippNew(); ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "x-dimension", 21000); ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "y-dimension", 29700); ippAddCollection(cols[1], IPP_TAG_JOB, "media-size", size); ippDelete(size); ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL, "plaid"); ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL, "glossy"); ippAddCollections(request, IPP_TAG_JOB, "media-col", 2, (const ipp_t **)cols); ippDelete(cols[0]); ippDelete(cols[1]); length = ippLength(request); if (length != sizeof(collection)) { printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n", (int)length, (int)sizeof(collection)); status = 1; } else puts("PASS"); /* * Write test #1... */ printf("Write Sample to Memory: "); data.wused = 0; data.wsize = sizeof(buffer); data.wbuffer = buffer; while ((state = ippWriteIO(&data, (ipp_iocb_t)write_cb, 1, NULL, request)) != IPP_STATE_DATA) if (state == IPP_STATE_ERROR) break; if (state != IPP_STATE_DATA) { printf("FAIL - %d bytes written.\n", (int)data.wused); status = 1; } else if (data.wused != sizeof(collection)) { printf("FAIL - wrote %d bytes, expected %d bytes!\n", (int)data.wused, (int)sizeof(collection)); hex_dump("Bytes Written", data.wbuffer, data.wused); hex_dump("Baseline", collection, sizeof(collection)); status = 1; } else if (memcmp(data.wbuffer, collection, data.wused)) { for (i = 0; i < data.wused; i ++) if (data.wbuffer[i] != collection[i]) break; printf("FAIL - output does not match baseline at 0x%04x!\n", (unsigned)i); hex_dump("Bytes Written", data.wbuffer, data.wused); hex_dump("Baseline", collection, sizeof(collection)); status = 1; } else puts("PASS"); ippDelete(request); /* * Read the data back in and confirm... */ printf("Read Sample from Memory: "); request = ippNew(); data.rpos = 0; while ((state = ippReadIO(&data, (ipp_iocb_t)read_cb, 1, NULL, request)) != IPP_STATE_DATA) if (state == IPP_STATE_ERROR) break; length = ippLength(request); if (state != IPP_STATE_DATA) { printf("FAIL - %d bytes read.\n", (int)data.rpos); status = 1; } else if (data.rpos != data.wused) { printf("FAIL - read %d bytes, expected %d bytes!\n", (int)data.rpos, (int)data.wused); print_attributes(request, 8); status = 1; } else if (length != sizeof(collection)) { printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n", (int)length, (int)sizeof(collection)); print_attributes(request, 8); status = 1; } else puts("PASS"); fputs("ippFindAttribute(media-col): ", stdout); if ((media_col = ippFindAttribute(request, "media-col", IPP_TAG_BEGIN_COLLECTION)) == NULL) { if ((media_col = ippFindAttribute(request, "media-col", IPP_TAG_ZERO)) == NULL) puts("FAIL (not found)"); else printf("FAIL (wrong type - %s)\n", ippTagString(media_col->value_tag)); status = 1; } else if (media_col->num_values != 2) { printf("FAIL (wrong count - %d)\n", media_col->num_values); status = 1; } else puts("PASS"); if (media_col) { fputs("ippFindAttribute(media-size 1): ", stdout); if ((media_size = ippFindAttribute(media_col->values[0].collection, "media-size", IPP_TAG_BEGIN_COLLECTION)) == NULL) { if ((media_size = ippFindAttribute(media_col->values[0].collection, "media-col", IPP_TAG_ZERO)) == NULL) puts("FAIL (not found)"); else printf("FAIL (wrong type - %s)\n", ippTagString(media_size->value_tag)); status = 1; } else { if ((attr = ippFindAttribute(media_size->values[0].collection, "x-dimension", IPP_TAG_INTEGER)) == NULL) { if ((attr = ippFindAttribute(media_size->values[0].collection, "x-dimension", IPP_TAG_ZERO)) == NULL) puts("FAIL (missing x-dimension)"); else printf("FAIL (wrong type for x-dimension - %s)\n", ippTagString(attr->value_tag)); status = 1; } else if (attr->values[0].integer != 21590) { printf("FAIL (wrong value for x-dimension - %d)\n", attr->values[0].integer); status = 1; } else if ((attr = ippFindAttribute(media_size->values[0].collection, "y-dimension", IPP_TAG_INTEGER)) == NULL) { if ((attr = ippFindAttribute(media_size->values[0].collection, "y-dimension", IPP_TAG_ZERO)) == NULL) puts("FAIL (missing y-dimension)"); else printf("FAIL (wrong type for y-dimension - %s)\n", ippTagString(attr->value_tag)); status = 1; } else if (attr->values[0].integer != 27940) { printf("FAIL (wrong value for y-dimension - %d)\n", attr->values[0].integer); status = 1; } else puts("PASS"); } fputs("ippFindAttribute(media-size 2): ", stdout); if ((media_size = ippFindAttribute(media_col->values[1].collection, "media-size", IPP_TAG_BEGIN_COLLECTION)) == NULL) { if ((media_size = ippFindAttribute(media_col->values[1].collection, "media-col", IPP_TAG_ZERO)) == NULL) puts("FAIL (not found)"); else printf("FAIL (wrong type - %s)\n", ippTagString(media_size->value_tag)); status = 1; } else { if ((attr = ippFindAttribute(media_size->values[0].collection, "x-dimension", IPP_TAG_INTEGER)) == NULL) { if ((attr = ippFindAttribute(media_size->values[0].collection, "x-dimension", IPP_TAG_ZERO)) == NULL) puts("FAIL (missing x-dimension)"); else printf("FAIL (wrong type for x-dimension - %s)\n", ippTagString(attr->value_tag)); status = 1; } else if (attr->values[0].integer != 21000) { printf("FAIL (wrong value for x-dimension - %d)\n", attr->values[0].integer); status = 1; } else if ((attr = ippFindAttribute(media_size->values[0].collection, "y-dimension", IPP_TAG_INTEGER)) == NULL) { if ((attr = ippFindAttribute(media_size->values[0].collection, "y-dimension", IPP_TAG_ZERO)) == NULL) puts("FAIL (missing y-dimension)"); else printf("FAIL (wrong type for y-dimension - %s)\n", ippTagString(attr->value_tag)); status = 1; } else if (attr->values[0].integer != 29700) { printf("FAIL (wrong value for y-dimension - %d)\n", attr->values[0].integer); status = 1; } else puts("PASS"); } } /* * Test hierarchical find... */ fputs("ippFindAttribute(media-col/media-size/x-dimension): ", stdout); if ((attr = ippFindAttribute(request, "media-col/media-size/x-dimension", IPP_TAG_INTEGER)) != NULL) { if (ippGetInteger(attr, 0) != 21590) { printf("FAIL (wrong value for x-dimension - %d)\n", ippGetInteger(attr, 0)); status = 1; } else puts("PASS"); } else { puts("FAIL (not found)"); status = 1; } fputs("ippFindNextAttribute(media-col/media-size/x-dimension): ", stdout); if ((attr = ippFindNextAttribute(request, "media-col/media-size/x-dimension", IPP_TAG_INTEGER)) != NULL) { if (ippGetInteger(attr, 0) != 21000) { printf("FAIL (wrong value for x-dimension - %d)\n", ippGetInteger(attr, 0)); status = 1; } else puts("PASS"); } else { puts("FAIL (not found)"); status = 1; } fputs("ippFindNextAttribute(media-col/media-size/x-dimension) again: ", stdout); if ((attr = ippFindNextAttribute(request, "media-col/media-size/x-dimension", IPP_TAG_INTEGER)) != NULL) { printf("FAIL (got %d, expected nothing)\n", ippGetInteger(attr, 0)); status = 1; } else puts("PASS"); ippDelete(request); /* * Read the mixed data and confirm we converted everything to rangeOfInteger * values... */ printf("Read Mixed integer/rangeOfInteger from Memory: "); request = ippNew(); data.rpos = 0; data.wused = sizeof(mixed); data.wsize = sizeof(mixed); data.wbuffer = mixed; while ((state = ippReadIO(&data, (ipp_iocb_t)read_cb, 1, NULL, request)) != IPP_STATE_DATA) if (state == IPP_STATE_ERROR) break; length = ippLength(request); if (state != IPP_STATE_DATA) { printf("FAIL - %d bytes read.\n", (int)data.rpos); status = 1; } else if (data.rpos != sizeof(mixed)) { printf("FAIL - read %d bytes, expected %d bytes!\n", (int)data.rpos, (int)sizeof(mixed)); print_attributes(request, 8); status = 1; } else if (length != (sizeof(mixed) + 4)) { printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n", (int)length, (int)sizeof(mixed) + 4); print_attributes(request, 8); status = 1; } else puts("PASS"); fputs("ippFindAttribute(notify-lease-duration-supported): ", stdout); if ((attr = ippFindAttribute(request, "notify-lease-duration-supported", IPP_TAG_ZERO)) == NULL) { puts("FAIL (not found)"); status = 1; } else if (attr->value_tag != IPP_TAG_RANGE) { printf("FAIL (wrong type - %s)\n", ippTagString(attr->value_tag)); status = 1; } else if (attr->num_values != 2) { printf("FAIL (wrong count - %d)\n", attr->num_values); status = 1; } else if (attr->values[0].range.lower != 1 || attr->values[0].range.upper != 1 || attr->values[1].range.lower != 16 || attr->values[1].range.upper != 32) { printf("FAIL (wrong values - %d,%d and %d,%d)\n", attr->values[0].range.lower, attr->values[0].range.upper, attr->values[1].range.lower, attr->values[1].range.upper); status = 1; } else puts("PASS"); ippDelete(request); #ifdef DEBUG /* * Test that private option array is sorted... */ fputs("_ippCheckOptions: ", stdout); if ((name = _ippCheckOptions()) == NULL) puts("PASS"); else { printf("FAIL (\"%s\" out of order)\n", name); status = 1; } #endif /* DEBUG */ /* * Test _ippFindOption() private API... */ fputs("_ippFindOption(\"printer-type\"): ", stdout); if (_ippFindOption("printer-type")) puts("PASS"); else { puts("FAIL"); status = 1; } /* * Summarize... */ putchar('\n'); if (status) puts("Core IPP tests failed."); else puts("Core IPP tests passed."); } else { /* * Read IPP files... */ for (i = 1; i < (size_t)argc; i ++) { if (strlen(argv[i]) > 5 && !strcmp(argv[i] + strlen(argv[i]) - 5, ".test")) { /* * Read an ASCII IPP message... */ _ipp_vars_t v; /* IPP variables */ _ippVarsInit(&v, NULL, NULL, token_cb); request = _ippFileParse(&v, argv[i], NULL); _ippVarsDeinit(&v); } else { /* * Read a raw (binary) IPP message... */ if ((fp = cupsFileOpen(argv[i], "r")) == NULL) { printf("Unable to open \"%s\" - %s\n", argv[i], strerror(errno)); status = 1; continue; } request = ippNew(); while ((state = ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL, request)) == IPP_STATE_ATTRIBUTE); if (state != IPP_STATE_DATA) { printf("Error reading IPP message from \"%s\".\n", argv[i]); status = 1; ippDelete(request); request = NULL; } cupsFileClose(fp); } if (request) { printf("\n%s:\n", argv[i]); print_attributes(request, 4); ippDelete(request); } } } return (status); } /* * 'hex_dump()' - Produce a hex dump of a buffer. */ void hex_dump(const char *title, /* I - Title */ ipp_uchar_t *buffer, /* I - Buffer to dump */ size_t bytes) /* I - Number of bytes */ { size_t i, j; /* Looping vars */ int ch; /* Current ASCII char */ /* * Show lines of 16 bytes at a time... */ printf(" %s:\n", title); for (i = 0; i < bytes; i += 16) { /* * Show the offset... */ printf(" %04x ", (unsigned)i); /* * Then up to 16 bytes in hex... */ for (j = 0; j < 16; j ++) if ((i + j) < bytes) printf(" %02x", buffer[i + j]); else printf(" "); /* * Then the ASCII representation of the bytes... */ putchar(' '); putchar(' '); for (j = 0; j < 16 && (i + j) < bytes; j ++) { ch = buffer[i + j] & 127; if (ch < ' ' || ch == 127) putchar('.'); else putchar(ch); } putchar('\n'); } } /* * 'print_attributes()' - Print the attributes in a request... */ void print_attributes(ipp_t *ipp, /* I - IPP request */ int indent) /* I - Indentation */ { ipp_tag_t group; /* Current group */ ipp_attribute_t *attr; /* Current attribute */ char buffer[2048]; /* Value string */ for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next) { if (!attr->name && indent == 4) { group = IPP_TAG_ZERO; putchar('\n'); continue; } if (group != attr->group_tag) { group = attr->group_tag; printf("\n%*s%s:\n\n", indent - 4, "", ippTagString(group)); } ippAttributeString(attr, buffer, sizeof(buffer)); printf("%*s%s (%s%s): %s\n", indent, "", attr->name ? attr->name : "(null)", attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag), buffer); } } /* * 'read_cb()' - Read data from a buffer. */ ssize_t /* O - Number of bytes read */ read_cb(_ippdata_t *data, /* I - Data */ ipp_uchar_t *buffer, /* O - Buffer to read */ size_t bytes) /* I - Number of bytes to read */ { size_t count; /* Number of bytes */ /* * Copy bytes from the data buffer to the read buffer... */ if ((count = data->wsize - data->rpos) > bytes) count = bytes; memcpy(buffer, data->wbuffer + data->rpos, count); data->rpos += count; /* * Return the number of bytes read... */ return ((ssize_t)count); } /* * 'token_cb()' - Token callback for ASCII IPP data file parser. */ int /* O - 1 on success, 0 on failure */ token_cb(_ipp_file_t *f, /* I - IPP file data */ _ipp_vars_t *v, /* I - IPP variables */ void *user_data, /* I - User data pointer */ const char *token) /* I - Token string */ { (void)v; (void)user_data; if (!token) { f->attrs = ippNew(); f->group_tag = IPP_TAG_PRINTER; } else { fprintf(stderr, "Unknown directive \"%s\" on line %d of \"%s\".\n", token, f->linenum, f->filename); return (0); } return (1); } /* * 'write_cb()' - Write data into a buffer. */ ssize_t /* O - Number of bytes written */ write_cb(_ippdata_t *data, /* I - Data */ ipp_uchar_t *buffer, /* I - Buffer to write */ size_t bytes) /* I - Number of bytes to write */ { size_t count; /* Number of bytes */ /* * Loop until all bytes are written... */ if ((count = data->wsize - data->wused) > bytes) count = bytes; memcpy(data->wbuffer + data->wused, buffer, count); data->wused += count; /* * Return the number of bytes written... */ return ((ssize_t)count); } ippsample/cups/testfile.c0000644000175000017500000003702313240604116014501 0ustar tilltill/* * File test program for CUPS. * * Copyright 2007-2015 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "string-private.h" #include "debug-private.h" #include "file.h" #include #include #ifdef HAVE_LIBZ # include #endif /* HAVE_LIBZ */ #ifdef WIN32 # include #else # include #endif /* WIN32 */ #include /* * Local functions... */ static int count_lines(cups_file_t *fp); static int random_tests(void); static int read_write_tests(int compression); /* * 'main()' - Main entry. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int status; /* Exit status */ char filename[1024]; /* Filename buffer */ cups_file_t *fp; /* File pointer */ #ifndef WIN32 int fds[2]; /* Open file descriptors */ cups_file_t *fdfile; /* File opened with cupsFileOpenFd() */ #endif /* !WIN32 */ int count; /* Number of lines in file */ if (argc == 1) { /* * Do uncompressed file tests... */ status = read_write_tests(0); #ifdef HAVE_LIBZ /* * Do compressed file tests... */ putchar('\n'); status += read_write_tests(1); #endif /* HAVE_LIBZ */ /* * Do uncompressed random I/O tests... */ status += random_tests(); #ifndef WIN32 /* * Test fdopen and close without reading... */ pipe(fds); close(fds[1]); fputs("\ncupsFileOpenFd(fd, \"r\"): ", stdout); fflush(stdout); if ((fdfile = cupsFileOpenFd(fds[0], "r")) == NULL) { puts("FAIL"); status ++; } else { /* * Able to open file, now close without reading. If we don't return * before the alarm fires, that is a failure and we will crash on the * alarm signal... */ puts("PASS"); fputs("cupsFileClose(no read): ", stdout); fflush(stdout); alarm(5); cupsFileClose(fdfile); alarm(0); puts("PASS"); } #endif /* !WIN32 */ /* * Count lines in test file, rewind, then count again. */ fputs("\ncupsFileOpen(\"testfile.txt\", \"r\"): ", stdout); if ((fp = cupsFileOpen("testfile.txt", "r")) == NULL) { puts("FAIL"); status ++; } else { puts("PASS"); fputs("cupsFileGets: ", stdout); if ((count = count_lines(fp)) != 477) { printf("FAIL (got %d lines, expected 477)\n", count); status ++; } else { puts("PASS"); fputs("cupsFileRewind: ", stdout); if (cupsFileRewind(fp) != 0) { puts("FAIL"); status ++; } else { puts("PASS"); fputs("cupsFileGets: ", stdout); if ((count = count_lines(fp)) != 477) { printf("FAIL (got %d lines, expected 477)\n", count); status ++; } else puts("PASS"); } } cupsFileClose(fp); } /* * Test path functions... */ fputs("\ncupsFileFind: ", stdout); #ifdef WIN32 if (cupsFileFind("notepad.exe", "C:/WINDOWS", 1, filename, sizeof(filename)) && cupsFileFind("notepad.exe", "C:/WINDOWS;C:/WINDOWS/SYSTEM32", 1, filename, sizeof(filename))) #else if (cupsFileFind("cat", "/bin", 1, filename, sizeof(filename)) && cupsFileFind("cat", "/bin:/usr/bin", 1, filename, sizeof(filename))) #endif /* WIN32 */ printf("PASS (%s)\n", filename); else { puts("FAIL"); status ++; } /* * Summarize the results and return... */ if (!status) puts("\nALL TESTS PASSED!"); else printf("\n%d TEST(S) FAILED!\n", status); } else { /* * Cat the filename on the command-line... */ char line[8192]; /* Line from file */ if ((fp = cupsFileOpen(argv[1], "r")) == NULL) { perror(argv[1]); status = 1; } else if (argc == 2) { status = 0; while (cupsFileGets(fp, line, sizeof(line))) puts(line); if (!cupsFileEOF(fp)) perror(argv[1]); cupsFileClose(fp); } else { status = 0; ssize_t bytes; while ((bytes = cupsFileRead(fp, line, sizeof(line))) > 0) printf("%s: %d bytes\n", argv[1], (int)bytes); if (cupsFileEOF(fp)) printf("%s: EOF\n", argv[1]); else perror(argv[1]); cupsFileClose(fp); } } return (status); } /* * 'count_lines()' - Count the number of lines in a file. */ static int /* O - Number of lines */ count_lines(cups_file_t *fp) /* I - File to read from */ { int count; /* Number of lines */ char line[1024]; /* Line buffer */ for (count = 0; cupsFileGets(fp, line, sizeof(line)); count ++); return (count); } /* * 'random_tests()' - Do random access tests. */ static int /* O - Status */ random_tests(void) { int status, /* Status of tests */ pass, /* Current pass */ count, /* Number of records read */ record, /* Current record */ num_records; /* Number of records */ off_t pos; /* Position in file */ ssize_t expected; /* Expected position in file */ cups_file_t *fp; /* File */ char buffer[512]; /* Data buffer */ /* * Run 4 passes, each time appending to a data file and then reopening the * file for reading to validate random records in the file. */ for (status = 0, pass = 0; pass < 4; pass ++) { /* * cupsFileOpen(append) */ printf("\ncupsFileOpen(append %d): ", pass); if ((fp = cupsFileOpen("testfile.dat", "a")) == NULL) { printf("FAIL (%s)\n", strerror(errno)); status ++; break; } else puts("PASS"); /* * cupsFileTell() */ expected = 256 * (ssize_t)sizeof(buffer) * pass; fputs("cupsFileTell(): ", stdout); if ((pos = cupsFileTell(fp)) != (off_t)expected) { printf("FAIL (" CUPS_LLFMT " instead of " CUPS_LLFMT ")\n", CUPS_LLCAST pos, CUPS_LLCAST expected); status ++; break; } else puts("PASS"); /* * cupsFileWrite() */ fputs("cupsFileWrite(256 512-byte records): ", stdout); for (record = 0; record < 256; record ++) { memset(buffer, record, sizeof(buffer)); if (cupsFileWrite(fp, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) break; } if (record < 256) { printf("FAIL (%d: %s)\n", record, strerror(errno)); status ++; break; } else puts("PASS"); /* * cupsFileTell() */ expected += 256 * (ssize_t)sizeof(buffer); fputs("cupsFileTell(): ", stdout); if ((pos = cupsFileTell(fp)) != (off_t)expected) { printf("FAIL (" CUPS_LLFMT " instead of " CUPS_LLFMT ")\n", CUPS_LLCAST pos, CUPS_LLCAST expected); status ++; break; } else puts("PASS"); cupsFileClose(fp); /* * cupsFileOpen(read) */ printf("\ncupsFileOpen(read %d): ", pass); if ((fp = cupsFileOpen("testfile.dat", "r")) == NULL) { printf("FAIL (%s)\n", strerror(errno)); status ++; break; } else puts("PASS"); /* * cupsFileSeek, cupsFileRead */ fputs("cupsFileSeek(), cupsFileRead(): ", stdout); for (num_records = (pass + 1) * 256, count = (pass + 1) * 256, record = ((int)CUPS_RAND() & 65535) % num_records; count > 0; count --, record = (record + ((int)CUPS_RAND() & 31) - 16 + num_records) % num_records) { /* * The last record is always the first... */ if (count == 1) record = 0; /* * Try reading the data for the specified record, and validate the * contents... */ expected = (ssize_t)sizeof(buffer) * record; if ((pos = cupsFileSeek(fp, expected)) != expected) { printf("FAIL (" CUPS_LLFMT " instead of " CUPS_LLFMT ")\n", CUPS_LLCAST pos, CUPS_LLCAST expected); status ++; break; } else { if (cupsFileRead(fp, buffer, sizeof(buffer)) != sizeof(buffer)) { printf("FAIL (%s)\n", strerror(errno)); status ++; break; } else if ((buffer[0] & 255) != (record & 255) || memcmp(buffer, buffer + 1, sizeof(buffer) - 1)) { printf("FAIL (Bad Data - %d instead of %d)\n", buffer[0] & 255, record & 255); status ++; break; } } } if (count == 0) puts("PASS"); cupsFileClose(fp); } /* * Remove the test file... */ unlink("testfile.dat"); /* * Return the test status... */ return (status); } /* * 'read_write_tests()' - Perform read/write tests. */ static int /* O - Status */ read_write_tests(int compression) /* I - Use compression? */ { int i; /* Looping var */ cups_file_t *fp; /* File */ int status; /* Exit status */ char line[1024], /* Line from file */ *value; /* Directive value from line */ int linenum; /* Line number */ unsigned char readbuf[8192], /* Read buffer */ writebuf[8192]; /* Write buffer */ int byte; /* Byte from file */ ssize_t bytes; /* Number of bytes read/written */ off_t length; /* Length of file */ static const char *partial_line = "partial line"; /* Partial line */ /* * No errors so far... */ status = 0; /* * Initialize the write buffer with random data... */ CUPS_SRAND((unsigned)time(NULL)); for (i = 0; i < (int)sizeof(writebuf); i ++) writebuf[i] = (unsigned char)CUPS_RAND(); /* * cupsFileOpen(write) */ printf("cupsFileOpen(write%s): ", compression ? " compressed" : ""); fp = cupsFileOpen(compression ? "testfile.dat.gz" : "testfile.dat", compression ? "w9" : "w"); if (fp) { puts("PASS"); /* * cupsFileCompression() */ fputs("cupsFileCompression(): ", stdout); if (cupsFileCompression(fp) == compression) puts("PASS"); else { printf("FAIL (Got %d, expected %d)\n", cupsFileCompression(fp), compression); status ++; } /* * cupsFilePuts() */ fputs("cupsFilePuts(): ", stdout); if (cupsFilePuts(fp, "# Hello, World\n") > 0) puts("PASS"); else { printf("FAIL (%s)\n", strerror(errno)); status ++; } /* * cupsFilePrintf() */ fputs("cupsFilePrintf(): ", stdout); for (i = 0; i < 1000; i ++) if (cupsFilePrintf(fp, "TestLine %03d\n", i) < 0) break; if (i >= 1000) puts("PASS"); else { printf("FAIL (%s)\n", strerror(errno)); status ++; } /* * cupsFilePutChar() */ fputs("cupsFilePutChar(): ", stdout); for (i = 0; i < 256; i ++) if (cupsFilePutChar(fp, i) < 0) break; if (i >= 256) puts("PASS"); else { printf("FAIL (%s)\n", strerror(errno)); status ++; } /* * cupsFileWrite() */ fputs("cupsFileWrite(): ", stdout); for (i = 0; i < 10000; i ++) if (cupsFileWrite(fp, (char *)writebuf, sizeof(writebuf)) < 0) break; if (i >= 10000) puts("PASS"); else { printf("FAIL (%s)\n", strerror(errno)); status ++; } /* * cupsFilePuts() with partial line... */ fputs("cupsFilePuts(\"partial line\"): ", stdout); if (cupsFilePuts(fp, partial_line) > 0) puts("PASS"); else { printf("FAIL (%s)\n", strerror(errno)); status ++; } /* * cupsFileTell() */ fputs("cupsFileTell(): ", stdout); if ((length = cupsFileTell(fp)) == 81933283) puts("PASS"); else { printf("FAIL (" CUPS_LLFMT " instead of 81933283)\n", CUPS_LLCAST length); status ++; } /* * cupsFileClose() */ fputs("cupsFileClose(): ", stdout); if (!cupsFileClose(fp)) puts("PASS"); else { printf("FAIL (%s)\n", strerror(errno)); status ++; } } else { printf("FAIL (%s)\n", strerror(errno)); status ++; } /* * cupsFileOpen(read) */ fputs("\ncupsFileOpen(read): ", stdout); fp = cupsFileOpen(compression ? "testfile.dat.gz" : "testfile.dat", "r"); if (fp) { puts("PASS"); /* * cupsFileGets() */ fputs("cupsFileGets(): ", stdout); if (cupsFileGets(fp, line, sizeof(line))) { if (line[0] == '#') puts("PASS"); else { printf("FAIL (Got line \"%s\", expected comment line)\n", line); status ++; } } else { printf("FAIL (%s)\n", strerror(errno)); status ++; } /* * cupsFileCompression() */ fputs("cupsFileCompression(): ", stdout); if (cupsFileCompression(fp) == compression) puts("PASS"); else { printf("FAIL (Got %d, expected %d)\n", cupsFileCompression(fp), compression); status ++; } /* * cupsFileGetConf() */ linenum = 1; fputs("cupsFileGetConf(): ", stdout); for (i = 0, value = NULL; i < 1000; i ++) if (!cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) break; else if (_cups_strcasecmp(line, "TestLine") || !value || atoi(value) != i || linenum != (i + 2)) break; if (i >= 1000) puts("PASS"); else if (line[0]) { printf("FAIL (Line %d, directive \"%s\", value \"%s\")\n", linenum, line, value ? value : "(null)"); status ++; } else { printf("FAIL (%s)\n", strerror(errno)); status ++; } /* * cupsFileGetChar() */ fputs("cupsFileGetChar(): ", stdout); for (i = 0, byte = 0; i < 256; i ++) if ((byte = cupsFileGetChar(fp)) != i) break; if (i >= 256) puts("PASS"); else if (byte >= 0) { printf("FAIL (Got %d, expected %d)\n", byte, i); status ++; } else { printf("FAIL (%s)\n", strerror(errno)); status ++; } /* * cupsFileRead() */ fputs("cupsFileRead(): ", stdout); for (i = 0, bytes = 0; i < 10000; i ++) if ((bytes = cupsFileRead(fp, (char *)readbuf, sizeof(readbuf))) < 0) break; else if (memcmp(readbuf, writebuf, sizeof(readbuf))) break; if (i >= 10000) puts("PASS"); else if (bytes > 0) { printf("FAIL (Pass %d, ", i); for (i = 0; i < (int)sizeof(readbuf); i ++) if (readbuf[i] != writebuf[i]) break; printf("match failed at offset %d - got %02X, expected %02X)\n", i, readbuf[i], writebuf[i]); } else { printf("FAIL (%s)\n", strerror(errno)); status ++; } /* * cupsFileGetChar() with partial line... */ fputs("cupsFileGetChar(partial line): ", stdout); for (i = 0; i < (int)strlen(partial_line); i ++) if ((byte = cupsFileGetChar(fp)) < 0) break; else if (byte != partial_line[i]) break; if (!partial_line[i]) puts("PASS"); else { printf("FAIL (got '%c', expected '%c')\n", byte, partial_line[i]); status ++; } /* * cupsFileTell() */ fputs("cupsFileTell(): ", stdout); if ((length = cupsFileTell(fp)) == 81933283) puts("PASS"); else { printf("FAIL (" CUPS_LLFMT " instead of 81933283)\n", CUPS_LLCAST length); status ++; } /* * cupsFileClose() */ fputs("cupsFileClose(): ", stdout); if (!cupsFileClose(fp)) puts("PASS"); else { printf("FAIL (%s)\n", strerror(errno)); status ++; } } else { printf("FAIL (%s)\n", strerror(errno)); status ++; } /* * Remove the test file... */ if (!status) unlink(compression ? "testfile.dat.gz" : "testfile.dat"); /* * Return the test status... */ return (status); } ippsample/cups/string-private.h0000644000175000017500000001232513240604116015643 0ustar tilltill/* * Private string definitions for CUPS. * * Copyright 2007-2015 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_STRING_PRIVATE_H_ # define _CUPS_STRING_PRIVATE_H_ /* * Include necessary headers... */ # include # include # include # include # include # include # include # include "config.h" # ifdef HAVE_STRING_H # include # endif /* HAVE_STRING_H */ # ifdef HAVE_STRINGS_H # include # endif /* HAVE_STRINGS_H */ # ifdef HAVE_BSTRING_H # include # endif /* HAVE_BSTRING_H */ # if defined(WIN32) && !defined(__CUPS_SSIZE_T_DEFINED) # define __CUPS_SSIZE_T_DEFINED # include /* Windows does not support the ssize_t type, so map it to long... */ typedef long ssize_t; /* @private@ */ # endif /* WIN32 && !__CUPS_SSIZE_T_DEFINED */ /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * String pool structures... */ # define _CUPS_STR_GUARD 0x12344321 typedef struct _cups_sp_item_s /**** String Pool Item ****/ { # ifdef DEBUG_GUARDS unsigned int guard; /* Guard word */ # endif /* DEBUG_GUARDS */ unsigned int ref_count; /* Reference count */ char str[1]; /* String */ } _cups_sp_item_t; /* * Replacements for the ctype macros that are not affected by locale, since we * really only care about testing for ASCII characters when parsing files, etc. * * The _CUPS_INLINE definition controls whether we get an inline function body, * and external function body, or an external definition. */ # if defined(__GNUC__) || __STDC_VERSION__ >= 199901L # define _CUPS_INLINE static inline # elif defined(_MSC_VER) # define _CUPS_INLINE static __inline # elif defined(_CUPS_STRING_C_) # define _CUPS_INLINE # endif /* __GNUC__ || __STDC_VERSION__ */ # ifdef _CUPS_INLINE _CUPS_INLINE int /* O - 1 on match, 0 otherwise */ _cups_isalnum(int ch) /* I - Character to test */ { return ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')); } _CUPS_INLINE int /* O - 1 on match, 0 otherwise */ _cups_isalpha(int ch) /* I - Character to test */ { return ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')); } _CUPS_INLINE int /* O - 1 on match, 0 otherwise */ _cups_islower(int ch) /* I - Character to test */ { return (ch >= 'a' && ch <= 'z'); } _CUPS_INLINE int /* O - 1 on match, 0 otherwise */ _cups_isspace(int ch) /* I - Character to test */ { return (ch == ' ' || ch == '\f' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\v'); } _CUPS_INLINE int /* O - 1 on match, 0 otherwise */ _cups_isupper(int ch) /* I - Character to test */ { return (ch >= 'A' && ch <= 'Z'); } _CUPS_INLINE int /* O - Converted character */ _cups_tolower(int ch) /* I - Character to convert */ { return (_cups_isupper(ch) ? ch - 'A' + 'a' : ch); } _CUPS_INLINE int /* O - Converted character */ _cups_toupper(int ch) /* I - Character to convert */ { return (_cups_islower(ch) ? ch - 'a' + 'A' : ch); } # else extern int _cups_isalnum(int ch); extern int _cups_isalpha(int ch); extern int _cups_islower(int ch); extern int _cups_isspace(int ch); extern int _cups_isupper(int ch); extern int _cups_tolower(int ch); extern int _cups_toupper(int ch); # endif /* _CUPS_INLINE */ /* * Prototypes... */ extern ssize_t _cups_safe_vsnprintf(char *, size_t, const char *, va_list); extern void _cups_strcpy(char *dst, const char *src); # ifndef HAVE_STRDUP extern char *_cups_strdup(const char *); # define strdup _cups_strdup # endif /* !HAVE_STRDUP */ extern int _cups_strcasecmp(const char *, const char *); extern int _cups_strncasecmp(const char *, const char *, size_t n); # ifndef HAVE_STRLCAT extern size_t _cups_strlcat(char *, const char *, size_t); # define strlcat _cups_strlcat # endif /* !HAVE_STRLCAT */ # ifndef HAVE_STRLCPY extern size_t _cups_strlcpy(char *, const char *, size_t); # define strlcpy _cups_strlcpy # endif /* !HAVE_STRLCPY */ # ifndef HAVE_SNPRINTF extern int _cups_snprintf(char *, size_t, const char *, ...) __attribute__ ((__format__ (__printf__, 3, 4))); # define snprintf _cups_snprintf # endif /* !HAVE_SNPRINTF */ # ifndef HAVE_VSNPRINTF extern int _cups_vsnprintf(char *, size_t, const char *, va_list); # define vsnprintf _cups_vsnprintf # endif /* !HAVE_VSNPRINTF */ /* * String pool functions... */ extern char *_cupsStrAlloc(const char *s); extern void _cupsStrFlush(void); extern void _cupsStrFree(const char *s); extern char *_cupsStrRetain(const char *s); extern size_t _cupsStrStatistics(size_t *alloc_bytes, size_t *total_bytes); /* * Floating point number functions... */ extern char *_cupsStrFormatd(char *buf, char *bufend, double number, struct lconv *loc); extern double _cupsStrScand(const char *buf, char **bufptr, struct lconv *loc); /* * Date function... */ extern char *_cupsStrDate(char *buf, size_t bufsize, time_t timeval); /* * C++ magic... */ # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_STRING_H_ */ ippsample/cups/testfile.txt0000644000175000017500000007534413240604116015106 0ustar tilltillLorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi faucibus viverra nibh ut molestie. Sed aliquet vestibulum dignissim. Praesent dignissim mauris arcu. Donec porta velit quis nibh rutrum sollicitudin. Aliquam vel tellus vulputate, sollicitudin turpis in, luctus quam. Donec hendrerit enim dignissim varius tincidunt. Phasellus mi felis, ultrices nec magna in, ultrices interdum justo. Nulla aliquam sem ac porta tincidunt. Praesent nec fermentum mauris. Suspendisse ullamcorper mauris orci, eu ornare dui mollis quis. In vitae lorem id nulla pellentesque sagittis. Duis aliquet ligula nisl, sed mollis sapien commodo nec. Etiam placerat arcu turpis, eget viverra magna ultrices sed. Nullam dapibus urna et tristique consectetur. Curabitur iaculis nisl lobortis condimentum accumsan. Praesent sagittis purus nunc, vitae bibendum leo ornare a. Maecenas neque mauris, mollis a sem ut, rhoncus posuere orci. Aliquam luctus suscipit erat ut semper. In neque augue, vulputate ornare massa fermentum, sodales faucibus mauris. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque mattis ante nunc, sit amet blandit felis cursus sed. Quisque pellentesque ipsum ac mauris fringilla, a rhoncus nunc lacinia. Vestibulum tempor orci ut nisl cursus, at euismod sem sodales. Integer ornare tellus at sapien tincidunt ultrices. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer placerat eleifend magna, eget volutpat nibh vulputate eget. Donec cursus orci nisl, eget malesuada sem porta at. Sed maximus eleifend leo, posuere pellentesque urna viverra id. Aenean pharetra nunc ut suscipit aliquam. Sed dolor massa, ultrices sed sollicitudin nec, dapibus vitae tortor. Cras in scelerisque tellus. Sed eu felis vitae neque tempor eleifend vitae ac augue. Nunc felis ex, fringilla quis sapien vel, tempor congue nibh. Nullam placerat sit amet lacus quis facilisis. Sed semper nisi eget auctor semper. Phasellus sodales tempus massa ut suscipit. Integer malesuada convallis neque, sed pretium leo rhoncus ac. In hac habitasse platea dictumst. Nullam efficitur mollis lorem. Integer convallis lobortis dictum. Suspendisse euismod in mauris vel pharetra. Sed vitae magna ut turpis viverra rhoncus ut sit amet mauris. Nam vel lacinia metus. Proin ut elementum felis. Nullam massa velit, euismod vel metus eget, feugiat aliquet odio. Fusce venenatis lorem ut lectus ultricies, vitae accumsan nibh dictum. Maecenas porta euismod cursus. Nunc at ligula congue, lobortis quam id, volutpat felis. Proin blandit pulvinar ligula, at dapibus dui rutrum dictum. Etiam non finibus urna. Pellentesque semper pharetra arcu non dapibus. Vestibulum gravida dictum libero, quis dictum odio hendrerit sit amet. Aenean a venenatis ante, tincidunt convallis orci. Morbi tincidunt, orci vitae suscipit lacinia, nisl nunc rutrum ex, vitae convallis nulla libero ut mauris. Donec ac pellentesque sapien. Phasellus elementum orci a nisl feugiat tempus. Quisque id justo sed tellus ultricies porttitor. Fusce elementum mauris nunc. Nullam vel elit ultrices, rhoncus elit id, scelerisque erat. Pellentesque molestie efficitur purus, at malesuada orci efficitur et. Curabitur blandit nisi a ante viverra, vel ornare turpis molestie. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras scelerisque est non velit placerat, eu volutpat sem fermentum. Cras vitae gravida nisi, non vestibulum velit. Interdum et malesuada fames ac ante ipsum primis in faucibus. Cras sollicitudin rutrum tincidunt. Pellentesque non nisl condimentum, commodo turpis non, fringilla ante. Nunc non ante vel est porttitor tempor sed vitae nunc. Donec bibendum orci justo, lobortis laoreet purus accumsan vel. Phasellus non posuere orci. In hac habitasse platea dictumst. Praesent nec mi sit amet urna ornare pulvinar faucibus at sem. Vestibulum vel cursus nisl, vel ultricies justo. Proin sed consequat odio, eget dignissim dolor. Fusce mattis porttitor nulla rutrum aliquet. Duis vehicula enim nec condimentum dignissim. Phasellus viverra ex at erat lacinia varius. Nullam rutrum felis ac lacus dignissim elementum quis sit amet felis. Phasellus eget sapien sit amet sapien maximus tincidunt elementum ut ante. Mauris dictum pulvinar diam ac lobortis. Duis vitae dui metus. Donec imperdiet risus vitae augue placerat ultrices. Integer euismod, sapien sit amet faucibus venenatis, nisl lacus rhoncus lacus, a auctor justo ante sed turpis. Integer facilisis est non venenatis hendrerit. Vivamus quis ante sodales, mollis turpis in, bibendum turpis. In hac habitasse platea dictumst. Phasellus nisl est, porta feugiat eros ut, scelerisque efficitur diam. Suspendisse sit amet magna libero. Quisque eu arcu vel orci iaculis sagittis nec id orci. Mauris mattis nunc id quam tristique pellentesque. Vestibulum vehicula, mauris ac venenatis lobortis, ex risus bibendum nunc, eu bibendum dolor metus vitae purus. Ut bibendum sed ante viverra tincidunt. Vestibulum id semper lacus. Fusce lacinia dignissim semper. Proin diam enim, pellentesque vel dui eu, maximus tincidunt mauris. Cras lorem lectus, malesuada non dui ac, iaculis elementum justo. Fusce fringilla tempor arcu. Proin vel turpis vitae purus facilisis dapibus condimentum sed ipsum. Duis mollis justo at ante convallis ornare. Suspendisse accumsan eleifend mauris, ut aliquet eros scelerisque eget. Proin ornare elit eu felis dapibus, sit amet posuere est porttitor. Vivamus tincidunt metus ac nisl pharetra, vel mollis neque egestas. Quisque turpis ligula, lacinia id suscipit eget, cursus eget mauris. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales, urna eget luctus congue, metus magna viverra nisl, ut eleifend nulla urna eu arcu. Pellentesque interdum interdum erat, et hendrerit arcu rhoncus ut. Nulla congue tortor nec egestas aliquam. Nulla elementum augue eu est imperdiet, nec maximus sapien ornare. Donec aliquam blandit felis, sed vulputate orci ultrices non. Vivamus rutrum dapibus ligula, non ullamcorper ante eleifend vel. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aliquam sed lacus condimentum odio commodo tristique. Proin ultrices non tellus sit amet condimentum. Ut aliquam nulla eget viverra aliquet. Fusce aliquet orci nec finibus tempor. Etiam luctus eleifend diam vitae tempor. Fusce sagittis porttitor dignissim. Morbi euismod pellentesque mi vel malesuada. Praesent cursus rutrum diam sit amet auctor. Praesent non leo consequat, dapibus massa pellentesque, egestas nulla. Nulla efficitur luctus purus eu aliquet. Phasellus sed enim pharetra, molestie felis eget, tempor neque. Proin efficitur vestibulum libero ut hendrerit. Mauris vitae vestibulum augue, in pellentesque ligula. Phasellus at libero dictum, pretium mauris vitae, elementum ex. Pellentesque ut euismod orci. In ac elit vel nisl bibendum fermentum eget in dui. Donec fringilla, nisl vitae tincidunt varius, tellus sapien accumsan lectus, ac tincidunt eros ipsum nec libero. Sed mollis purus nec magna tempus, vitae laoreet purus luctus. Morbi accumsan, urna eget placerat volutpat, nunc magna mattis mi, vitae efficitur eros quam quis lacus. Etiam eros ligula, tempus vel consectetur non, consectetur quis risus. Phasellus venenatis lectus arcu, quis bibendum diam dignissim a. Donec tristique, felis quis dignissim tempor, justo sapien faucibus odio, at venenatis arcu purus et justo. Nunc vel ex a augue luctus pharetra ac ac turpis. Proin auctor turpis lobortis, scelerisque mi sit amet, elementum dui. Duis blandit arcu eros, eu dapibus enim imperdiet sed. Sed auctor urna sed lectus condimentum rhoncus. Mauris luctus dolor rhoncus suscipit semper. Sed molestie felis ut laoreet porta. Duis at purus viverra, faucibus elit eu, fringilla odio. Suspendisse sit amet sodales urna. In hac habitasse platea dictumst. Integer a sem sed augue sodales dictum. Quisque ut nisi pellentesque, lobortis lectus et, hendrerit eros. Phasellus posuere metus sit amet orci viverra vehicula. Nulla urna est, pellentesque in placerat ut, congue a ligula. Maecenas non viverra arcu. Vivamus fermentum odio tincidunt tellus tempus, ut suscipit justo hendrerit. Nunc quis sapien eget turpis mollis porta. Curabitur ultrices est molestie lacus finibus, vel sodales leo aliquam. Quisque ultrices semper porta. Nulla facilisi. Aenean nunc leo, ultrices quis augue non, hendrerit semper lectus. Nulla facilisi. In in volutpat tellus. Sed tincidunt efficitur sem, vel bibendum ex pharetra eleifend. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed nec erat at ipsum fringilla commodo eget eu est. Donec suscipit ligula eu ipsum lobortis tristique. Nulla dignissim nisi quis dignissim faucibus. Nunc finibus lacus eget est laoreet ultrices. Fusce molestie mattis facilisis. Fusce dictum blandit sem ac tincidunt. Suspendisse aliquam, dolor ac tincidunt scelerisque, lacus leo luctus quam, ac auctor ligula neque quis dolor. Maecenas laoreet viverra lectus, eget hendrerit urna congue ac. Donec convallis, erat ut consectetur ornare, diam diam accumsan lacus, at consectetur mauris nisi vitae massa. Vestibulum vestibulum dictum volutpat. Quisque et commodo velit. Praesent in odio nunc. Vivamus consectetur leo sem, sit amet auctor arcu blandit vitae. Donec non auctor mauris. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin nibh tellus, fermentum quis erat in, vulputate faucibus nunc. Vestibulum imperdiet ipsum purus, eget efficitur mi hendrerit vel. Aenean iaculis elementum metus nec consectetur. Suspendisse felis turpis, maximus sit amet diam at, elementum vestibulum nulla. Quisque et lacinia elit. Pellentesque tincidunt bibendum neque, non molestie massa ultrices eget. Duis scelerisque magna in blandit dictum. Pellentesque lacinia augue vitae fermentum mollis. Etiam mi velit, tempor at risus vel, luctus vestibulum odio. Phasellus vel ipsum sit amet velit malesuada hendrerit. Donec consequat laoreet enim. Aliquam sed justo eget ex rhoncus laoreet. Duis maximus tortor at odio suscipit, non accumsan arcu efficitur. Nunc pharetra id neque nec dignissim. Sed condimentum magna ut viverra porttitor. Pellentesque rutrum magna et pretium semper. Fusce tincidunt ipsum at auctor commodo. Duis et ipsum nec turpis pharetra pulvinar a nec risus. Praesent in enim et ligula maximus consectetur. Aenean nec turpis turpis. Quisque mollis dignissim elit, sit amet interdum urna venenatis sit amet. Quisque interdum, diam eu ullamcorper suscipit, augue purus fermentum purus, nec consequat purus nibh laoreet lectus. Ut nisi mauris, ultrices non euismod ac, mollis id libero. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras vitae tristique mi. Mauris ut bibendum dolor. Suspendisse potenti. Ut tempus ultricies erat, a molestie sapien aliquet non. Aliquam sagittis nisi vel enim rhoncus eleifend. Proin aliquam eros ut metus consectetur suscipit. Curabitur ornare mi eget faucibus aliquam. Praesent ultricies libero est, eget porttitor risus ornare nec. Curabitur pharetra ex ut eleifend lacinia. Nam nec finibus nunc. Sed hendrerit risus nisi, eu sollicitudin tellus sollicitudin nec. Proin vel est leo. Fusce et orci finibus, auctor purus eu, varius magna. Sed sollicitudin elit vitae turpis tincidunt, at suscipit lacus ultricies. Mauris pretium, nisi sed cursus ullamcorper, sem sem vulputate neque, a pellentesque lectus massa vel metus. Sed tincidunt iaculis lectus, non facilisis elit finibus at. Nunc odio purus, eleifend ac pretium nec, malesuada condimentum eros. Aenean interdum dolor et malesuada auctor. Donec placerat velit ex, vel cursus metus posuere sed. Phasellus rutrum nisl vel imperdiet egestas. Interdum et malesuada fames ac ante ipsum primis in faucibus. Etiam volutpat quam ut risus ultricies blandit. Mauris commodo ullamcorper pretium. Nam interdum lobortis eleifend. Fusce quam nisl, feugiat vitae dui non, egestas eleifend erat. Mauris in ligula purus. Morbi vel mollis diam. Praesent leo felis, luctus ac blandit sit amet, aliquam at enim. Duis sit amet augue enim. Donec feugiat ultricies neque, ut porttitor lectus sagittis ut. Sed ante sem, mollis ut dui quis, finibus rutrum justo. Phasellus ornare nibh ac scelerisque fringilla. Donec rhoncus luctus elit sed accumsan. Maecenas fermentum quam nec eros consequat, vitae sollicitudin elit facilisis. Phasellus urna metus, viverra at nibh ac, euismod fringilla mi. Aliquam nec odio neque. Duis pulvinar congue aliquam. Suspendisse laoreet bibendum sapien, non ultricies velit porta id. Vivamus dignissim rhoncus mi, sit amet mollis arcu cursus nec. Maecenas sagittis cursus dictum. Nam fermentum tincidunt pellentesque. Vivamus tempus tincidunt rutrum. Mauris semper orci non scelerisque accumsan. Nulla fermentum in lacus at aliquet. Proin ut ligula venenatis, maximus elit a, finibus felis. Nam euismod arcu vel diam laoreet, sed hendrerit urna pharetra. Phasellus non hendrerit tortor. Donec ut congue odio. Nunc pellentesque ipsum et est venenatis, sed vehicula magna convallis. Quisque eget euismod orci. In ut nulla ac augue auctor dapibus a vel arcu. Duis elementum, libero at ullamcorper consequat, libero nulla vestibulum elit, vel congue lacus nulla quis nulla. Nulla vel dolor vulputate, dictum nunc nec, pellentesque lacus. Nulla nibh mi, gravida vel velit vel, tempus dapibus magna. Mauris ornare elementum feugiat. Vestibulum non finibus lorem, a ullamcorper quam. Duis eget velit sodales, rhoncus odio nec, laoreet lorem. Donec fermentum est eu ornare placerat. Sed interdum metus ac metus hendrerit rhoncus. In molestie diam sem, et faucibus purus lacinia eu. Donec quam arcu, tempus ac commodo sit amet, porttitor sit amet urna. Suspendisse pellentesque placerat mi, at semper orci tincidunt non. Fusce ut mattis nisi. Pellentesque vel nisi quis massa volutpat aliquam vel nec tortor. Maecenas vitae risus quis nibh vestibulum rutrum. Vestibulum egestas dolor ullamcorper lorem placerat tincidunt. Curabitur massa urna, pharetra sed gravida vitae, venenatis a tellus. Duis condimentum lectus tellus, ut sodales ipsum hendrerit ac. Nullam sed accumsan arcu, ut sollicitudin diam. Integer eu ligula vitae purus vehicula vulputate nec et metus. Aenean mollis tempor lectus eu elementum. Integer in dui tempus, porttitor erat sed, malesuada magna. Cras nec orci sed tellus porta tristique a ac dui. Nam eu faucibus mi. Praesent condimentum laoreet augue id pellentesque. In malesuada ex sed turpis consectetur, non sodales mi cursus. Nunc id sem luctus, mattis lorem vel, tempus ipsum. Nunc efficitur augue et nunc hendrerit, non tincidunt magna commodo. Aenean sodales porta mi. Sed semper accumsan turpis vitae aliquam. Phasellus vitae ex faucibus, suscipit ante non, commodo ligula. Aliquam erat volutpat. Etiam odio sem, fringilla in sem eu, bibendum ornare est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec fringilla magna. Morbi eu cursus sem. Fusce euismod eget turpis et bibendum. Donec vel tincidunt neque. Suspendisse commodo euismod sodales. Integer pretium congue tortor nec ullamcorper. Nam imperdiet, urna auctor pretium facilisis, sem arcu malesuada turpis, sit amet sodales nisi lectus sollicitudin tellus. Praesent consequat leo in dui congue, euismod ornare risus malesuada. Nunc id tincidunt tortor. Vestibulum sit amet sapien urna. Donec quis tristique elit, non facilisis neque. Donec gravida molestie tellus, sagittis accumsan metus varius eu. Duis nec est vitae augue laoreet rhoncus non nec mi. Phasellus pretium pharetra magna, et congue urna posuere eget. Sed finibus arcu magna, sed luctus ante suscipit quis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce at accumsan quam. Mauris dolor lectus, tempus auctor ante ut, auctor maximus turpis. Proin pulvinar dolor in consectetur aliquam. Fusce sagittis elementum fermentum. Aliquam nec posuere ipsum. Nulla commodo est at magna fringilla lobortis. Etiam diam orci, venenatis non erat iaculis, commodo hendrerit diam. Nam imperdiet justo vitae massa consectetur, ornare feugiat ipsum molestie. Curabitur dignissim vitae augue et euismod. Interdum et malesuada fames ac ante ipsum primis in faucibus. Praesent justo nunc, pellentesque vel ante vitae, dignissim maximus felis. Proin vel congue nisl. Quisque ac tempus libero. In at placerat tellus. Integer lobortis ligula vel dolor ornare finibus. Donec semper nisl mauris, eu consectetur lacus sollicitudin a. Integer sem enim, consectetur sed tincidunt id, dignissim at mauris. In a justo non erat cursus tincidunt et sed sapien. Aenean vulputate placerat ornare. Etiam id lectus lacus. Donec a sodales sapien. Duis in suscipit est, ultrices mollis magna. Etiam blandit diam vitae sollicitudin sodales. Proin vel diam nec neque ullamcorper ullamcorper ut at sapien. Sed quis sollicitudin libero. Nulla sed arcu consequat, egestas libero viverra, dignissim magna. Nullam semper turpis a sem tincidunt, ut molestie ante tincidunt. Curabitur efficitur nisl quis aliquam tristique. Proin a auctor lectus. Donec dictum mauris a leo consequat, eu bibendum neque efficitur. Donec euismod, mi nec faucibus ornare, elit est tincidunt ligula, at molestie neque augue non justo. Vestibulum condimentum varius felis non pretium. Praesent maximus ex sed justo tristique elementum. Phasellus nec feugiat dolor. Nulla sed odio quam. Nulla nec massa sit amet tellus efficitur accumsan sed et orci. Nullam sed mollis augue, eget dictum metus. Etiam ut velit elit. Nullam nibh eros, commodo vitae maximus sit amet, convallis sit amet elit. Nullam faucibus arcu tortor, vitae tincidunt augue ullamcorper in. Praesent quis metus et purus volutpat pulvinar. Sed commodo vehicula sodales. Phasellus fringilla vehicula placerat. Vestibulum sit amet ante in ante condimentum laoreet. Sed id purus diam. Suspendisse in libero in risus eleifend fringilla. Cras non sapien vel sapien condimentum tristique. Integer non semper mi, a aliquet enim. Phasellus congue erat sed lorem molestie consectetur. Integer iaculis nisi et nisi blandit auctor. Nullam magna diam, hendrerit sollicitudin urna vel, gravida congue diam. Curabitur finibus ipsum ex, ac feugiat massa posuere at. Pellentesque in molestie lorem. Fusce rhoncus velit at magna accumsan convallis. Aliquam posuere elementum turpis, eget eleifend quam auctor et. Mauris a diam vitae magna malesuada fermentum sit amet ut justo. Quisque in purus et erat rhoncus accumsan. Donec feugiat, ipsum vel pulvinar suscipit, nibh nisi volutpat felis, nec rutrum nisi turpis at diam. Suspendisse posuere, ante ut imperdiet tempor, tortor magna maximus risus, id fermentum urna mauris hendrerit magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Ut eu faucibus neque. Fusce tempus luctus dui ut ullamcorper. Suspendisse in velit a turpis facilisis scelerisque. Nullam ultricies sodales convallis. Proin viverra vulputate justo sit amet interdum. Donec mi neque, dapibus ac ex at, dignissim tincidunt lacus. Praesent ultricies, erat ac sagittis tempor, justo turpis porta tortor, eget consectetur turpis odio sed nibh. Vestibulum vitae porta lorem, efficitur viverra enim. Nullam sodales sagittis tristique. Duis ac velit ultrices, efficitur tortor sit amet, varius lacus. Praesent blandit et arcu sit amet tempus. Quisque neque lectus, congue at rutrum at, commodo eu velit. Aliquam sed mi a ante condimentum consectetur. Morbi feugiat risus dolor, ac auctor massa ultrices in. Praesent laoreet metus non urna rhoncus, vel lacinia ex dapibus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur vitae arcu vel enim feugiat rhoncus. Nullam nec neque sed nulla hendrerit iaculis sed non erat. Pellentesque orci lacus, ullamcorper posuere odio vel, efficitur elementum ipsum. Morbi justo risus, faucibus sit amet urna eu, facilisis consequat ipsum. Quisque et congue ipsum, at ornare lacus. Nunc laoreet elit nec arcu lobortis consectetur. Sed consectetur ultrices risus, quis tincidunt lectus fermentum at. Nunc libero sem, dignissim pharetra lacinia eu, posuere quis libero. Sed at lacus consectetur, molestie nisi quis, scelerisque tortor. Etiam accumsan placerat nulla, vel consectetur felis aliquam et. Cras pellentesque massa a ex commodo condimentum. Integer nec nulla sed metus dignissim placerat. Ut vel urna augue. Donec pharetra justo ac ex pretium, ut condimentum erat lacinia. Nunc id porta nunc, ac dapibus massa. Suspendisse accumsan justo quis felis pharetra tempus. Donec rutrum nulla in consectetur tincidunt. Sed eu orci eu ligula maximus aliquet eget sed ex. Donec rhoncus fringilla tellus, a bibendum mi placerat eu. Pellentesque luctus finibus neque blandit pharetra. Aenean nec elit pretium, sodales lacus sed, mollis felis. Duis commodo pellentesque risus et semper. Praesent pretium, libero pharetra fringilla faucibus, ipsum urna porta nunc, nec euismod dolor risus eget lacus. Curabitur malesuada dapibus tellus ut luctus. Aliquam gravida mauris tellus, ut vestibulum massa dignissim vestibulum. Sed pulvinar, ex et consequat malesuada, erat tellus bibendum mi, nec auctor nulla massa eu justo. Suspendisse imperdiet interdum ligula. Donec at pretium urna. Donec quis diam leo. Aenean ac lectus non justo aliquam consequat vitae mattis ipsum. Integer at consectetur felis, et volutpat sapien. Suspendisse efficitur libero eu pulvinar cursus. Suspendisse interdum enim id nibh imperdiet, et pulvinar lectus aliquet. Donec ultricies mattis lorem eget malesuada. Sed hendrerit massa in rutrum auctor. Suspendisse interdum mauris in sem vestibulum volutpat. Maecenas interdum facilisis dui, posuere volutpat eros suscipit eget. Curabitur blandit odio turpis, non dignissim magna varius sit amet. Suspendisse cursus ipsum id metus venenatis, eu malesuada arcu congue. Nulla vitae mi ut nibh pretium cursus in vitae turpis. In hac habitasse platea dictumst. Phasellus consectetur, metus at tempus sollicitudin, nibh est molestie nunc, sed imperdiet purus sapien in lorem. Etiam eget leo nec sem efficitur luctus. Vestibulum mattis a odio ut volutpat. Duis consequat magna eget luctus vulputate. Nam viverra posuere ultricies. Duis sagittis nunc et sem sagittis venenatis. Sed massa lacus, vestibulum eget convallis ac, facilisis nec turpis. Morbi ac ornare ex. Quisque non laoreet lectus, sed tempus libero. Sed non neque risus. Sed gravida, mauris ac aliquam porttitor, dolor massa faucibus est, eget vestibulum eros eros et risus. Morbi sit amet tincidunt eros, ut cursus mauris. Integer a lectus pharetra, molestie massa vel, laoreet sem. Suspendisse et enim libero. Nam molestie risus nec ex laoreet, a faucibus massa rhoncus. Vivamus faucibus sapien eget lorem efficitur auctor. Curabitur sit amet leo non massa tempor bibendum. Nunc in tristique est. Donec id mollis mauris, vel porta magna. Nulla vulputate eleifend lacus sed tincidunt. Maecenas vitae sapien eu neque hendrerit venenatis sit amet nec nulla. Morbi vestibulum dui lectus, id commodo dui vehicula eget. Nulla laoreet turpis vitae lacus vehicula lacinia. Integer rhoncus tellus mi, vitae gravida metus convallis quis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris et accumsan sem. Sed elementum egestas tellus eget eleifend. Sed finibus luctus felis. Maecenas ultrices sodales orci non dapibus. Phasellus vitae lacus at diam ultrices mattis porta non ipsum. Aliquam erat volutpat. Vestibulum auctor diam vehicula gravida volutpat. In rhoncus, dui sit amet consequat convallis, odio mauris tincidunt mi, vestibulum imperdiet lacus erat sed metus. Aenean in augue eu tortor dictum tempor a ac magna. Mauris aliquet justo eget sem sollicitudin, congue facilisis velit mollis. Proin dignissim, nulla a efficitur fringilla, orci nulla malesuada velit, eget cursus dolor metus vitae nisl. Phasellus non neque ipsum. Pellentesque porta vehicula ipsum, nec posuere urna bibendum et. Etiam nec nisl eu nulla tempus placerat. Pellentesque risus magna, accumsan vitae sem vitae, cursus fermentum elit. Ut varius efficitur turpis, et pellentesque libero rutrum hendrerit. Maecenas condimentum lobortis eros, a euismod metus. Ut risus sapien, pulvinar quis euismod id, vestibulum ac erat. Donec feugiat tempor commodo. Donec ligula est, aliquet eu sagittis eu, posuere vel eros. Nullam sollicitudin diam eget libero malesuada, vel tempus lectus congue. Praesent a odio risus. Nullam maximus tellus sed ligula eleifend, sed mollis nunc consequat. Quisque eros mi, imperdiet nec ipsum in, pretium feugiat nibh. Pellentesque cursus justo at metus condimentum consectetur. Nulla facilisi. Ut tincidunt sem eget diam rhoncus, vitae gravida ipsum facilisis. Integer et condimentum purus. Sed faucibus tempus orci, id cursus eros volutpat non. Nam pulvinar ex nec enim egestas ultricies. Suspendisse at eros ac metus sodales varius eu in ante. Cras sed est quis magna tempus mollis id faucibus nibh. Curabitur convallis nisi dolor, in imperdiet ante tempor eu. Quisque placerat leo et leo cursus, nec eleifend urna scelerisque. Duis consequat ex a sapien facilisis consectetur. Vivamus et aliquam lacus. Praesent consequat lacus in aliquam ultricies. Sed consectetur vehicula aliquet. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vivamus tellus neque, eleifend sed purus quis, elementum luctus mi. Nullam elit lacus, finibus a sollicitudin in, suscipit non nunc. Nulla vulputate odio vitae mauris tristique, ac interdum urna interdum. Phasellus nec tortor hendrerit, mattis ante non, pharetra tortor. Pellentesque vitae tempor urna, ut gravida enim. Sed eget sem purus. Nunc semper quam mi, sed mollis ligula feugiat at. Pellentesque finibus augue risus, et ultricies lacus scelerisque vel. Proin euismod tortor quam, et cursus ipsum dictum ac. Suspendisse laoreet velit consequat ullamcorper cursus. Nam ultricies gravida viverra. Vivamus non sodales quam, eget rutrum quam. Suspendisse venenatis lorem sodales lectus eleifend, ac consequat odio finibus. Morbi id maximus metus, a molestie neque. Integer eget felis sit amet sem tempor placerat. Suspendisse lobortis congue justo eu accumsan. Nullam accumsan laoreet purus. Nulla quis efficitur risus. Ut ac leo libero. Nam nec nisi iaculis, ornare nunc fringilla, sodales lectus. Nulla laoreet mauris sodales, sagittis enim non, vestibulum orci. Fusce orci dui, dapibus nec ligula vitae, vulputate maximus ante. Mauris vitae felis tincidunt, ullamcorper neque quis, pulvinar nisl. Fusce ut augue ac nisl posuere tristique ac sed leo. Nunc pellentesque pretium turpis. Integer maximus rutrum felis, ut molestie mauris mattis non. Morbi ac risus ut mauris porta pharetra. Fusce mollis pharetra turpis nec consequat. Aenean tincidunt felis vel nulla porta, faucibus egestas ligula efficitur. Morbi et dictum velit. Proin scelerisque justo in tristique congue. Maecenas consequat ante dapibus justo vehicula pretium. Sed consequat turpis ac orci suscipit malesuada non a risus. In id leo molestie, venenatis risus quis, dignissim nulla. Nulla aliquet risus nulla, a convallis sem tincidunt ac. Pellentesque scelerisque, elit eu finibus eleifend, orci lectus egestas lorem, nec bibendum libero est non leo. Nullam nisl ante, ullamcorper in efficitur a, consectetur sit amet tellus. Ut et pellentesque eros. Etiam mattis nulla justo, sed ultricies dui commodo vel. Ut tristique posuere leo, ac facilisis massa lobortis nec. Quisque leo ligula, venenatis vel facilisis vel, volutpat ac sapien. Fusce sed porttitor urna. Phasellus tempus semper condimentum. Aliquam sit amet felis vel nulla porta luctus id vel leo. Ut ut odio tincidunt, ultrices enim at, pellentesque sem. Proin bibendum ligula lacus, ut tempus mauris tincidunt id. Praesent sollicitudin interdum tellus, vel tincidunt nisi ultrices a. Aliquam cursus faucibus elit, quis lacinia erat elementum eu. Duis sollicitudin lectus lectus, ut ultrices elit malesuada quis. Phasellus viverra turpis sit amet erat iaculis dapibus. Donec semper turpis sed risus pharetra pharetra. Donec ut ante ac orci blandit interdum. Pellentesque facilisis id purus egestas placerat. Suspendisse sit amet euismod velit, et rutrum ipsum. Maecenas at mi pulvinar, dignissim erat quis, blandit libero. Praesent quam tortor, tempus et laoreet nec, aliquet sed libero. Duis vestibulum est sed risus venenatis rhoncus. Phasellus arcu libero, commodo eget tincidunt non, aliquam in velit. Phasellus imperdiet ante a laoreet gravida. Cras faucibus semper nulla eu facilisis. Praesent non sem sem. Nulla tempus ullamcorper sollicitudin. Ut eget nisi eget augue fermentum consequat. Proin congue a nisi eget ullamcorper. Pellentesque luctus diam felis, a pharetra nunc cursus in. Vivamus a quam dolor. Curabitur fermentum elit sit amet purus ultricies, ut placerat nisl finibus. Nunc sed ligula diam. Ut efficitur risus tortor. Suspendisse sem elit, posuere sit amet nisi et, placerat tristique ipsum. Ut nunc ex, fermentum sed tempor vitae, scelerisque quis nulla. Duis ac aliquam lectus. Curabitur consequat maximus leo sed cursus. Maecenas cursus lectus non porttitor consectetur. Vivamus ultricies, lectus non tempor porttitor, turpis velit auctor leo, at auctor nibh justo ut mi. Vivamus interdum massa at fermentum cursus. Nulla suscipit purus nulla, vel condimentum eros rhoncus eget. Nulla malesuada aliquet maximus. Nulla blandit ipsum finibus leo rhoncus, non lobortis felis scelerisque. Duis blandit massa quis velit efficitur cursus. Aliquam nibh arcu, dictum et feugiat eget, iaculis ac risus. Nunc facilisis pellentesque mauris, a aliquet libero eleifend eu. Pellentesque a turpis et justo blandit maximus. Phasellus imperdiet dui odio, eu facilisis quam porttitor id. Morbi accumsan, mauris eget fermentum porta, mi risus sagittis nisi, in semper odio orci a magna. Praesent maximus accumsan odio, vitae bibendum ipsum ultrices eu. Vestibulum laoreet purus nec neque fringilla dignissim. Morbi interdum diam eget ornare vestibulum. Etiam egestas at ipsum eget dapibus. Nullam feugiat mi ex, et varius odio ornare id. Sed sagittis augue quam, in maximus orci tincidunt vel. Duis molestie felis nunc, et feugiat risus vestibulum et. Integer efficitur augue elit, id commodo lorem volutpat sed. Fusce quam velit, suscipit a posuere sit amet, pulvinar sed nisi. Fusce lacinia accumsan nunc vitae lobortis. Vivamus eu fringilla velit. Cras hendrerit efficitur faucibus. Praesent facilisis a nulla non efficitur. Etiam quis est ac neque pharetra bibendum a vitae neque. Phasellus dui dui, pellentesque in facilisis quis, vulputate non nibh. Integer in lobortis velit. Curabitur efficitur imperdiet dolor, vel tempus dui fermentum quis. Maecenas porttitor nibh at nibh cursus mattis. In dolor neque, efficitur at ligula nec, lobortis aliquam ipsum. Phasellus quam magna, imperdiet at nunc a, suscipit aliquam metus. Cras consequat, enim vitae feugiat venenatis, enim urna venenatis ligula, vel cursus odio lectus id purus. Integer sit amet finibus diam. Fusce aliquet vehicula mauris, a varius metus semper in. Cras sodales malesuada consectetur.ippsample/cups/tls-gnutls.c0000644000175000017500000012734113240604116015001 0ustar tilltill/* * TLS support code for CUPS using GNU TLS. * * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /**** This file is included from tls.c ****/ /* * Include necessary headers... */ #include /* * Local globals... */ static int tls_auto_create = 0; /* Auto-create self-signed certs? */ static char *tls_common_name = NULL; /* Default common name */ static gnutls_x509_crl_t tls_crl = NULL;/* Certificate revocation list */ static char *tls_keypath = NULL; /* Server cert keychain path */ static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER; /* Mutex for keychain/certs */ static int tls_options = -1,/* Options for TLS connections */ tls_min_version = _HTTP_TLS_1_0, tls_max_version = _HTTP_TLS_MAX; /* * Local functions... */ static gnutls_x509_crt_t http_gnutls_create_credential(http_credential_t *credential); static const char *http_gnutls_default_path(char *buffer, size_t bufsize); static void http_gnutls_load_crl(void); static const char *http_gnutls_make_path(char *buffer, size_t bufsize, const char *dirname, const char *filename, const char *ext); static ssize_t http_gnutls_read(gnutls_transport_ptr_t ptr, void *data, size_t length); static ssize_t http_gnutls_write(gnutls_transport_ptr_t ptr, const void *data, size_t length); /* * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 1 on success, 0 on failure */ cupsMakeServerCredentials( const char *path, /* I - Path to keychain/directory */ const char *common_name, /* I - Common name */ int num_alt_names, /* I - Number of subject alternate names */ const char **alt_names, /* I - Subject Alternate Names */ time_t expiration_date) /* I - Expiration date */ { gnutls_x509_crt_t crt; /* Self-signed certificate */ gnutls_x509_privkey_t key; /* Encryption private key */ char temp[1024], /* Temporary directory name */ crtfile[1024], /* Certificate filename */ keyfile[1024]; /* Private key filename */ cups_lang_t *language; /* Default language info */ cups_file_t *fp; /* Key/cert file */ unsigned char buffer[8192]; /* Buffer for x509 data */ size_t bytes; /* Number of bytes of data */ unsigned char serial[4]; /* Serial number buffer */ time_t curtime; /* Current time */ int result; /* Result of GNU TLS calls */ DEBUG_printf(("cupsMakeServerCredentials(path=\"%s\", common_name=\"%s\", num_alt_names=%d, alt_names=%p, expiration_date=%d)", path, common_name, num_alt_names, alt_names, (int)expiration_date)); /* * Filenames... */ if (!path) path = http_gnutls_default_path(temp, sizeof(temp)); if (!path || !common_name) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (0); } http_gnutls_make_path(crtfile, sizeof(crtfile), path, common_name, "crt"); http_gnutls_make_path(keyfile, sizeof(keyfile), path, common_name, "key"); /* * Create the encryption key... */ DEBUG_puts("1cupsMakeServerCredentials: Creating key pair."); gnutls_x509_privkey_init(&key); gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0); DEBUG_puts("1cupsMakeServerCredentials: Key pair created."); /* * Save it... */ bytes = sizeof(buffer); if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, buffer, &bytes)) < 0) { DEBUG_printf(("1cupsMakeServerCredentials: Unable to export private key: %s", gnutls_strerror(result))); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(result), 0); gnutls_x509_privkey_deinit(key); return (0); } else if ((fp = cupsFileOpen(keyfile, "w")) != NULL) { DEBUG_printf(("1cupsMakeServerCredentials: Writing private key to \"%s\".", keyfile)); cupsFileWrite(fp, (char *)buffer, bytes); cupsFileClose(fp); } else { DEBUG_printf(("1cupsMakeServerCredentials: Unable to create private key file \"%s\": %s", keyfile, strerror(errno))); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); gnutls_x509_privkey_deinit(key); return (0); } /* * Create the self-signed certificate... */ DEBUG_puts("1cupsMakeServerCredentials: Generating self-signed X.509 certificate."); language = cupsLangDefault(); curtime = time(NULL); serial[0] = curtime >> 24; serial[1] = curtime >> 16; serial[2] = curtime >> 8; serial[3] = curtime; gnutls_x509_crt_init(&crt); if (strlen(language->language) == 5) gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, language->language + 3, 2); else gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, "US", 2); gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0, common_name, strlen(common_name)); gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, common_name, strlen(common_name)); gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, "Unknown", 7); gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, "Unknown", 7); gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0, "Unknown", 7); /* gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0, ServerAdmin, strlen(ServerAdmin));*/ gnutls_x509_crt_set_key(crt, key); gnutls_x509_crt_set_serial(crt, serial, sizeof(serial)); gnutls_x509_crt_set_activation_time(crt, curtime); gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400); gnutls_x509_crt_set_ca_status(crt, 0); if (num_alt_names > 0) gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME, alt_names[0]); gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0); gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT); gnutls_x509_crt_set_version(crt, 3); bytes = sizeof(buffer); if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0) gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes); gnutls_x509_crt_sign(crt, crt, key); /* * Save it... */ bytes = sizeof(buffer); if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, buffer, &bytes)) < 0) { DEBUG_printf(("1cupsMakeServerCredentials: Unable to export public key and X.509 certificate: %s", gnutls_strerror(result))); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(result), 0); gnutls_x509_crt_deinit(crt); gnutls_x509_privkey_deinit(key); return (0); } else if ((fp = cupsFileOpen(crtfile, "w")) != NULL) { DEBUG_printf(("1cupsMakeServerCredentials: Writing public key and X.509 certificate to \"%s\".", crtfile)); cupsFileWrite(fp, (char *)buffer, bytes); cupsFileClose(fp); } else { DEBUG_printf(("1cupsMakeServerCredentials: Unable to create public key and X.509 certificate file \"%s\": %s", crtfile, strerror(errno))); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); gnutls_x509_crt_deinit(crt); gnutls_x509_privkey_deinit(key); return (0); } /* * Cleanup... */ gnutls_x509_crt_deinit(crt); gnutls_x509_privkey_deinit(key); DEBUG_puts("1cupsMakeServerCredentials: Successfully created credentials."); return (1); } /* * 'cupsSetServerCredentials()' - Set the default server credentials. * * Note: The server credentials are used by all threads in the running process. * This function is threadsafe. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 1 on success, 0 on failure */ cupsSetServerCredentials( const char *path, /* I - Path to keychain/directory */ const char *common_name, /* I - Default common name for server */ int auto_create) /* I - 1 = automatically create self-signed certificates */ { char temp[1024]; /* Default path buffer */ DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path, common_name, auto_create)); /* * Use defaults as needed... */ if (!path) path = http_gnutls_default_path(temp, sizeof(temp)); /* * Range check input... */ if (!path || !common_name) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (0); } _cupsMutexLock(&tls_mutex); /* * Free old values... */ if (tls_keypath) _cupsStrFree(tls_keypath); if (tls_common_name) _cupsStrFree(tls_common_name); /* * Save the new values... */ tls_keypath = _cupsStrAlloc(path); tls_auto_create = auto_create; tls_common_name = _cupsStrAlloc(common_name); _cupsMutexUnlock(&tls_mutex); return (1); } /* * 'httpCopyCredentials()' - Copy the credentials associated with the peer in * an encrypted connection. * * @since CUPS 1.5/macOS 10.7@ */ int /* O - Status of call (0 = success) */ httpCopyCredentials( http_t *http, /* I - Connection to server */ cups_array_t **credentials) /* O - Array of credentials */ { unsigned count; /* Number of certificates */ const gnutls_datum_t *certs; /* Certificates */ DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http, credentials)); if (credentials) *credentials = NULL; if (!http || !http->tls || !credentials) return (-1); *credentials = cupsArrayNew(NULL, NULL); certs = gnutls_certificate_get_peers(http->tls, &count); DEBUG_printf(("1httpCopyCredentials: certs=%p, count=%u", certs, count)); if (certs && count) { while (count > 0) { httpAddCredential(*credentials, certs->data, certs->size); certs ++; count --; } } return (0); } /* * '_httpCreateCredentials()' - Create credentials in the internal format. */ http_tls_credentials_t /* O - Internal credentials */ _httpCreateCredentials( cups_array_t *credentials) /* I - Array of credentials */ { (void)credentials; return (NULL); } /* * '_httpFreeCredentials()' - Free internal credentials. */ void _httpFreeCredentials( http_tls_credentials_t credentials) /* I - Internal credentials */ { (void)credentials; } /* * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 1 if valid, 0 otherwise */ httpCredentialsAreValidForName( cups_array_t *credentials, /* I - Credentials */ const char *common_name) /* I - Name to check */ { gnutls_x509_crt_t cert; /* Certificate */ int result = 0; /* Result */ cert = http_gnutls_create_credential((http_credential_t *)cupsArrayFirst(credentials)); if (cert) { result = gnutls_x509_crt_check_hostname(cert, common_name) != 0; if (result) { int i, /* Looping var */ count; /* Number of revoked certificates */ unsigned char cserial[1024], /* Certificate serial number */ rserial[1024]; /* Revoked serial number */ size_t cserial_size, /* Size of cert serial number */ rserial_size; /* Size of revoked serial number */ _cupsMutexLock(&tls_mutex); count = gnutls_x509_crl_get_crt_count(tls_crl); if (count > 0) { cserial_size = sizeof(cserial); gnutls_x509_crt_get_serial(cert, cserial, &cserial_size); for (i = 0; i < count; i ++) { rserial_size = sizeof(rserial); if (!gnutls_x509_crl_get_crt_serial(tls_crl, (unsigned)i, rserial, &rserial_size, NULL) && cserial_size == rserial_size && !memcmp(cserial, rserial, (int)rserial_size)) { result = 0; break; } } } _cupsMutexUnlock(&tls_mutex); } gnutls_x509_crt_deinit(cert); } return (result); } /* * 'httpCredentialsGetTrust()' - Return the trust of credentials. * * @since CUPS 2.0/OS 10.10@ */ http_trust_t /* O - Level of trust */ httpCredentialsGetTrust( cups_array_t *credentials, /* I - Credentials */ const char *common_name) /* I - Common name for trust lookup */ { http_trust_t trust = HTTP_TRUST_OK; /* Trusted? */ gnutls_x509_crt_t cert; /* Certificate */ cups_array_t *tcreds = NULL; /* Trusted credentials */ _cups_globals_t *cg = _cupsGlobals(); /* Per-thread globals */ if (!common_name) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No common name specified."), 1); return (HTTP_TRUST_UNKNOWN); } if ((cert = http_gnutls_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create credentials from array."), 1); return (HTTP_TRUST_UNKNOWN); } if (cg->any_root < 0) { _cupsSetDefaults(); http_gnutls_load_crl(); } /* * Look this common name up in the default keychains... */ httpLoadCredentials(NULL, &tcreds, common_name); if (tcreds) { char credentials_str[1024], /* String for incoming credentials */ tcreds_str[1024]; /* String for saved credentials */ httpCredentialsString(credentials, credentials_str, sizeof(credentials_str)); httpCredentialsString(tcreds, tcreds_str, sizeof(tcreds_str)); if (strcmp(credentials_str, tcreds_str)) { /* * Credentials don't match, let's look at the expiration date of the new * credentials and allow if the new ones have a later expiration... */ if (!cg->trust_first) { /* * Do not trust certificates on first use... */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1); trust = HTTP_TRUST_INVALID; } else if (httpCredentialsGetExpiration(credentials) <= httpCredentialsGetExpiration(tcreds)) { /* * The new credentials are not newly issued... */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("New credentials are older than stored credentials."), 1); trust = HTTP_TRUST_INVALID; } else if (!httpCredentialsAreValidForName(credentials, common_name)) { /* * The common name does not match the issued certificate... */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("New credentials are not valid for name."), 1); trust = HTTP_TRUST_INVALID; } else if (httpCredentialsGetExpiration(tcreds) < time(NULL)) { /* * Save the renewed credentials... */ trust = HTTP_TRUST_RENEWED; httpSaveCredentials(NULL, credentials, common_name); } } httpFreeCredentials(tcreds); } else if (cg->validate_certs && !httpCredentialsAreValidForName(credentials, common_name)) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No stored credentials, not valid for name."), 1); trust = HTTP_TRUST_INVALID; } else if (!cg->trust_first) { /* * See if we have a site CA certificate we can compare... */ if (!httpLoadCredentials(NULL, &tcreds, "site")) { if (cupsArrayCount(credentials) != (cupsArrayCount(tcreds) + 1)) { /* * Certificate isn't directly generated from the CA cert... */ trust = HTTP_TRUST_INVALID; } else { /* * Do a tail comparison of the two certificates... */ http_credential_t *a, *b; /* Certificates */ for (a = (http_credential_t *)cupsArrayFirst(tcreds), b = (http_credential_t *)cupsArrayIndex(credentials, 1); a && b; a = (http_credential_t *)cupsArrayNext(tcreds), b = (http_credential_t *)cupsArrayNext(credentials)) if (a->datalen != b->datalen || memcmp(a->data, b->data, a->datalen)) break; if (a || b) trust = HTTP_TRUST_INVALID; } if (trust != HTTP_TRUST_OK) _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Credentials do not validate against site CA certificate."), 1); } else { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1); trust = HTTP_TRUST_INVALID; } } if (trust == HTTP_TRUST_OK && !cg->expired_certs) { time_t curtime; /* Current date/time */ time(&curtime); if (curtime < gnutls_x509_crt_get_activation_time(cert) || curtime > gnutls_x509_crt_get_expiration_time(cert)) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Credentials have expired."), 1); trust = HTTP_TRUST_EXPIRED; } } if (trust == HTTP_TRUST_OK && !cg->any_root && cupsArrayCount(credentials) == 1) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Self-signed credentials are blocked."), 1); trust = HTTP_TRUST_INVALID; } gnutls_x509_crt_deinit(cert); return (trust); } /* * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials. * * @since CUPS 2.0/OS 10.10@ */ time_t /* O - Expiration date of credentials */ httpCredentialsGetExpiration( cups_array_t *credentials) /* I - Credentials */ { gnutls_x509_crt_t cert; /* Certificate */ time_t result = 0; /* Result */ cert = http_gnutls_create_credential((http_credential_t *)cupsArrayFirst(credentials)); if (cert) { result = gnutls_x509_crt_get_expiration_time(cert); gnutls_x509_crt_deinit(cert); } return (result); } /* * 'httpCredentialsString()' - Return a string representing the credentials. * * @since CUPS 2.0/OS 10.10@ */ size_t /* O - Total size of credentials string */ httpCredentialsString( cups_array_t *credentials, /* I - Credentials */ char *buffer, /* I - Buffer or @code NULL@ */ size_t bufsize) /* I - Size of buffer */ { http_credential_t *first; /* First certificate */ gnutls_x509_crt_t cert; /* Certificate */ DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", credentials, buffer, CUPS_LLCAST bufsize)); if (!buffer) return (0); if (buffer && bufsize > 0) *buffer = '\0'; if ((first = (http_credential_t *)cupsArrayFirst(credentials)) != NULL && (cert = http_gnutls_create_credential(first)) != NULL) { char name[256]; /* Common name associated with cert */ size_t namelen; /* Length of name */ time_t expiration; /* Expiration date of cert */ unsigned char md5_digest[16]; /* MD5 result */ namelen = sizeof(name) - 1; if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, name, &namelen) >= 0) name[namelen] = '\0'; else strlcpy(name, "unknown", sizeof(name)); expiration = gnutls_x509_crt_get_expiration_time(cert); cupsHashData("md5", first->data, first->datalen, md5_digest, sizeof(md5_digest)); snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", name, httpGetDateString(expiration), md5_digest[0], md5_digest[1], md5_digest[2], md5_digest[3], md5_digest[4], md5_digest[5], md5_digest[6], md5_digest[7], md5_digest[8], md5_digest[9], md5_digest[10], md5_digest[11], md5_digest[12], md5_digest[13], md5_digest[14], md5_digest[15]); gnutls_x509_crt_deinit(cert); } DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer)); return (strlen(buffer)); } /* * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 0 on success, -1 on error */ httpLoadCredentials( const char *path, /* I - Keychain/PKCS#12 path */ cups_array_t **credentials, /* IO - Credentials */ const char *common_name) /* I - Common name for credentials */ { cups_file_t *fp; /* Certificate file */ char filename[1024], /* filename.crt */ temp[1024], /* Temporary string */ line[256]; /* Base64-encoded line */ unsigned char *data = NULL; /* Buffer for cert data */ size_t alloc_data = 0, /* Bytes allocated */ num_data = 0; /* Bytes used */ int decoded; /* Bytes decoded */ int in_certificate = 0; /* In a certificate? */ if (!credentials || !common_name) return (-1); if (!path) path = http_gnutls_default_path(temp, sizeof(temp)); if (!path) return (-1); http_gnutls_make_path(filename, sizeof(filename), path, common_name, "crt"); if ((fp = cupsFileOpen(filename, "r")) == NULL) return (-1); while (cupsFileGets(fp, line, sizeof(line))) { if (!strcmp(line, "-----BEGIN CERTIFICATE-----")) { if (in_certificate) { /* * Missing END CERTIFICATE... */ httpFreeCredentials(*credentials); *credentials = NULL; break; } in_certificate = 1; } else if (!strcmp(line, "-----END CERTIFICATE-----")) { if (!in_certificate || !num_data) { /* * Missing data... */ httpFreeCredentials(*credentials); *credentials = NULL; break; } if (!*credentials) *credentials = cupsArrayNew(NULL, NULL); if (httpAddCredential(*credentials, data, num_data)) { httpFreeCredentials(*credentials); *credentials = NULL; break; } num_data = 0; in_certificate = 0; } else if (in_certificate) { if (alloc_data == 0) { data = malloc(2048); alloc_data = 2048; if (!data) break; } else if ((num_data + strlen(line)) >= alloc_data) { unsigned char *tdata = realloc(data, alloc_data + 1024); /* Expanded buffer */ if (!tdata) { httpFreeCredentials(*credentials); *credentials = NULL; break; } data = tdata; alloc_data += 1024; } decoded = alloc_data - num_data; httpDecode64_2((char *)data + num_data, &decoded, line); num_data += (size_t)decoded; } } cupsFileClose(fp); if (in_certificate) { /* * Missing END CERTIFICATE... */ httpFreeCredentials(*credentials); *credentials = NULL; } if (data) free(data); return (*credentials ? 0 : -1); } /* * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file. * * @since CUPS 2.0/OS 10.10@ */ int /* O - -1 on error, 0 on success */ httpSaveCredentials( const char *path, /* I - Keychain/PKCS#12 path */ cups_array_t *credentials, /* I - Credentials */ const char *common_name) /* I - Common name for credentials */ { cups_file_t *fp; /* Certificate file */ char filename[1024], /* filename.crt */ nfilename[1024],/* filename.crt.N */ temp[1024], /* Temporary string */ line[256]; /* Base64-encoded line */ const unsigned char *ptr; /* Pointer into certificate */ ssize_t remaining; /* Bytes left */ http_credential_t *cred; /* Current credential */ if (!credentials || !common_name) return (-1); if (!path) path = http_gnutls_default_path(temp, sizeof(temp)); if (!path) return (-1); http_gnutls_make_path(filename, sizeof(filename), path, common_name, "crt"); snprintf(nfilename, sizeof(nfilename), "%s.N", filename); if ((fp = cupsFileOpen(nfilename, "w")) == NULL) return (-1); fchmod(cupsFileNumber(fp), 0600); for (cred = (http_credential_t *)cupsArrayFirst(credentials); cred; cred = (http_credential_t *)cupsArrayNext(credentials)) { cupsFilePuts(fp, "-----BEGIN CERTIFICATE-----\n"); for (ptr = cred->data, remaining = (ssize_t)cred->datalen; remaining > 0; remaining -= 45, ptr += 45) { httpEncode64_2(line, sizeof(line), (char *)ptr, remaining > 45 ? 45 : remaining); cupsFilePrintf(fp, "%s\n", line); } cupsFilePuts(fp, "-----END CERTIFICATE-----\n"); } cupsFileClose(fp); return (rename(nfilename, filename)); } /* * 'http_gnutls_create_credential()' - Create a single credential in the internal format. */ static gnutls_x509_crt_t /* O - Certificate */ http_gnutls_create_credential( http_credential_t *credential) /* I - Credential */ { int result; /* Result from GNU TLS */ gnutls_x509_crt_t cert; /* Certificate */ gnutls_datum_t datum; /* Data record */ DEBUG_printf(("3http_gnutls_create_credential(credential=%p)", credential)); if (!credential) return (NULL); if ((result = gnutls_x509_crt_init(&cert)) < 0) { DEBUG_printf(("4http_gnutls_create_credential: init error: %s", gnutls_strerror(result))); return (NULL); } datum.data = credential->data; datum.size = credential->datalen; if ((result = gnutls_x509_crt_import(cert, &datum, GNUTLS_X509_FMT_DER)) < 0) { DEBUG_printf(("4http_gnutls_create_credential: import error: %s", gnutls_strerror(result))); gnutls_x509_crt_deinit(cert); return (NULL); } return (cert); } /* * 'http_gnutls_default_path()' - Get the default credential store path. */ static const char * /* O - Path or NULL on error */ http_gnutls_default_path(char *buffer,/* I - Path buffer */ size_t bufsize)/* I - Size of path buffer */ { const char *home = getenv("HOME"); /* HOME environment variable */ if (getuid() && home) { snprintf(buffer, bufsize, "%s/.cups", home); if (access(buffer, 0)) { DEBUG_printf(("1http_gnutls_default_path: Making directory \"%s\".", buffer)); if (mkdir(buffer, 0700)) { DEBUG_printf(("1http_gnutls_default_path: Failed to make directory: %s", strerror(errno))); return (NULL); } } snprintf(buffer, bufsize, "%s/.cups/ssl", home); if (access(buffer, 0)) { DEBUG_printf(("1http_gnutls_default_path: Making directory \"%s\".", buffer)); if (mkdir(buffer, 0700)) { DEBUG_printf(("1http_gnutls_default_path: Failed to make directory: %s", strerror(errno))); return (NULL); } } } else strlcpy(buffer, CUPS_SERVERROOT "/ssl", bufsize); DEBUG_printf(("1http_gnutls_default_path: Using default path \"%s\".", buffer)); return (buffer); } /* * 'http_gnutls_load_crl()' - Load the certificate revocation list, if any. */ static void http_gnutls_load_crl(void) { _cupsMutexLock(&tls_mutex); if (!gnutls_x509_crl_init(&tls_crl)) { cups_file_t *fp; /* CRL file */ char filename[1024], /* site.crl */ line[256]; /* Base64-encoded line */ unsigned char *data = NULL; /* Buffer for cert data */ size_t alloc_data = 0, /* Bytes allocated */ num_data = 0; /* Bytes used */ int decoded; /* Bytes decoded */ gnutls_datum_t datum; /* Data record */ http_gnutls_make_path(filename, sizeof(filename), CUPS_SERVERROOT, "site", "crl"); if ((fp = cupsFileOpen(filename, "r")) != NULL) { while (cupsFileGets(fp, line, sizeof(line))) { if (!strcmp(line, "-----BEGIN X509 CRL-----")) { if (num_data) { /* * Missing END X509 CRL... */ break; } } else if (!strcmp(line, "-----END X509 CRL-----")) { if (!num_data) { /* * Missing data... */ break; } datum.data = data; datum.size = num_data; gnutls_x509_crl_import(tls_crl, &datum, GNUTLS_X509_FMT_PEM); num_data = 0; } else { if (alloc_data == 0) { data = malloc(2048); alloc_data = 2048; if (!data) break; } else if ((num_data + strlen(line)) >= alloc_data) { unsigned char *tdata = realloc(data, alloc_data + 1024); /* Expanded buffer */ if (!tdata) break; data = tdata; alloc_data += 1024; } decoded = alloc_data - num_data; httpDecode64_2((char *)data + num_data, &decoded, line); num_data += (size_t)decoded; } } cupsFileClose(fp); if (data) free(data); } } _cupsMutexUnlock(&tls_mutex); } /* * 'http_gnutls_make_path()' - Format a filename for a certificate or key file. */ static const char * /* O - Filename */ http_gnutls_make_path( char *buffer, /* I - Filename buffer */ size_t bufsize, /* I - Size of buffer */ const char *dirname, /* I - Directory */ const char *filename, /* I - Filename (usually hostname) */ const char *ext) /* I - Extension */ { char *bufptr, /* Pointer into buffer */ *bufend = buffer + bufsize - 1; /* End of buffer */ snprintf(buffer, bufsize, "%s/", dirname); bufptr = buffer + strlen(buffer); while (*filename && bufptr < bufend) { if (_cups_isalnum(*filename) || *filename == '-' || *filename == '.') *bufptr++ = *filename; else *bufptr++ = '_'; filename ++; } if (bufptr < bufend) *bufptr++ = '.'; strlcpy(bufptr, ext, (size_t)(bufend - bufptr + 1)); return (buffer); } /* * 'http_gnutls_read()' - Read function for the GNU TLS library. */ static ssize_t /* O - Number of bytes read or -1 on error */ http_gnutls_read( gnutls_transport_ptr_t ptr, /* I - Connection to server */ void *data, /* I - Buffer */ size_t length) /* I - Number of bytes to read */ { http_t *http; /* HTTP connection */ ssize_t bytes; /* Bytes read */ DEBUG_printf(("6http_gnutls_read(ptr=%p, data=%p, length=%d)", ptr, data, (int)length)); http = (http_t *)ptr; if (!http->blocking) { /* * Make sure we have data before we read... */ while (!_httpWait(http, http->wait_value, 0)) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; http->error = ETIMEDOUT; return (-1); } } bytes = recv(http->fd, data, length, 0); DEBUG_printf(("6http_gnutls_read: bytes=%d", (int)bytes)); return (bytes); } /* * 'http_gnutls_write()' - Write function for the GNU TLS library. */ static ssize_t /* O - Number of bytes written or -1 on error */ http_gnutls_write( gnutls_transport_ptr_t ptr, /* I - Connection to server */ const void *data, /* I - Data buffer */ size_t length) /* I - Number of bytes to write */ { ssize_t bytes; /* Bytes written */ DEBUG_printf(("6http_gnutls_write(ptr=%p, data=%p, length=%d)", ptr, data, (int)length)); bytes = send(((http_t *)ptr)->fd, data, length, 0); DEBUG_printf(("http_gnutls_write: bytes=%d", (int)bytes)); return (bytes); } /* * '_httpTLSInitialize()' - Initialize the TLS stack. */ void _httpTLSInitialize(void) { /* * Initialize GNU TLS... */ gnutls_global_init(); } /* * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes. */ size_t /* O - Bytes available */ _httpTLSPending(http_t *http) /* I - HTTP connection */ { return (gnutls_record_check_pending(http->tls)); } /* * '_httpTLSRead()' - Read from a SSL/TLS connection. */ int /* O - Bytes read */ _httpTLSRead(http_t *http, /* I - Connection to server */ char *buf, /* I - Buffer to store data */ int len) /* I - Length of buffer */ { ssize_t result; /* Return value */ result = gnutls_record_recv(http->tls, buf, (size_t)len); if (result < 0 && !errno) { /* * Convert GNU TLS error to errno value... */ switch (result) { case GNUTLS_E_INTERRUPTED : errno = EINTR; break; case GNUTLS_E_AGAIN : errno = EAGAIN; break; default : errno = EPIPE; break; } result = -1; } return ((int)result); } /* * '_httpTLSSetCredentials()' - Set the TLS credentials. */ int /* O - Status of connection */ _httpTLSSetCredentials(http_t *http) /* I - Connection to server */ { (void)http; return (0); } /* * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options. */ void _httpTLSSetOptions(int options, /* I - Options */ int min_version, /* I - Minimum TLS version */ int max_version) /* I - Maximum TLS version */ { if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0) { tls_options = options; tls_min_version = min_version; tls_max_version = max_version; } } /* * '_httpTLSStart()' - Set up SSL/TLS support on a connection. */ int /* O - 0 on success, -1 on failure */ _httpTLSStart(http_t *http) /* I - Connection to server */ { char hostname[256], /* Hostname */ *hostptr; /* Pointer into hostname */ int status; /* Status of handshake */ gnutls_certificate_credentials_t *credentials; /* TLS credentials */ char priority_string[2048]; /* Priority string */ int version; /* Current version */ static const char * const versions[] =/* SSL/TLS versions */ { "VERS-SSL3.0", "VERS-TLS1.0", "VERS-TLS1.1", "VERS-TLS1.2", "VERS-TLS1.3", "VERS-TLS-ALL" }; DEBUG_printf(("3_httpTLSStart(http=%p)", http)); if (tls_options < 0) { DEBUG_puts("4_httpTLSStart: Setting defaults."); _cupsSetDefaults(); DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options)); } if (http->mode == _HTTP_MODE_SERVER && !tls_keypath) { DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called."); http->error = errno = EINVAL; http->status = HTTP_STATUS_ERROR; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Server credentials not set."), 1); return (-1); } credentials = (gnutls_certificate_credentials_t *) malloc(sizeof(gnutls_certificate_credentials_t)); if (credentials == NULL) { DEBUG_printf(("8_httpStartTLS: Unable to allocate credentials: %s", strerror(errno))); http->error = errno; http->status = HTTP_STATUS_ERROR; _cupsSetHTTPError(HTTP_STATUS_ERROR); return (-1); } gnutls_certificate_allocate_credentials(credentials); status = gnutls_init(&http->tls, http->mode == _HTTP_MODE_CLIENT ? GNUTLS_CLIENT : GNUTLS_SERVER); if (!status) status = gnutls_set_default_priority(http->tls); if (status) { http->error = EIO; http->status = HTTP_STATUS_ERROR; DEBUG_printf(("4_httpTLSStart: Unable to initialize common TLS parameters: %s", gnutls_strerror(status))); _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0); gnutls_deinit(http->tls); gnutls_certificate_free_credentials(*credentials); free(credentials); http->tls = NULL; return (-1); } if (http->mode == _HTTP_MODE_CLIENT) { /* * Client: get the hostname to use for TLS... */ if (httpAddrLocalhost(http->hostaddr)) { strlcpy(hostname, "localhost", sizeof(hostname)); } else { /* * Otherwise make sure the hostname we have does not end in a trailing dot. */ strlcpy(hostname, http->hostname, sizeof(hostname)); if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && *hostptr == '.') *hostptr = '\0'; } status = gnutls_server_name_set(http->tls, GNUTLS_NAME_DNS, hostname, strlen(hostname)); } else { /* * Server: get certificate and private key... */ char crtfile[1024], /* Certificate file */ keyfile[1024]; /* Private key file */ int have_creds = 0; /* Have credentials? */ if (http->fields[HTTP_FIELD_HOST]) { /* * Use hostname for TLS upgrade... */ strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname)); } else { /* * Resolve hostname from connection address... */ http_addr_t addr; /* Connection address */ socklen_t addrlen; /* Length of address */ addrlen = sizeof(addr); if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen)) { DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno))); hostname[0] = '\0'; } else if (httpAddrLocalhost(&addr)) hostname[0] = '\0'; else { httpAddrLookup(&addr, hostname, sizeof(hostname)); DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname)); } } if (isdigit(hostname[0] & 255) || hostname[0] == '[') hostname[0] = '\0'; /* Don't allow numeric addresses */ if (hostname[0]) { /* * First look in the CUPS keystore... */ http_gnutls_make_path(crtfile, sizeof(crtfile), tls_keypath, hostname, "crt"); http_gnutls_make_path(keyfile, sizeof(keyfile), tls_keypath, hostname, "key"); if (access(crtfile, R_OK) || access(keyfile, R_OK)) { /* * No CUPS-managed certs, look for CA certs... */ char cacrtfile[1024], cakeyfile[1024]; /* CA cert files */ snprintf(cacrtfile, sizeof(cacrtfile), "/etc/letsencrypt/live/%s/fullchain.pem", hostname); snprintf(cakeyfile, sizeof(cakeyfile), "/etc/letsencrypt/live/%s/privkey.pem", hostname); if ((access(cacrtfile, R_OK) || access(cakeyfile, R_OK)) && (hostptr = strchr(hostname, '.')) != NULL) { /* * Try just domain name... */ hostptr ++; if (strchr(hostptr, '.')) { snprintf(cacrtfile, sizeof(cacrtfile), "/etc/letsencrypt/live/%s/fullchain.pem", hostptr); snprintf(cakeyfile, sizeof(cakeyfile), "/etc/letsencrypt/live/%s/privkey.pem", hostptr); } } if (!access(cacrtfile, R_OK) && !access(cakeyfile, R_OK)) { /* * Use the CA certs... */ strlcpy(crtfile, cacrtfile, sizeof(crtfile)); strlcpy(keyfile, cakeyfile, sizeof(keyfile)); } } have_creds = !access(crtfile, R_OK) && !access(keyfile, R_OK); } else if (tls_common_name) { /* * First look in the CUPS keystore... */ http_gnutls_make_path(crtfile, sizeof(crtfile), tls_keypath, tls_common_name, "crt"); http_gnutls_make_path(keyfile, sizeof(keyfile), tls_keypath, tls_common_name, "key"); if (access(crtfile, R_OK) || access(keyfile, R_OK)) { /* * No CUPS-managed certs, look for CA certs... */ char cacrtfile[1024], cakeyfile[1024]; /* CA cert files */ snprintf(cacrtfile, sizeof(cacrtfile), "/etc/letsencrypt/live/%s/fullchain.pem", tls_common_name); snprintf(cakeyfile, sizeof(cakeyfile), "/etc/letsencrypt/live/%s/privkey.pem", tls_common_name); if ((access(cacrtfile, R_OK) || access(cakeyfile, R_OK)) && (hostptr = strchr(tls_common_name, '.')) != NULL) { /* * Try just domain name... */ hostptr ++; if (strchr(hostptr, '.')) { snprintf(cacrtfile, sizeof(cacrtfile), "/etc/letsencrypt/live/%s/fullchain.pem", hostptr); snprintf(cakeyfile, sizeof(cakeyfile), "/etc/letsencrypt/live/%s/privkey.pem", hostptr); } } if (!access(cacrtfile, R_OK) && !access(cakeyfile, R_OK)) { /* * Use the CA certs... */ strlcpy(crtfile, cacrtfile, sizeof(crtfile)); strlcpy(keyfile, cakeyfile, sizeof(keyfile)); } } have_creds = !access(crtfile, R_OK) && !access(keyfile, R_OK); } if (!have_creds && tls_auto_create && (hostname[0] || tls_common_name)) { DEBUG_printf(("4_httpTLSStart: Auto-create credentials for \"%s\".", hostname[0] ? hostname : tls_common_name)); if (!cupsMakeServerCredentials(tls_keypath, hostname[0] ? hostname : tls_common_name, 0, NULL, time(NULL) + 365 * 86400)) { DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed."); http->error = errno = EINVAL; http->status = HTTP_STATUS_ERROR; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1); return (-1); } } DEBUG_printf(("4_httpTLSStart: Using certificate \"%s\" and private key \"%s\".", crtfile, keyfile)); if (!status) status = gnutls_certificate_set_x509_key_file(*credentials, crtfile, keyfile, GNUTLS_X509_FMT_PEM); } if (!status) status = gnutls_credentials_set(http->tls, GNUTLS_CRD_CERTIFICATE, *credentials); if (status) { http->error = EIO; http->status = HTTP_STATUS_ERROR; DEBUG_printf(("4_httpTLSStart: Unable to complete client/server setup: %s", gnutls_strerror(status))); _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0); gnutls_deinit(http->tls); gnutls_certificate_free_credentials(*credentials); free(credentials); http->tls = NULL; return (-1); } strlcpy(priority_string, "NORMAL", sizeof(priority_string)); if (tls_max_version < _HTTP_TLS_MAX) { /* * Require specific TLS versions... */ strlcat(priority_string, ":-VERS-TLS-ALL", sizeof(priority_string)); for (version = tls_min_version; version <= tls_max_version; version ++) { strlcat(priority_string, ":+", sizeof(priority_string)); strlcat(priority_string, versions[version], sizeof(priority_string)); } } else if (tls_min_version == _HTTP_TLS_SSL3) { /* * Allow all versions of TLS and SSL/3.0... */ strlcat(priority_string, ":+VERS-TLS-ALL:+VERS-SSL3.0", sizeof(priority_string)); } else { /* * Require a minimum version... */ strlcat(priority_string, ":+VERS-TLS-ALL", sizeof(priority_string)); for (version = 0; version < tls_min_version; version ++) { strlcat(priority_string, ":-", sizeof(priority_string)); strlcat(priority_string, versions[version], sizeof(priority_string)); } } if (tls_options & _HTTP_TLS_ALLOW_RC4) strlcat(priority_string, ":+ARCFOUR-128", sizeof(priority_string)); else strlcat(priority_string, ":!ARCFOUR-128", sizeof(priority_string)); strlcat(priority_string, ":!ANON-DH", sizeof(priority_string)); if (tls_options & _HTTP_TLS_DENY_CBC) strlcat(priority_string, ":!AES-128-CBC:!AES-256-CBC:!CAMELLIA-128-CBC:!CAMELLIA-256-CBC:!3DES-CBC", sizeof(priority_string)); #ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT gnutls_priority_set_direct(http->tls, priority_string, NULL); #else gnutls_priority_t priority; /* Priority */ gnutls_priority_init(&priority, priority_string, NULL); gnutls_priority_set(http->tls, priority); gnutls_priority_deinit(priority); #endif /* HAVE_GNUTLS_PRIORITY_SET_DIRECT */ gnutls_transport_set_ptr(http->tls, (gnutls_transport_ptr_t)http); gnutls_transport_set_pull_function(http->tls, http_gnutls_read); #ifdef HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION gnutls_transport_set_pull_timeout_function(http->tls, (gnutls_pull_timeout_func)httpWait); #endif /* HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION */ gnutls_transport_set_push_function(http->tls, http_gnutls_write); while ((status = gnutls_handshake(http->tls)) != GNUTLS_E_SUCCESS) { DEBUG_printf(("5_httpStartTLS: gnutls_handshake returned %d (%s)", status, gnutls_strerror(status))); if (gnutls_error_is_fatal(status)) { http->error = EIO; http->status = HTTP_STATUS_ERROR; _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0); gnutls_deinit(http->tls); gnutls_certificate_free_credentials(*credentials); free(credentials); http->tls = NULL; return (-1); } } http->tls_credentials = credentials; return (0); } /* * '_httpTLSStop()' - Shut down SSL/TLS on a connection. */ void _httpTLSStop(http_t *http) /* I - Connection to server */ { int error; /* Error code */ error = gnutls_bye(http->tls, http->mode == _HTTP_MODE_CLIENT ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR); if (error != GNUTLS_E_SUCCESS) _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gnutls_strerror(errno), 0); gnutls_deinit(http->tls); http->tls = NULL; if (http->tls_credentials) { gnutls_certificate_free_credentials(*(http->tls_credentials)); free(http->tls_credentials); http->tls_credentials = NULL; } } /* * '_httpTLSWrite()' - Write to a SSL/TLS connection. */ int /* O - Bytes written */ _httpTLSWrite(http_t *http, /* I - Connection to server */ const char *buf, /* I - Buffer holding data */ int len) /* I - Length of buffer */ { ssize_t result; /* Return value */ DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http, buf, len)); result = gnutls_record_send(http->tls, buf, (size_t)len); if (result < 0 && !errno) { /* * Convert GNU TLS error to errno value... */ switch (result) { case GNUTLS_E_INTERRUPTED : errno = EINTR; break; case GNUTLS_E_AGAIN : errno = EAGAIN; break; default : errno = EPIPE; break; } result = -1; } DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result)); return ((int)result); } ippsample/cups/error.c0000644000175000017500000001141513240604116014010 0ustar tilltill/* * Raster error handling for CUPS. * * Copyright 2007-2015 by Apple Inc. * Copyright 2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include /* * Local structures... */ typedef struct _cups_raster_error_s /**** Error buffer structure ****/ { char *start, /* Start of buffer */ *current, /* Current position in buffer */ *end; /* End of buffer */ } _cups_raster_error_t; /* * Local functions... */ static _cups_raster_error_t *get_error_buffer(void); /* * '_cupsRasterAddError()' - Add an error message to the error buffer. */ void _cupsRasterAddError(const char *f, /* I - Printf-style error message */ ...) /* I - Additional arguments as needed */ { _cups_raster_error_t *buf = get_error_buffer(); /* Error buffer */ va_list ap; /* Pointer to additional arguments */ char s[2048]; /* Message string */ ssize_t bytes; /* Bytes in message string */ DEBUG_printf(("_cupsRasterAddError(f=\"%s\", ...)", f)); va_start(ap, f); bytes = vsnprintf(s, sizeof(s), f, ap); va_end(ap); if (bytes <= 0) return; DEBUG_printf(("1_cupsRasterAddError: %s", s)); bytes ++; if ((size_t)bytes >= sizeof(s)) return; if (bytes > (ssize_t)(buf->end - buf->current)) { /* * Allocate more memory... */ char *temp; /* New buffer */ size_t size; /* Size of buffer */ size = (size_t)(buf->end - buf->start + 2 * bytes + 1024); if (buf->start) temp = realloc(buf->start, size); else temp = malloc(size); if (!temp) return; /* * Update pointers... */ buf->end = temp + size; buf->current = temp + (buf->current - buf->start); buf->start = temp; } /* * Append the message to the end of the current string... */ memcpy(buf->current, s, (size_t)bytes); buf->current += bytes - 1; } /* * '_cupsRasterClearError()' - Clear the error buffer. */ void _cupsRasterClearError(void) { _cups_raster_error_t *buf = get_error_buffer(); /* Error buffer */ buf->current = buf->start; if (buf->start) *(buf->start) = '\0'; } /* * 'cupsRasterErrorString()' - Return the last error from a raster function. * * If there are no recent errors, NULL is returned. * * @since CUPS 1.3/macOS 10.5@ */ const char * /* O - Last error */ cupsRasterErrorString(void) { _cups_raster_error_t *buf = get_error_buffer(); /* Error buffer */ if (buf->current == buf->start) return (NULL); else return (buf->start); } #ifdef HAVE_PTHREAD_H /* * Implement per-thread globals... */ # include /* * Local globals... */ static pthread_key_t raster_key = 0; /* Thread local storage key */ static pthread_once_t raster_key_once = PTHREAD_ONCE_INIT; /* One-time initialization object */ /* * Local functions... */ static void raster_init(void); static void raster_destructor(void *value); /* * 'get_error_buffer()' - Return a pointer to thread local storage. */ _cups_raster_error_t * /* O - Pointer to error buffer */ get_error_buffer(void) { _cups_raster_error_t *buf; /* Pointer to error buffer */ /* * Initialize the global data exactly once... */ DEBUG_puts("3get_error_buffer()"); pthread_once(&raster_key_once, raster_init); /* * See if we have allocated the data yet... */ if ((buf = (_cups_raster_error_t *)pthread_getspecific(raster_key)) == NULL) { DEBUG_puts("4get_error_buffer: allocating memory for thread."); /* * No, allocate memory as set the pointer for the key... */ buf = calloc(1, sizeof(_cups_raster_error_t)); pthread_setspecific(raster_key, buf); DEBUG_printf(("4get_error_buffer: buf=%p", (void *)buf)); } /* * Return the pointer to the data... */ return (buf); } /* * 'raster_init()' - Initialize error buffer once. */ static void raster_init(void) { pthread_key_create(&raster_key, raster_destructor); DEBUG_printf(("3raster_init(): raster_key=%x(%u)", (unsigned)raster_key, (unsigned)raster_key)); } /* * 'raster_destructor()' - Free memory allocated by get_error_buffer(). */ static void raster_destructor(void *value) /* I - Data to free */ { _cups_raster_error_t *buf = (_cups_raster_error_t *)value; /* Error buffer */ DEBUG_printf(("3raster_destructor(value=%p)", value)); if (buf->start) free(buf->start); free(value); } #else /* * Implement static globals... */ /* * 'get_error_buffer()' - Return a pointer to thread local storage. */ _cups_raster_error_t * /* O - Pointer to error buffer */ get_error_buffer(void) { static _cups_raster_error_t buf = { 0, 0, 0 }; /* Error buffer */ return (&buf); } #endif /* HAVE_PTHREAD_H */ ippsample/cups/http.h0000644000175000017500000007274213240604116013655 0ustar tilltill/* * Hyper-Text Transport Protocol definitions for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_HTTP_H_ # define _CUPS_HTTP_H_ /* * Include necessary headers... */ # include "versioning.h" # include "array.h" # include # include # include # ifdef WIN32 # ifndef __CUPS_SSIZE_T_DEFINED # define __CUPS_SSIZE_T_DEFINED /* Windows does not support the ssize_t type, so map it to off_t... */ typedef off_t ssize_t; /* @private@ */ # endif /* !__CUPS_SSIZE_T_DEFINED */ # include # include # else # include # include # include # include # include # include # include # include # if !defined(__APPLE__) || !defined(TCP_NODELAY) # include # endif /* !__APPLE__ || !TCP_NODELAY */ # if defined(AF_UNIX) && !defined(AF_LOCAL) # define AF_LOCAL AF_UNIX /* Older UNIX's have old names... */ # endif /* AF_UNIX && !AF_LOCAL */ # ifdef AF_LOCAL # include # endif /* AF_LOCAL */ # if defined(LOCAL_PEERCRED) && !defined(SO_PEERCRED) # define SO_PEERCRED LOCAL_PEERCRED # endif /* LOCAL_PEERCRED && !SO_PEERCRED */ # endif /* WIN32 */ /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Oh, the wonderful world of IPv6 compatibility. Apparently some * implementations expose the (more logical) 32-bit address parts * to everyone, while others only expose it to kernel code... To * make supporting IPv6 even easier, each vendor chose different * core structure and union names, so the same defines or code * can't be used on all platforms. * * The following will likely need tweaking on new platforms that * support IPv6 - the "s6_addr32" define maps to the 32-bit integer * array in the in6_addr union, which is named differently on various * platforms. */ #if defined(AF_INET6) && !defined(s6_addr32) # if defined(__sun) # define s6_addr32 _S6_un._S6_u32 # elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)|| defined(__DragonFly__) # define s6_addr32 __u6_addr.__u6_addr32 # elif defined(WIN32) /* * Windows only defines byte and 16-bit word members of the union and * requires special casing of all raw address code... */ # define s6_addr32 error_need_win32_specific_code # endif /* __sun */ #endif /* AF_INET6 && !s6_addr32 */ /* * Limits... */ # define HTTP_MAX_URI 1024 /* Max length of URI string */ # define HTTP_MAX_HOST 256 /* Max length of hostname string */ # define HTTP_MAX_BUFFER 2048 /* Max length of data buffer */ # define HTTP_MAX_VALUE 256 /* Max header field value length */ /* * Types and structures... */ typedef enum http_auth_e /**** HTTP authentication types @exclude all@ ****/ { HTTP_AUTH_NONE, /* No authentication in use */ HTTP_AUTH_BASIC, /* Basic authentication in use */ HTTP_AUTH_MD5, /* Digest authentication in use */ HTTP_AUTH_MD5_SESS, /* MD5-session authentication in use */ HTTP_AUTH_MD5_INT, /* Digest authentication in use for body */ HTTP_AUTH_MD5_SESS_INT, /* MD5-session authentication in use for body */ HTTP_AUTH_NEGOTIATE /* GSSAPI authentication in use @since CUPS 1.3/macOS 10.5@ */ } http_auth_t; typedef enum http_encoding_e /**** HTTP transfer encoding values ****/ { HTTP_ENCODING_LENGTH, /* Data is sent with Content-Length */ HTTP_ENCODING_CHUNKED, /* Data is chunked */ HTTP_ENCODING_FIELDS /* Sending HTTP fields */ # ifndef _CUPS_NO_DEPRECATED # define HTTP_ENCODE_LENGTH HTTP_ENCODING_LENGTH # define HTTP_ENCODE_CHUNKED HTTP_ENCODING_CHUNKED # define HTTP_ENCODE_FIELDS HTTP_ENCODING_FIELDS # endif /* !_CUPS_NO_DEPRECATED */ } http_encoding_t; typedef enum http_encryption_e /**** HTTP encryption values ****/ { HTTP_ENCRYPTION_IF_REQUESTED, /* Encrypt if requested (TLS upgrade) */ HTTP_ENCRYPTION_NEVER, /* Never encrypt */ HTTP_ENCRYPTION_REQUIRED, /* Encryption is required (TLS upgrade) */ HTTP_ENCRYPTION_ALWAYS /* Always encrypt (SSL) */ # ifndef _CUPS_NO_DEPRECATED # define HTTP_ENCRYPT_IF_REQUESTED HTTP_ENCRYPTION_IF_REQUESTED # define HTTP_ENCRYPT_NEVER HTTP_ENCRYPTION_NEVER # define HTTP_ENCRYPT_REQUIRED HTTP_ENCRYPTION_REQUIRED # define HTTP_ENCRYPT_ALWAYS HTTP_ENCRYPTION_ALWAYS # endif /* !_CUPS_NO_DEPRECATED */ } http_encryption_t; typedef enum http_field_e /**** HTTP field names ****/ { HTTP_FIELD_UNKNOWN = -1, /* Unknown field */ HTTP_FIELD_ACCEPT_LANGUAGE, /* Accept-Language field */ HTTP_FIELD_ACCEPT_RANGES, /* Accept-Ranges field */ HTTP_FIELD_AUTHORIZATION, /* Authorization field */ HTTP_FIELD_CONNECTION, /* Connection field */ HTTP_FIELD_CONTENT_ENCODING, /* Content-Encoding field */ HTTP_FIELD_CONTENT_LANGUAGE, /* Content-Language field */ HTTP_FIELD_CONTENT_LENGTH, /* Content-Length field */ HTTP_FIELD_CONTENT_LOCATION, /* Content-Location field */ HTTP_FIELD_CONTENT_MD5, /* Content-MD5 field */ HTTP_FIELD_CONTENT_RANGE, /* Content-Range field */ HTTP_FIELD_CONTENT_TYPE, /* Content-Type field */ HTTP_FIELD_CONTENT_VERSION, /* Content-Version field */ HTTP_FIELD_DATE, /* Date field */ HTTP_FIELD_HOST, /* Host field */ HTTP_FIELD_IF_MODIFIED_SINCE, /* If-Modified-Since field */ HTTP_FIELD_IF_UNMODIFIED_SINCE, /* If-Unmodified-Since field */ HTTP_FIELD_KEEP_ALIVE, /* Keep-Alive field */ HTTP_FIELD_LAST_MODIFIED, /* Last-Modified field */ HTTP_FIELD_LINK, /* Link field */ HTTP_FIELD_LOCATION, /* Location field */ HTTP_FIELD_RANGE, /* Range field */ HTTP_FIELD_REFERER, /* Referer field */ HTTP_FIELD_RETRY_AFTER, /* Retry-After field */ HTTP_FIELD_TRANSFER_ENCODING, /* Transfer-Encoding field */ HTTP_FIELD_UPGRADE, /* Upgrade field */ HTTP_FIELD_USER_AGENT, /* User-Agent field */ HTTP_FIELD_WWW_AUTHENTICATE, /* WWW-Authenticate field */ HTTP_FIELD_ACCEPT_ENCODING, /* Accepting-Encoding field @since CUPS 1.7/macOS 10.9@ */ HTTP_FIELD_ALLOW, /* Allow field @since CUPS 1.7/macOS 10.9@ */ HTTP_FIELD_SERVER, /* Server field @since CUPS 1.7/macOS 10.9@ */ HTTP_FIELD_MAX /* Maximum field index */ } http_field_t; typedef enum http_keepalive_e /**** HTTP keep-alive values ****/ { HTTP_KEEPALIVE_OFF = 0, /* No keep alive support */ HTTP_KEEPALIVE_ON /* Use keep alive */ } http_keepalive_t; typedef enum http_state_e /**** HTTP state values; states **** are server-oriented... ****/ { HTTP_STATE_ERROR = -1, /* Error on socket */ HTTP_STATE_WAITING, /* Waiting for command */ HTTP_STATE_OPTIONS, /* OPTIONS command, waiting for blank line */ HTTP_STATE_GET, /* GET command, waiting for blank line */ HTTP_STATE_GET_SEND, /* GET command, sending data */ HTTP_STATE_HEAD, /* HEAD command, waiting for blank line */ HTTP_STATE_POST, /* POST command, waiting for blank line */ HTTP_STATE_POST_RECV, /* POST command, receiving data */ HTTP_STATE_POST_SEND, /* POST command, sending data */ HTTP_STATE_PUT, /* PUT command, waiting for blank line */ HTTP_STATE_PUT_RECV, /* PUT command, receiving data */ HTTP_STATE_DELETE, /* DELETE command, waiting for blank line */ HTTP_STATE_TRACE, /* TRACE command, waiting for blank line */ HTTP_STATE_CONNECT, /* CONNECT command, waiting for blank line */ HTTP_STATE_STATUS, /* Command complete, sending status */ HTTP_STATE_UNKNOWN_METHOD, /* Unknown request method, waiting for blank line @since CUPS 1.7/macOS 10.9@ */ HTTP_STATE_UNKNOWN_VERSION /* Unknown request method, waiting for blank line @since CUPS 1.7/macOS 10.9@ */ # ifndef _CUPS_NO_DEPRECATED # define HTTP_WAITING HTTP_STATE_WAITING # define HTTP_OPTIONS HTTP_STATE_OPTIONS # define HTTP_GET HTTP_STATE_GET # define HTTP_GET_SEND HTTP_STATE_GET_SEND # define HTTP_HEAD HTTP_STATE_HEAD # define HTTP_POST HTTP_STATE_POST # define HTTP_POST_RECV HTTP_STATE_POST_RECV # define HTTP_POST_SEND HTTP_STATE_POST_SEND # define HTTP_PUT HTTP_STATE_PUT # define HTTP_PUT_RECV HTTP_STATE_PUT_RECV # define HTTP_DELETE HTTP_STATE_DELETE # define HTTP_TRACE HTTP_STATE_TRACE # define HTTP_CLOSE HTTP_STATE_CONNECT # define HTTP_STATUS HTTP_STATE_STATUS # endif /* !_CUPS_NO_DEPRECATED */ } http_state_t; typedef enum http_status_e /**** HTTP status codes ****/ { HTTP_STATUS_ERROR = -1, /* An error response from httpXxxx() */ HTTP_STATUS_NONE = 0, /* No Expect value @since CUPS 1.7/macOS 10.9@ */ HTTP_STATUS_CONTINUE = 100, /* Everything OK, keep going... */ HTTP_STATUS_SWITCHING_PROTOCOLS, /* HTTP upgrade to TLS/SSL */ HTTP_STATUS_OK = 200, /* OPTIONS/GET/HEAD/POST/TRACE command was successful */ HTTP_STATUS_CREATED, /* PUT command was successful */ HTTP_STATUS_ACCEPTED, /* DELETE command was successful */ HTTP_STATUS_NOT_AUTHORITATIVE, /* Information isn't authoritative */ HTTP_STATUS_NO_CONTENT, /* Successful command, no new data */ HTTP_STATUS_RESET_CONTENT, /* Content was reset/recreated */ HTTP_STATUS_PARTIAL_CONTENT, /* Only a partial file was received/sent */ HTTP_STATUS_MULTIPLE_CHOICES = 300, /* Multiple files match request */ HTTP_STATUS_MOVED_PERMANENTLY, /* Document has moved permanently */ HTTP_STATUS_FOUND, /* Document was found at a different URI */ HTTP_STATUS_SEE_OTHER, /* See this other link */ HTTP_STATUS_NOT_MODIFIED, /* File not modified */ HTTP_STATUS_USE_PROXY, /* Must use a proxy to access this URI */ HTTP_STATUS_TEMPORARY_REDIRECT = 307, /* Temporary redirection */ HTTP_STATUS_BAD_REQUEST = 400, /* Bad request */ HTTP_STATUS_UNAUTHORIZED, /* Unauthorized to access host */ HTTP_STATUS_PAYMENT_REQUIRED, /* Payment required */ HTTP_STATUS_FORBIDDEN, /* Forbidden to access this URI */ HTTP_STATUS_NOT_FOUND, /* URI was not found */ HTTP_STATUS_METHOD_NOT_ALLOWED, /* Method is not allowed */ HTTP_STATUS_NOT_ACCEPTABLE, /* Not Acceptable */ HTTP_STATUS_PROXY_AUTHENTICATION, /* Proxy Authentication is Required */ HTTP_STATUS_REQUEST_TIMEOUT, /* Request timed out */ HTTP_STATUS_CONFLICT, /* Request is self-conflicting */ HTTP_STATUS_GONE, /* Server has gone away */ HTTP_STATUS_LENGTH_REQUIRED, /* A content length or encoding is required */ HTTP_STATUS_PRECONDITION, /* Precondition failed */ HTTP_STATUS_REQUEST_TOO_LARGE, /* Request entity too large */ HTTP_STATUS_URI_TOO_LONG, /* URI too long */ HTTP_STATUS_UNSUPPORTED_MEDIATYPE, /* The requested media type is unsupported */ HTTP_STATUS_REQUESTED_RANGE, /* The requested range is not satisfiable */ HTTP_STATUS_EXPECTATION_FAILED, /* The expectation given in an Expect header field was not met */ HTTP_STATUS_UPGRADE_REQUIRED = 426, /* Upgrade to SSL/TLS required */ HTTP_STATUS_SERVER_ERROR = 500, /* Internal server error */ HTTP_STATUS_NOT_IMPLEMENTED, /* Feature not implemented */ HTTP_STATUS_BAD_GATEWAY, /* Bad gateway */ HTTP_STATUS_SERVICE_UNAVAILABLE, /* Service is unavailable */ HTTP_STATUS_GATEWAY_TIMEOUT, /* Gateway connection timed out */ HTTP_STATUS_NOT_SUPPORTED, /* HTTP version not supported */ HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED = 1000, /* User canceled authorization @since CUPS 1.4@ */ HTTP_STATUS_CUPS_PKI_ERROR, /* Error negotiating a secure connection @since CUPS 1.5/macOS 10.7@ */ HTTP_STATUS_CUPS_WEBIF_DISABLED /* Web interface is disabled @private@ */ # define HTTP_STATUS_MOVED_TEMPORARILY HTTP_STATUS_FOUND /* Renamed in RFC 7231 */ # ifndef _CUPS_NO_DEPRECATED /* Old names for this enumeration */ # define HTTP_ERROR HTTP_STATUS_ERROR # define HTTP_CONTINUE HTTP_STATUS_CONTINUE # define HTTP_SWITCHING_PROTOCOLS HTTP_STATUS_SWITCHING_PROTOCOLS # define HTTP_OK HTTP_STATUS_OK # define HTTP_CREATED HTTP_STATUS_CREATED # define HTTP_ACCEPTED HTTP_STATUS_ACCEPTED # define HTTP_NOT_AUTHORITATIVE HTTP_STATUS_NOT_AUTHORITATIVE # define HTTP_NO_CONTENT HTTP_STATUS_NO_CONTENT # define HTTP_RESET_CONTENT HTTP_STATUS_RESET_CONTENT # define HTTP_PARTIAL_CONTENT HTTP_STATUS_PARTIAL_CONTENT # define HTTP_MULTIPLE_CHOICES HTTP_STATUS_MULTIPLE_CHOICES # define HTTP_MOVED_PERMANENTLY HTTP_STATUS_MOVED_PERMANENTLY # define HTTP_MOVED_TEMPORARILY HTTP_STATUS_MOVED_TEMPORARILY # define HTTP_SEE_OTHER HTTP_STATUS_SEE_OTHER # define HTTP_NOT_MODIFIED HTTP_STATUS_NOT_MODIFIED # define HTTP_USE_PROXY HTTP_STATUS_USE_PROXY # define HTTP_BAD_REQUEST HTTP_STATUS_BAD_REQUEST # define HTTP_UNAUTHORIZED HTTP_STATUS_UNAUTHORIZED # define HTTP_PAYMENT_REQUIRED HTTP_STATUS_PAYMENT_REQUIRED # define HTTP_FORBIDDEN HTTP_STATUS_FORBIDDEN # define HTTP_NOT_FOUND HTTP_STATUS_NOT_FOUND # define HTTP_METHOD_NOT_ALLOWED HTTP_STATUS_METHOD_NOT_ALLOWED # define HTTP_NOT_ACCEPTABLE HTTP_STATUS_NOT_ACCEPTABLE # define HTTP_PROXY_AUTHENTICATION HTTP_STATUS_PROXY_AUTHENTICATION # define HTTP_REQUEST_TIMEOUT HTTP_STATUS_REQUEST_TIMEOUT # define HTTP_CONFLICT HTTP_STATUS_CONFLICT # define HTTP_GONE HTTP_STATUS_GONE # define HTTP_LENGTH_REQUIRED HTTP_STATUS_LENGTH_REQUIRED # define HTTP_PRECONDITION HTTP_STATUS_PRECONDITION # define HTTP_REQUEST_TOO_LARGE HTTP_STATUS_REQUEST_TOO_LARGE # define HTTP_URI_TOO_LONG HTTP_STATUS_URI_TOO_LONG # define HTTP_UNSUPPORTED_MEDIATYPE HTTP_STATUS_UNSUPPORTED_MEDIATYPE # define HTTP_REQUESTED_RANGE HTTP_STATUS_REQUESTED_RANGE # define HTTP_EXPECTATION_FAILED HTTP_STATUS_EXPECTATION_FAILED # define HTTP_UPGRADE_REQUIRED HTTP_STATUS_UPGRADE_REQUIRED # define HTTP_SERVER_ERROR HTTP_STATUS_SERVER_ERROR # define HTTP_NOT_IMPLEMENTED HTTP_STATUS_NOT_IMPLEMENTED # define HTTP_BAD_GATEWAY HTTP_STATUS_BAD_GATEWAY # define HTTP_SERVICE_UNAVAILABLE HTTP_STATUS_SERVICE_UNAVAILABLE # define HTTP_GATEWAY_TIMEOUT HTTP_STATUS_GATEWAY_TIMEOUT # define HTTP_NOT_SUPPORTED HTTP_STATUS_NOT_SUPPORTED # define HTTP_AUTHORIZATION_CANCELED HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED # define HTTP_PKI_ERROR HTTP_STATUS_CUPS_PKI_ERROR # define HTTP_WEBIF_DISABLED HTTP_STATUS_CUPS_WEBIF_DISABLED # endif /* !_CUPS_NO_DEPRECATED */ } http_status_t; typedef enum http_trust_e /**** Level of trust for credentials @since CUPS 2.0/OS 10.10@ */ { HTTP_TRUST_OK = 0, /* Credentials are OK/trusted */ HTTP_TRUST_INVALID, /* Credentials are invalid */ HTTP_TRUST_CHANGED, /* Credentials have changed */ HTTP_TRUST_EXPIRED, /* Credentials are expired */ HTTP_TRUST_RENEWED, /* Credentials have been renewed */ HTTP_TRUST_UNKNOWN, /* Credentials are unknown/new */ } http_trust_t; typedef enum http_uri_status_e /**** URI separation status @since CUPS 1.2@ ****/ { HTTP_URI_STATUS_OVERFLOW = -8, /* URI buffer for httpAssembleURI is too small */ HTTP_URI_STATUS_BAD_ARGUMENTS = -7, /* Bad arguments to function (error) */ HTTP_URI_STATUS_BAD_RESOURCE = -6, /* Bad resource in URI (error) */ HTTP_URI_STATUS_BAD_PORT = -5, /* Bad port number in URI (error) */ HTTP_URI_STATUS_BAD_HOSTNAME = -4, /* Bad hostname in URI (error) */ HTTP_URI_STATUS_BAD_USERNAME = -3, /* Bad username in URI (error) */ HTTP_URI_STATUS_BAD_SCHEME = -2, /* Bad scheme in URI (error) */ HTTP_URI_STATUS_BAD_URI = -1, /* Bad/empty URI (error) */ HTTP_URI_STATUS_OK = 0, /* URI decoded OK */ HTTP_URI_STATUS_MISSING_SCHEME, /* Missing scheme in URI (warning) */ HTTP_URI_STATUS_UNKNOWN_SCHEME, /* Unknown scheme in URI (warning) */ HTTP_URI_STATUS_MISSING_RESOURCE /* Missing resource in URI (warning) */ # ifndef _CUPS_NO_DEPRECATED # define HTTP_URI_OVERFLOW HTTP_URI_STATUS_OVERFLOW # define HTTP_URI_BAD_ARGUMENTS HTTP_URI_STATUS_BAD_ARGUMENTS # define HTTP_URI_BAD_RESOURCE HTTP_URI_STATUS_BAD_RESOURCE # define HTTP_URI_BAD_PORT HTTP_URI_STATUS_BAD_PORT # define HTTP_URI_BAD_HOSTNAME HTTP_URI_STATUS_BAD_HOSTNAME # define HTTP_URI_BAD_USERNAME HTTP_URI_STATUS_BAD_USERNAME # define HTTP_URI_BAD_SCHEME HTTP_URI_STATUS_BAD_SCHEME # define HTTP_URI_BAD_URI HTTP_URI_STATUS_BAD_URI # define HTTP_URI_OK HTTP_URI_STATUS_OK # define HTTP_URI_MISSING_SCHEME HTTP_URI_STATUS_MISSING_SCHEME # define HTTP_URI_UNKNOWN_SCHEME HTTP_URI_STATUS_UNKNOWN_SCHEME # define HTTP_URI_MISSING_RESOURCE HTTP_URI_STATUS_MISSING_RESOURCE # endif /* !_CUPS_NO_DEPRECATED */ } http_uri_status_t; typedef enum http_uri_coding_e /**** URI en/decode flags ****/ { HTTP_URI_CODING_NONE = 0, /* Don't en/decode anything */ HTTP_URI_CODING_USERNAME = 1, /* En/decode the username portion */ HTTP_URI_CODING_HOSTNAME = 2, /* En/decode the hostname portion */ HTTP_URI_CODING_RESOURCE = 4, /* En/decode the resource portion */ HTTP_URI_CODING_MOST = 7, /* En/decode all but the query */ HTTP_URI_CODING_QUERY = 8, /* En/decode the query portion */ HTTP_URI_CODING_ALL = 15, /* En/decode everything */ HTTP_URI_CODING_RFC6874 = 16 /* Use RFC 6874 address format */ } http_uri_coding_t; typedef enum http_version_e /**** HTTP version numbers @exclude all@ ****/ { HTTP_VERSION_0_9 = 9, /* HTTP/0.9 */ HTTP_VERSION_1_0 = 100, /* HTTP/1.0 */ HTTP_VERSION_1_1 = 101 /* HTTP/1.1 */ # ifndef _CUPS_NO_DEPRECATED # define HTTP_0_9 HTTP_VERSION_0_9 # define HTTP_1_0 HTTP_VERSION_1_0 # define HTTP_1_1 HTTP_VERSION_1_1 # endif /* !_CUPS_NO_DEPRECATED */ } http_version_t; typedef union _http_addr_u /**** Socket address union, which **** makes using IPv6 and other **** address types easier and **** more portable. @since CUPS 1.2/macOS 10.5@ ****/ { struct sockaddr addr; /* Base structure for family value */ struct sockaddr_in ipv4; /* IPv4 address */ #ifdef AF_INET6 struct sockaddr_in6 ipv6; /* IPv6 address */ #endif /* AF_INET6 */ #ifdef AF_LOCAL struct sockaddr_un un; /* Domain socket file */ #endif /* AF_LOCAL */ char pad[256]; /* Padding to ensure binary compatibility */ } http_addr_t; typedef struct http_addrlist_s /**** Socket address list, which is **** used to enumerate all of the **** addresses that are associated **** with a hostname. @since CUPS 1.2/macOS 10.5@ **** @exclude all@ ****/ { struct http_addrlist_s *next; /* Pointer to next address in list */ http_addr_t addr; /* Address */ } http_addrlist_t; typedef struct _http_s http_t; /**** HTTP connection type ****/ typedef struct http_credential_s /**** HTTP credential data @since CUPS 1.5/macOS 10.7@ @exclude all@ ****/ { void *data; /* Pointer to credential data */ size_t datalen; /* Credential length */ } http_credential_t; typedef int (*http_timeout_cb_t)(http_t *http, void *user_data); /**** HTTP timeout callback @since CUPS 1.5/macOS 10.7@ ****/ /* * Prototypes... */ extern void httpBlocking(http_t *http, int b); extern int httpCheck(http_t *http); extern void httpClearFields(http_t *http); extern void httpClose(http_t *http); extern http_t *httpConnect(const char *host, int port) _CUPS_DEPRECATED_1_7_MSG("Use httpConnect2 instead."); extern http_t *httpConnectEncrypt(const char *host, int port, http_encryption_t encryption) _CUPS_DEPRECATED_1_7_MSG("Use httpConnect2 instead."); extern int httpDelete(http_t *http, const char *uri); extern int httpEncryption(http_t *http, http_encryption_t e); extern int httpError(http_t *http); extern void httpFlush(http_t *http); extern int httpGet(http_t *http, const char *uri); extern char *httpGets(char *line, int length, http_t *http); extern const char *httpGetDateString(time_t t); extern time_t httpGetDateTime(const char *s); extern const char *httpGetField(http_t *http, http_field_t field); extern struct hostent *httpGetHostByName(const char *name); extern char *httpGetSubField(http_t *http, http_field_t field, const char *name, char *value); extern int httpHead(http_t *http, const char *uri); extern void httpInitialize(void); extern int httpOptions(http_t *http, const char *uri); extern int httpPost(http_t *http, const char *uri); extern int httpPrintf(http_t *http, const char *format, ...) __attribute__ ((__format__ (__printf__, 2, 3))); extern int httpPut(http_t *http, const char *uri); extern int httpRead(http_t *http, char *buffer, int length) _CUPS_DEPRECATED_MSG("Use httpRead2 instead."); extern int httpReconnect(http_t *http) _CUPS_DEPRECATED_1_6_MSG("Use httpReconnect2 instead."); extern void httpSeparate(const char *uri, char *method, char *username, char *host, int *port, char *resource) _CUPS_DEPRECATED_MSG("Use httpSeparateURI instead."); extern void httpSetField(http_t *http, http_field_t field, const char *value); extern const char *httpStatus(http_status_t status); extern int httpTrace(http_t *http, const char *uri); extern http_status_t httpUpdate(http_t *http); extern int httpWrite(http_t *http, const char *buffer, int length) _CUPS_DEPRECATED_MSG("Use httpWrite2 instead."); extern char *httpEncode64(char *out, const char *in) _CUPS_DEPRECATED_MSG("Use httpEncode64_2 instead."); extern char *httpDecode64(char *out, const char *in) _CUPS_DEPRECATED_MSG("Use httpDecode64_2 instead."); extern int httpGetLength(http_t *http) _CUPS_DEPRECATED_MSG("Use httpGetLength2 instead."); extern char *httpMD5(const char *, const char *, const char *, char [33]) _CUPS_DEPRECATED_MSG("Use cupsDoAuth or cupsHashData instead."); extern char *httpMD5Final(const char *, const char *, const char *, char [33]) _CUPS_DEPRECATED_MSG("Use cupsDoAuth or cupsHashData instead."); extern char *httpMD5String(const unsigned char *, char [33]) _CUPS_DEPRECATED_MSG("Use cupsHashString instead."); /**** New in CUPS 1.1.19 ****/ extern void httpClearCookie(http_t *http) _CUPS_API_1_1_19; extern const char *httpGetCookie(http_t *http) _CUPS_API_1_1_19; extern void httpSetCookie(http_t *http, const char *cookie) _CUPS_API_1_1_19; extern int httpWait(http_t *http, int msec) _CUPS_API_1_1_19; /**** New in CUPS 1.1.21 ****/ extern char *httpDecode64_2(char *out, int *outlen, const char *in) _CUPS_API_1_1_21; extern char *httpEncode64_2(char *out, int outlen, const char *in, int inlen) _CUPS_API_1_1_21; extern void httpSeparate2(const char *uri, char *method, int methodlen, char *username, int usernamelen, char *host, int hostlen, int *port, char *resource, int resourcelen) _CUPS_DEPRECATED_MSG("Use httpSeparateURI instead."); /**** New in CUPS 1.2/macOS 10.5 ****/ extern int httpAddrAny(const http_addr_t *addr) _CUPS_API_1_2; extern http_addrlist_t *httpAddrConnect(http_addrlist_t *addrlist, int *sock) _CUPS_API_1_2; extern int httpAddrEqual(const http_addr_t *addr1, const http_addr_t *addr2) _CUPS_API_1_2; extern void httpAddrFreeList(http_addrlist_t *addrlist) _CUPS_API_1_2; extern http_addrlist_t *httpAddrGetList(const char *hostname, int family, const char *service) _CUPS_API_1_2; extern int httpAddrLength(const http_addr_t *addr) _CUPS_API_1_2; extern int httpAddrLocalhost(const http_addr_t *addr) _CUPS_API_1_2; extern char *httpAddrLookup(const http_addr_t *addr, char *name, int namelen) _CUPS_API_1_2; extern char *httpAddrString(const http_addr_t *addr, char *s, int slen) _CUPS_API_1_2; extern http_uri_status_t httpAssembleURI(http_uri_coding_t encoding, char *uri, int urilen, const char *scheme, const char *username, const char *host, int port, const char *resource) _CUPS_API_1_2; extern http_uri_status_t httpAssembleURIf(http_uri_coding_t encoding, char *uri, int urilen, const char *scheme, const char *username, const char *host, int port, const char *resourcef, ...) _CUPS_API_1_2; extern int httpFlushWrite(http_t *http) _CUPS_API_1_2; extern int httpGetBlocking(http_t *http) _CUPS_API_1_2; extern const char *httpGetDateString2(time_t t, char *s, int slen) _CUPS_API_1_2; extern int httpGetFd(http_t *http) _CUPS_API_1_2; extern const char *httpGetHostname(http_t *http, char *s, int slen) _CUPS_API_1_2; extern off_t httpGetLength2(http_t *http) _CUPS_API_1_2; extern http_status_t httpGetStatus(http_t *http) _CUPS_API_1_2; extern char *httpGetSubField2(http_t *http, http_field_t field, const char *name, char *value, int valuelen) _CUPS_API_1_2; extern ssize_t httpRead2(http_t *http, char *buffer, size_t length) _CUPS_API_1_2; extern http_uri_status_t httpSeparateURI(http_uri_coding_t decoding, const char *uri, char *scheme, int schemelen, char *username, int usernamelen, char *host, int hostlen, int *port, char *resource, int resourcelen) _CUPS_API_1_2; extern void httpSetExpect(http_t *http, http_status_t expect) _CUPS_API_1_2; extern void httpSetLength(http_t *http, size_t length) _CUPS_API_1_2; extern ssize_t httpWrite2(http_t *http, const char *buffer, size_t length) _CUPS_API_1_2; /**** New in CUPS 1.3/macOS 10.5 ****/ extern char *httpGetAuthString(http_t *http) _CUPS_API_1_3; extern void httpSetAuthString(http_t *http, const char *scheme, const char *data) _CUPS_API_1_3; /**** New in CUPS 1.5/macOS 10.7 ****/ extern int httpAddCredential(cups_array_t *credentials, const void *data, size_t datalen) _CUPS_API_1_5; extern int httpCopyCredentials(http_t *http, cups_array_t **credentials) _CUPS_API_1_5; extern void httpFreeCredentials(cups_array_t *certs) _CUPS_API_1_5; extern int httpSetCredentials(http_t *http, cups_array_t *certs) _CUPS_API_1_5; extern void httpSetTimeout(http_t *http, double timeout, http_timeout_cb_t cb, void *user_data) _CUPS_API_1_5; /**** New in CUPS 1.6/macOS 10.8 ****/ extern http_addrlist_t *httpAddrConnect2(http_addrlist_t *addrlist, int *sock, int msec, int *cancel) _CUPS_API_1_6; extern http_state_t httpGetState(http_t *http) _CUPS_API_1_6; extern http_version_t httpGetVersion(http_t *http) _CUPS_API_1_6; extern int httpReconnect2(http_t *http, int msec, int *cancel) _CUPS_API_1_6; /**** New in CUPS 1.7/macOS 10.9 ****/ extern http_t *httpAcceptConnection(int fd, int blocking) _CUPS_API_1_7; extern http_addrlist_t *httpAddrCopyList(http_addrlist_t *src) _CUPS_API_1_7; extern int httpAddrListen(http_addr_t *addr, int port) _CUPS_API_1_7; extern int httpAddrPort(http_addr_t *addr) _CUPS_API_1_7; extern char *httpAssembleUUID(const char *server, int port, const char *name, int number, char *buffer, size_t bufsize) _CUPS_API_1_7; extern http_t *httpConnect2(const char *host, int port, http_addrlist_t *addrlist, int family, http_encryption_t encryption, int blocking, int msec, int *cancel) _CUPS_API_1_7; extern const char *httpGetContentEncoding(http_t *http) _CUPS_API_1_7; extern http_status_t httpGetExpect(http_t *http) _CUPS_API_1_7; extern ssize_t httpPeek(http_t *http, char *buffer, size_t length) _CUPS_API_1_7; extern http_state_t httpReadRequest(http_t *http, char *resource, size_t resourcelen) _CUPS_API_1_7; extern void httpSetDefaultField(http_t *http, http_field_t field, const char *value) _CUPS_API_1_7; extern http_state_t httpWriteResponse(http_t *http, http_status_t status) _CUPS_API_1_7; /* New in CUPS 2.0/macOS 10.10 */ extern int httpAddrClose(http_addr_t *addr, int fd) _CUPS_API_2_0; extern int httpAddrFamily(http_addr_t *addr) _CUPS_API_2_0; extern int httpCompareCredentials(cups_array_t *cred1, cups_array_t *cred2) _CUPS_API_2_0; extern int httpCredentialsAreValidForName(cups_array_t *credentials, const char *common_name); extern time_t httpCredentialsGetExpiration(cups_array_t *credentials) _CUPS_API_2_0; extern http_trust_t httpCredentialsGetTrust(cups_array_t *credentials, const char *common_name) _CUPS_API_2_0; extern size_t httpCredentialsString(cups_array_t *credentials, char *buffer, size_t bufsize) _CUPS_API_2_0; extern http_field_t httpFieldValue(const char *name) _CUPS_API_2_0; extern time_t httpGetActivity(http_t *http) _CUPS_API_2_0; extern http_addr_t *httpGetAddress(http_t *http) _CUPS_API_2_0; extern http_encryption_t httpGetEncryption(http_t *http) _CUPS_API_2_0; extern http_keepalive_t httpGetKeepAlive(http_t *http) _CUPS_API_2_0; extern size_t httpGetPending(http_t *http) _CUPS_API_2_0; extern size_t httpGetReady(http_t *http) _CUPS_API_2_0; extern size_t httpGetRemaining(http_t *http) _CUPS_API_2_0; extern int httpIsChunked(http_t *http) _CUPS_API_2_0; extern int httpIsEncrypted(http_t *http) _CUPS_API_2_0; extern int httpLoadCredentials(const char *path, cups_array_t **credentials, const char *common_name) _CUPS_API_2_0; extern const char *httpResolveHostname(http_t *http, char *buffer, size_t bufsize) _CUPS_API_2_0; extern int httpSaveCredentials(const char *path, cups_array_t *credentials, const char *common_name) _CUPS_API_2_0; extern void httpSetKeepAlive(http_t *http, http_keepalive_t keep_alive) _CUPS_API_2_0; extern void httpShutdown(http_t *http) _CUPS_API_2_0; extern const char *httpStateString(http_state_t state) _CUPS_API_2_0; extern const char *httpURIStatusString(http_uri_status_t status) _CUPS_API_2_0; /* * C++ magic... */ # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_HTTP_H_ */ ippsample/cups/cups-private.h0000644000175000017500000002061513240604116015310 0ustar tilltill/* * Private definitions for CUPS. * * Copyright © 2007-2018 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ #ifndef _CUPS_CUPS_PRIVATE_H_ # define _CUPS_CUPS_PRIVATE_H_ /* * Include necessary headers... */ # include "string-private.h" # include "debug-private.h" # include "array-private.h" # include "ipp-private.h" # include "http-private.h" # include "language-private.h" # include "pwg-private.h" # include "thread-private.h" # include # ifdef __APPLE__ # include # include # endif /* __APPLE__ */ /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Types... */ typedef struct _cups_buffer_s /**** Read/write buffer ****/ { struct _cups_buffer_s *next; /* Next buffer in list */ size_t size; /* Size of buffer */ char used, /* Is this buffer used? */ d[1]; /* Data buffer */ } _cups_buffer_t; typedef struct _cups_globals_s /**** CUPS global state data ****/ { /* Multiple places... */ const char *cups_datadir, /* CUPS_DATADIR environment var */ *cups_serverbin,/* CUPS_SERVERBIN environment var */ *cups_serverroot, /* CUPS_SERVERROOT environment var */ *cups_statedir, /* CUPS_STATEDIR environment var */ *localedir; /* LOCALDIR environment var */ /* adminutil.c */ time_t cupsd_update; /* Last time we got or set cupsd.conf */ char cupsd_hostname[HTTP_MAX_HOST]; /* Hostname for connection */ int cupsd_num_settings; /* Number of server settings */ cups_option_t *cupsd_settings;/* Server settings */ /* auth.c */ # ifdef HAVE_GSSAPI char gss_service_name[32]; /* Kerberos service name */ # endif /* HAVE_GSSAPI */ /* backend.c */ char resolved_uri[1024]; /* Buffer for cupsBackendDeviceURI */ /* debug.c */ # ifdef DEBUG int thread_id; /* Friendly thread ID */ # endif /* DEBUG */ /* file.c */ cups_file_t *stdio_files[3];/* stdin, stdout, stderr */ /* http.c */ char http_date[256]; /* Date+time buffer */ /* http-addr.c */ unsigned ip_addr; /* Packed IPv4 address */ char *ip_ptrs[2]; /* Pointer to packed address */ struct hostent hostent; /* Host entry for IP address */ # ifdef HAVE_GETADDRINFO char hostname[1024]; /* Hostname */ # endif /* HAVE_GETADDRINFO */ int need_res_init; /* Need to reinitialize resolver? */ /* ipp.c */ ipp_uchar_t ipp_date[11]; /* RFC-2579 date/time data */ _cups_buffer_t *cups_buffers; /* Buffer list */ /* ipp-support.c */ int ipp_port; /* IPP port number */ char ipp_unknown[255]; /* Unknown error statuses */ /* language.c */ cups_lang_t *lang_default; /* Default language */ # ifdef __APPLE__ char language[32]; /* Cached language */ # endif /* __APPLE__ */ /* pwg-media.c */ cups_array_t *leg_size_lut, /* Lookup table for legacy names */ *ppd_size_lut, /* Lookup table for PPD names */ *pwg_size_lut; /* Lookup table for PWG names */ pwg_media_t pwg_media; /* PWG media data for custom size */ char pwg_name[65], /* PWG media name for custom size */ ppd_name[41]; /* PPD media name for custom size */ /* request.c */ http_t *http; /* Current server connection */ ipp_status_t last_error; /* Last IPP error */ char *last_status_message; /* Last IPP status-message */ /* snmp.c */ char snmp_community[255]; /* Default SNMP community name */ int snmp_debug; /* Log SNMP IO to stderr? */ /* tempfile.c */ char tempfile[1024]; /* cupsTempFd/File buffer */ /* usersys.c */ http_encryption_t encryption; /* Encryption setting */ char user[65], /* User name */ user_agent[256],/* User-Agent string */ server[256], /* Server address */ servername[256],/* Server hostname */ password[128]; /* Password for default callback */ cups_password_cb2_t password_cb; /* Password callback */ void *password_data; /* Password user data */ http_tls_credentials_t tls_credentials; /* Default client credentials */ cups_client_cert_cb_t client_cert_cb; /* Client certificate callback */ void *client_cert_data; /* Client certificate user data */ cups_server_cert_cb_t server_cert_cb; /* Server certificate callback */ void *server_cert_data; /* Server certificate user data */ int server_version, /* Server IPP version */ trust_first, /* Trust on first use? */ any_root, /* Allow any (e.g., self-signed) root */ expired_certs, /* Allow expired certs */ validate_certs; /* Validate certificates */ /* util.c */ char def_printer[256]; /* Default printer */ } _cups_globals_t; typedef struct _cups_media_db_s /* Media database */ { char *color, /* Media color, if any */ *key, /* Media key, if any */ *info, /* Media human-readable name, if any */ *size_name, /* Media PWG size name, if provided */ *source, /* Media source, if any */ *type; /* Media type, if any */ int width, /* Width in hundredths of millimeters */ length, /* Length in hundredths of * millimeters */ bottom, /* Bottom margin in hundredths of * millimeters */ left, /* Left margin in hundredths of * millimeters */ right, /* Right margin in hundredths of * millimeters */ top; /* Top margin in hundredths of * millimeters */ } _cups_media_db_t; typedef struct _cups_dconstres_s /* Constraint/resolver */ { char *name; /* Name of resolver */ ipp_t *collection; /* Collection containing attrs */ } _cups_dconstres_t; struct _cups_dinfo_s /* Destination capability and status * information */ { int version; /* IPP version */ const char *uri; /* Printer URI */ char *resource; /* Resource path */ ipp_t *attrs; /* Printer attributes */ int num_defaults; /* Number of default options */ cups_option_t *defaults; /* Default options */ cups_array_t *constraints; /* Job constraints */ cups_array_t *resolvers; /* Job resolvers */ cups_array_t *localizations; /* Localization information */ cups_array_t *media_db; /* Media database */ _cups_media_db_t min_size, /* Minimum size */ max_size; /* Maximum size */ unsigned cached_flags; /* Flags used for cached media */ cups_array_t *cached_db; /* Cache of media from last index/default */ time_t ready_time; /* When xxx-ready attributes were last queried */ ipp_t *ready_attrs; /* xxx-ready attributes */ cups_array_t *ready_db; /* media[-col]-ready media database */ }; /* * Prototypes... */ # ifdef __APPLE__ extern CFStringRef _cupsAppleCopyDefaultPaperID(void); extern CFStringRef _cupsAppleCopyDefaultPrinter(void); extern int _cupsAppleGetUseLastPrinter(void); extern void _cupsAppleSetDefaultPaperID(CFStringRef name); extern void _cupsAppleSetDefaultPrinter(CFStringRef name); extern void _cupsAppleSetUseLastPrinter(int uselast); # endif /* __APPLE__ */ extern char *_cupsBufferGet(size_t size); extern void _cupsBufferRelease(char *b); extern http_t *_cupsConnect(void); extern char *_cupsCreateDest(const char *name, const char *info, const char *device_id, const char *device_uri, char *uri, size_t urisize); extern void _cupsEncodeOption(ipp_t *ipp, ipp_tag_t group_tag, _ipp_option_t *map, const char *name, const char *value); extern int _cupsGet1284Values(const char *device_id, cups_option_t **values); extern const char *_cupsGetDestResource(cups_dest_t *dest, unsigned flags, char *resource, size_t resourcesize); extern int _cupsGetDests(http_t *http, ipp_op_t op, const char *name, cups_dest_t **dests, cups_ptype_t type, cups_ptype_t mask); extern const char *_cupsGetPassword(const char *prompt); extern void _cupsGlobalLock(void); extern _cups_globals_t *_cupsGlobals(void); extern void _cupsGlobalUnlock(void); # ifdef HAVE_GSSAPI extern const char *_cupsGSSServiceName(void); # endif /* HAVE_GSSAPI */ extern int _cupsNextDelay(int current, int *previous); extern void _cupsSetDefaults(void); extern void _cupsSetError(ipp_status_t status, const char *message, int localize); extern void _cupsSetHTTPError(http_status_t status); # ifdef HAVE_GSSAPI extern int _cupsSetNegotiateAuthString(http_t *http, const char *method, const char *resource); # endif /* HAVE_GSSAPI */ extern char *_cupsUserDefault(char *name, size_t namesize); /* * C++ magic... */ # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_CUPS_PRIVATE_H_ */ ippsample/cups/usersys.c0000644000175000017500000010515013240604116014374 0ustar tilltill/* * User, system, and password routines for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #include #include #ifdef WIN32 # include #else # include # include # include #endif /* WIN32 */ /* * Local constants... */ #ifdef __APPLE__ # define kCUPSPrintingPrefs CFSTR("org.cups.PrintingPrefs") # define kAllowAnyRootKey CFSTR("AllowAnyRoot") # define kAllowExpiredCertsKey CFSTR("AllowExpiredCerts") # define kEncryptionKey CFSTR("Encryption") # define kGSSServiceNameKey CFSTR("GSSServiceName") # define kSSLOptionsKey CFSTR("SSLOptions") # define kTrustOnFirstUseKey CFSTR("TrustOnFirstUse") # define kValidateCertsKey CFSTR("ValidateCerts") #endif /* __APPLE__ */ #define _CUPS_PASSCHAR '*' /* Character that is echoed for password */ /* * Local types... */ typedef struct _cups_client_conf_s /**** client.conf config data ****/ { #ifdef HAVE_SSL int ssl_options, /* SSLOptions values */ ssl_min_version,/* Minimum SSL/TLS version */ ssl_max_version;/* Maximum SSL/TLS version */ #endif /* HAVE_SSL */ int trust_first, /* Trust on first use? */ any_root, /* Allow any (e.g., self-signed) root */ expired_certs, /* Allow expired certs */ validate_certs; /* Validate certificates */ http_encryption_t encryption; /* Encryption setting */ char user[65], /* User name */ server_name[256]; /* Server hostname */ #ifdef HAVE_GSSAPI char gss_service_name[32]; /* Kerberos service name */ #endif /* HAVE_GSSAPI */ } _cups_client_conf_t; /* * Local functions... */ #ifdef __APPLE__ static int cups_apple_get_boolean(CFStringRef key, int *value); static int cups_apple_get_string(CFStringRef key, char *value, size_t valsize); #endif /* __APPLE__ */ static int cups_boolean_value(const char *value); static void cups_finalize_client_conf(_cups_client_conf_t *cc); static void cups_init_client_conf(_cups_client_conf_t *cc); static void cups_read_client_conf(cups_file_t *fp, _cups_client_conf_t *cc); static void cups_set_default_ipp_port(_cups_globals_t *cg); static void cups_set_encryption(_cups_client_conf_t *cc, const char *value); #ifdef HAVE_GSSAPI static void cups_set_gss_service_name(_cups_client_conf_t *cc, const char *value); #endif /* HAVE_GSSAPI */ static void cups_set_server_name(_cups_client_conf_t *cc, const char *value); #ifdef HAVE_SSL static void cups_set_ssl_options(_cups_client_conf_t *cc, const char *value); #endif /* HAVE_SSL */ static void cups_set_user(_cups_client_conf_t *cc, const char *value); /* * 'cupsEncryption()' - Get the current encryption settings. * * The default encryption setting comes from the CUPS_ENCRYPTION * environment variable, then the ~/.cups/client.conf file, and finally the * /etc/cups/client.conf file. If not set, the default is * @code HTTP_ENCRYPTION_IF_REQUESTED@. * * Note: The current encryption setting is tracked separately for each thread * in a program. Multi-threaded programs that override the setting via the * @link cupsSetEncryption@ function need to do so in each thread for the same * setting to be used. */ http_encryption_t /* O - Encryption settings */ cupsEncryption(void) { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ if (cg->encryption == (http_encryption_t)-1) _cupsSetDefaults(); return (cg->encryption); } /* * 'cupsGetPassword()' - Get a password from the user. * * Uses the current password callback function. Returns @code NULL@ if the * user does not provide a password. * * Note: The current password callback function is tracked separately for each * thread in a program. Multi-threaded programs that override the setting via * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to * do so in each thread for the same function to be used. * * @exclude all@ */ const char * /* O - Password */ cupsGetPassword(const char *prompt) /* I - Prompt string */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ return ((cg->password_cb)(prompt, NULL, NULL, NULL, cg->password_data)); } /* * 'cupsGetPassword2()' - Get a password from the user using the current * password callback. * * Uses the current password callback function. Returns @code NULL@ if the * user does not provide a password. * * Note: The current password callback function is tracked separately for each * thread in a program. Multi-threaded programs that override the setting via * the @link cupsSetPasswordCB2@ function need to do so in each thread for the * same function to be used. * * @since CUPS 1.4/macOS 10.6@ */ const char * /* O - Password */ cupsGetPassword2(const char *prompt, /* I - Prompt string */ http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *method, /* I - Request method ("GET", "POST", "PUT") */ const char *resource) /* I - Resource path */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ if (!http) http = _cupsConnect(); return ((cg->password_cb)(prompt, http, method, resource, cg->password_data)); } /* * 'cupsServer()' - Return the hostname/address of the current server. * * The default server comes from the CUPS_SERVER environment variable, then the * ~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not * set, the default is the local system - either "localhost" or a domain socket * path. * * The returned value can be a fully-qualified hostname, a numeric IPv4 or IPv6 * address, or a domain socket pathname. * * Note: The current server is tracked separately for each thread in a program. * Multi-threaded programs that override the server via the * @link cupsSetServer@ function need to do so in each thread for the same * server to be used. */ const char * /* O - Server name */ cupsServer(void) { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ if (!cg->server[0]) _cupsSetDefaults(); return (cg->server); } /* * 'cupsSetClientCertCB()' - Set the client certificate callback. * * Pass @code NULL@ to restore the default callback. * * Note: The current certificate callback is tracked separately for each thread * in a program. Multi-threaded programs that override the callback need to do * so in each thread for the same callback to be used. * * @since CUPS 1.5/macOS 10.7@ */ void cupsSetClientCertCB( cups_client_cert_cb_t cb, /* I - Callback function */ void *user_data) /* I - User data pointer */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ cg->client_cert_cb = cb; cg->client_cert_data = user_data; } /* * 'cupsSetCredentials()' - Set the default credentials to be used for SSL/TLS * connections. * * Note: The default credentials are tracked separately for each thread in a * program. Multi-threaded programs that override the setting need to do so in * each thread for the same setting to be used. * * @since CUPS 1.5/macOS 10.7@ */ int /* O - Status of call (0 = success) */ cupsSetCredentials( cups_array_t *credentials) /* I - Array of credentials */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ if (cupsArrayCount(credentials) < 1) return (-1); #ifdef HAVE_SSL _httpFreeCredentials(cg->tls_credentials); cg->tls_credentials = _httpCreateCredentials(credentials); #endif /* HAVE_SSL */ return (cg->tls_credentials ? 0 : -1); } /* * 'cupsSetEncryption()' - Set the encryption preference. * * The default encryption setting comes from the CUPS_ENCRYPTION * environment variable, then the ~/.cups/client.conf file, and finally the * /etc/cups/client.conf file. If not set, the default is * @code HTTP_ENCRYPTION_IF_REQUESTED@. * * Note: The current encryption setting is tracked separately for each thread * in a program. Multi-threaded programs that override the setting need to do * so in each thread for the same setting to be used. */ void cupsSetEncryption(http_encryption_t e) /* I - New encryption preference */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ cg->encryption = e; if (cg->http) httpEncryption(cg->http, e); } /* * 'cupsSetPasswordCB()' - Set the password callback for CUPS. * * Pass @code NULL@ to restore the default (console) password callback, which * reads the password from the console. Programs should call either this * function or @link cupsSetPasswordCB2@, as only one callback can be registered * by a program per thread. * * Note: The current password callback is tracked separately for each thread * in a program. Multi-threaded programs that override the callback need to do * so in each thread for the same callback to be used. * * @exclude all@ */ void cupsSetPasswordCB(cups_password_cb_t cb)/* I - Callback function */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ if (cb == (cups_password_cb_t)0) cg->password_cb = (cups_password_cb2_t)_cupsGetPassword; else cg->password_cb = (cups_password_cb2_t)cb; cg->password_data = NULL; } /* * 'cupsSetPasswordCB2()' - Set the advanced password callback for CUPS. * * Pass @code NULL@ to restore the default (console) password callback, which * reads the password from the console. Programs should call either this * function or @link cupsSetPasswordCB2@, as only one callback can be registered * by a program per thread. * * Note: The current password callback is tracked separately for each thread * in a program. Multi-threaded programs that override the callback need to do * so in each thread for the same callback to be used. * * @since CUPS 1.4/macOS 10.6@ */ void cupsSetPasswordCB2( cups_password_cb2_t cb, /* I - Callback function */ void *user_data) /* I - User data pointer */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ if (cb == (cups_password_cb2_t)0) cg->password_cb = (cups_password_cb2_t)_cupsGetPassword; else cg->password_cb = cb; cg->password_data = user_data; } /* * 'cupsSetServer()' - Set the default server name and port. * * The "server" string can be a fully-qualified hostname, a numeric * IPv4 or IPv6 address, or a domain socket pathname. Hostnames and numeric IP * addresses can be optionally followed by a colon and port number to override * the default port 631, e.g. "hostname:8631". Pass @code NULL@ to restore the * default server name and port. * * Note: The current server is tracked separately for each thread in a program. * Multi-threaded programs that override the server need to do so in each * thread for the same server to be used. */ void cupsSetServer(const char *server) /* I - Server name */ { char *options, /* Options */ *port; /* Pointer to port */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ if (server) { strlcpy(cg->server, server, sizeof(cg->server)); if (cg->server[0] != '/' && (options = strrchr(cg->server, '/')) != NULL) { *options++ = '\0'; if (!strcmp(options, "version=1.0")) cg->server_version = 10; else if (!strcmp(options, "version=1.1")) cg->server_version = 11; else if (!strcmp(options, "version=2.0")) cg->server_version = 20; else if (!strcmp(options, "version=2.1")) cg->server_version = 21; else if (!strcmp(options, "version=2.2")) cg->server_version = 22; } else cg->server_version = 20; if (cg->server[0] != '/' && (port = strrchr(cg->server, ':')) != NULL && !strchr(port, ']') && isdigit(port[1] & 255)) { *port++ = '\0'; cg->ipp_port = atoi(port); } if (!cg->ipp_port) cups_set_default_ipp_port(cg); if (cg->server[0] == '/') strlcpy(cg->servername, "localhost", sizeof(cg->servername)); else strlcpy(cg->servername, cg->server, sizeof(cg->servername)); } else { cg->server[0] = '\0'; cg->servername[0] = '\0'; cg->server_version = 20; cg->ipp_port = 0; } if (cg->http) { httpClose(cg->http); cg->http = NULL; } } /* * 'cupsSetServerCertCB()' - Set the server certificate callback. * * Pass @code NULL@ to restore the default callback. * * Note: The current credentials callback is tracked separately for each thread * in a program. Multi-threaded programs that override the callback need to do * so in each thread for the same callback to be used. * * @since CUPS 1.5/macOS 10.7@ */ void cupsSetServerCertCB( cups_server_cert_cb_t cb, /* I - Callback function */ void *user_data) /* I - User data pointer */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ cg->server_cert_cb = cb; cg->server_cert_data = user_data; } /* * 'cupsSetUser()' - Set the default user name. * * Pass @code NULL@ to restore the default user name. * * Note: The current user name is tracked separately for each thread in a * program. Multi-threaded programs that override the user name need to do so * in each thread for the same user name to be used. */ void cupsSetUser(const char *user) /* I - User name */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ if (user) strlcpy(cg->user, user, sizeof(cg->user)); else cg->user[0] = '\0'; } /* * 'cupsSetUserAgent()' - Set the default HTTP User-Agent string. * * Setting the string to NULL forces the default value containing the CUPS * version, IPP version, and operating system version and architecture. * * @since CUPS 1.7/macOS 10.9@ */ void cupsSetUserAgent(const char *user_agent)/* I - User-Agent string or @code NULL@ */ { _cups_globals_t *cg = _cupsGlobals(); /* Thread globals */ #ifdef WIN32 SYSTEM_INFO sysinfo; /* System information */ OSVERSIONINFO version; /* OS version info */ #else struct utsname name; /* uname info */ #endif /* WIN32 */ if (user_agent) { strlcpy(cg->user_agent, user_agent, sizeof(cg->user_agent)); return; } #ifdef WIN32 version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&version); GetNativeSystemInfo(&sysinfo); snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (Windows %d.%d; %s) IPP/2.0", version.dwMajorVersion, version.dwMinorVersion, sysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? "amd64" : sysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM ? "arm" : sysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 ? "ia64" : sysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL ? "intel" : "unknown"); #else uname(&name); snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (%s %s; %s) IPP/2.0", name.sysname, name.release, name.machine); #endif /* WIN32 */ } /* * 'cupsUser()' - Return the current user's name. * * Note: The current user name is tracked separately for each thread in a * program. Multi-threaded programs that override the user name with the * @link cupsSetUser@ function need to do so in each thread for the same user * name to be used. */ const char * /* O - User name */ cupsUser(void) { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ if (!cg->user[0]) _cupsSetDefaults(); return (cg->user); } /* * 'cupsUserAgent()' - Return the default HTTP User-Agent string. * * @since CUPS 1.7/macOS 10.9@ */ const char * /* O - User-Agent string */ cupsUserAgent(void) { _cups_globals_t *cg = _cupsGlobals(); /* Thread globals */ if (!cg->user_agent[0]) cupsSetUserAgent(NULL); return (cg->user_agent); } /* * '_cupsGetPassword()' - Get a password from the user. */ const char * /* O - Password or @code NULL@ if none */ _cupsGetPassword(const char *prompt) /* I - Prompt string */ { #ifdef WIN32 HANDLE tty; /* Console handle */ DWORD mode; /* Console mode */ char passch, /* Current key press */ *passptr, /* Pointer into password string */ *passend; /* End of password string */ DWORD passbytes; /* Bytes read */ _cups_globals_t *cg = _cupsGlobals(); /* Thread globals */ /* * Disable input echo and set raw input... */ if ((tty = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) return (NULL); if (!GetConsoleMode(tty, &mode)) return (NULL); if (!SetConsoleMode(tty, 0)) return (NULL); /* * Display the prompt... */ printf("%s ", prompt); fflush(stdout); /* * Read the password string from /dev/tty until we get interrupted or get a * carriage return or newline... */ passptr = cg->password; passend = cg->password + sizeof(cg->password) - 1; while (ReadFile(tty, &passch, 1, &passbytes, NULL)) { if (passch == 0x0A || passch == 0x0D) { /* * Enter/return... */ break; } else if (passch == 0x08 || passch == 0x7F) { /* * Backspace/delete (erase character)... */ if (passptr > cg->password) { passptr --; fputs("\010 \010", stdout); } else putchar(0x07); } else if (passch == 0x15) { /* * CTRL+U (erase line) */ if (passptr > cg->password) { while (passptr > cg->password) { passptr --; fputs("\010 \010", stdout); } } else putchar(0x07); } else if (passch == 0x03) { /* * CTRL+C... */ passptr = cg->password; break; } else if ((passch & 255) < 0x20 || passptr >= passend) putchar(0x07); else { *passptr++ = passch; putchar(_CUPS_PASSCHAR); } fflush(stdout); } putchar('\n'); fflush(stdout); /* * Cleanup... */ SetConsoleMode(tty, mode); /* * Return the proper value... */ if (passbytes == 1 && passptr > cg->password) { *passptr = '\0'; return (cg->password); } else { memset(cg->password, 0, sizeof(cg->password)); return (NULL); } #else int tty; /* /dev/tty - never read from stdin */ struct termios original, /* Original input mode */ noecho; /* No echo input mode */ char passch, /* Current key press */ *passptr, /* Pointer into password string */ *passend; /* End of password string */ ssize_t passbytes; /* Bytes read */ _cups_globals_t *cg = _cupsGlobals(); /* Thread globals */ /* * Disable input echo and set raw input... */ if ((tty = open("/dev/tty", O_RDONLY)) < 0) return (NULL); if (tcgetattr(tty, &original)) { close(tty); return (NULL); } noecho = original; noecho.c_lflag &= (tcflag_t)~(ICANON | ECHO | ECHOE | ISIG); noecho.c_cc[VMIN] = 1; noecho.c_cc[VTIME] = 0; if (tcsetattr(tty, TCSAFLUSH, &noecho)) { close(tty); return (NULL); } /* * Display the prompt... */ printf("%s ", prompt); fflush(stdout); /* * Read the password string from /dev/tty until we get interrupted or get a * carriage return or newline... */ passptr = cg->password; passend = cg->password + sizeof(cg->password) - 1; while ((passbytes = read(tty, &passch, 1)) == 1) { if (passch == noecho.c_cc[VEOL] || # ifdef VEOL2 passch == noecho.c_cc[VEOL2] || # endif /* VEOL2 */ passch == 0x0A || passch == 0x0D) { /* * Enter/return... */ break; } else if (passch == noecho.c_cc[VERASE] || passch == 0x08 || passch == 0x7F) { /* * Backspace/delete (erase character)... */ if (passptr > cg->password) { passptr --; fputs("\010 \010", stdout); } else putchar(0x07); } else if (passch == noecho.c_cc[VKILL]) { /* * CTRL+U (erase line) */ if (passptr > cg->password) { while (passptr > cg->password) { passptr --; fputs("\010 \010", stdout); } } else putchar(0x07); } else if (passch == noecho.c_cc[VINTR] || passch == noecho.c_cc[VQUIT] || passch == noecho.c_cc[VEOF]) { /* * CTRL+C, CTRL+D, or CTRL+Z... */ passptr = cg->password; break; } else if ((passch & 255) < 0x20 || passptr >= passend) putchar(0x07); else { *passptr++ = passch; putchar(_CUPS_PASSCHAR); } fflush(stdout); } putchar('\n'); fflush(stdout); /* * Cleanup... */ tcsetattr(tty, TCSAFLUSH, &original); close(tty); /* * Return the proper value... */ if (passbytes == 1 && passptr > cg->password) { *passptr = '\0'; return (cg->password); } else { memset(cg->password, 0, sizeof(cg->password)); return (NULL); } #endif /* WIN32 */ } #ifdef HAVE_GSSAPI /* * '_cupsGSSServiceName()' - Get the GSS (Kerberos) service name. */ const char * _cupsGSSServiceName(void) { _cups_globals_t *cg = _cupsGlobals(); /* Thread globals */ if (!cg->gss_service_name[0]) _cupsSetDefaults(); return (cg->gss_service_name); } #endif /* HAVE_GSSAPI */ /* * '_cupsSetDefaults()' - Set the default server, port, and encryption. */ void _cupsSetDefaults(void) { cups_file_t *fp; /* File */ const char *home; /* Home directory of user */ char filename[1024]; /* Filename */ _cups_client_conf_t cc; /* client.conf values */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ DEBUG_puts("_cupsSetDefaults()"); /* * Load initial client.conf values... */ cups_init_client_conf(&cc); /* * Read the /etc/cups/client.conf and ~/.cups/client.conf files, if * present. */ snprintf(filename, sizeof(filename), "%s/client.conf", cg->cups_serverroot); if ((fp = cupsFileOpen(filename, "r")) != NULL) { cups_read_client_conf(fp, &cc); cupsFileClose(fp); } # ifdef HAVE_GETEUID if ((geteuid() == getuid() || !getuid()) && getegid() == getgid() && (home = getenv("HOME")) != NULL) # elif !defined(WIN32) if (getuid() && (home = getenv("HOME")) != NULL) # else if ((home = getenv("HOME")) != NULL) # endif /* HAVE_GETEUID */ { /* * Look for ~/.cups/client.conf... */ snprintf(filename, sizeof(filename), "%s/.cups/client.conf", home); if ((fp = cupsFileOpen(filename, "r")) != NULL) { cups_read_client_conf(fp, &cc); cupsFileClose(fp); } } /* * Finalize things so every client.conf value is set... */ cups_finalize_client_conf(&cc); if (cg->encryption == (http_encryption_t)-1) cg->encryption = cc.encryption; if (!cg->server[0] || !cg->ipp_port) cupsSetServer(cc.server_name); if (!cg->ipp_port) cups_set_default_ipp_port(cg); if (!cg->user[0]) strlcpy(cg->user, cc.user, sizeof(cg->user)); #ifdef HAVE_GSSAPI if (!cg->gss_service_name[0]) strlcpy(cg->gss_service_name, cc.gss_service_name, sizeof(cg->gss_service_name)); #endif /* HAVE_GSSAPI */ if (cg->trust_first < 0) cg->trust_first = cc.trust_first; if (cg->any_root < 0) cg->any_root = cc.any_root; if (cg->expired_certs < 0) cg->expired_certs = cc.expired_certs; if (cg->validate_certs < 0) cg->validate_certs = cc.validate_certs; #ifdef HAVE_SSL _httpTLSSetOptions(cc.ssl_options | _HTTP_TLS_SET_DEFAULT, cc.ssl_min_version, cc.ssl_max_version); #endif /* HAVE_SSL */ } #ifdef __APPLE__ /* * 'cups_apple_get_boolean()' - Get a boolean setting from the CUPS preferences. */ static int /* O - 1 if set, 0 otherwise */ cups_apple_get_boolean( CFStringRef key, /* I - Key (name) */ int *value) /* O - Boolean value */ { Boolean bval, /* Preference value */ bval_set; /* Value is set? */ bval = CFPreferencesGetAppBooleanValue(key, kCUPSPrintingPrefs, &bval_set); if (bval_set) *value = (int)bval; return ((int)bval_set); } /* * 'cups_apple_get_string()' - Get a string setting from the CUPS preferences. */ static int /* O - 1 if set, 0 otherwise */ cups_apple_get_string( CFStringRef key, /* I - Key (name) */ char *value, /* O - String value */ size_t valsize) /* I - Size of value buffer */ { CFStringRef sval; /* String value */ if ((sval = CFPreferencesCopyAppValue(key, kCUPSPrintingPrefs)) != NULL) { Boolean result = CFStringGetCString(sval, value, (CFIndex)valsize, kCFStringEncodingUTF8); CFRelease(sval); if (result) return (1); } return (0); } #endif /* __APPLE__ */ /* * 'cups_boolean_value()' - Convert a string to a boolean value. */ static int /* O - Boolean value */ cups_boolean_value(const char *value) /* I - String value */ { return (!_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "on") || !_cups_strcasecmp(value, "true")); } /* * 'cups_finalize_client_conf()' - Finalize client.conf values. */ static void cups_finalize_client_conf( _cups_client_conf_t *cc) /* I - client.conf values */ { const char *value; /* Environment variable */ if ((value = getenv("CUPS_TRUSTFIRST")) != NULL) cc->trust_first = cups_boolean_value(value); if ((value = getenv("CUPS_ANYROOT")) != NULL) cc->any_root = cups_boolean_value(value); if ((value = getenv("CUPS_ENCRYPTION")) != NULL) cups_set_encryption(cc, value); if ((value = getenv("CUPS_EXPIREDCERTS")) != NULL) cc->expired_certs = cups_boolean_value(value); #ifdef HAVE_GSSAPI if ((value = getenv("CUPS_GSSSERVICENAME")) != NULL) cups_set_gss_service_name(cc, value); #endif /* HAVE_GSSAPI */ if ((value = getenv("CUPS_SERVER")) != NULL) cups_set_server_name(cc, value); if ((value = getenv("CUPS_USER")) != NULL) cups_set_user(cc, value); if ((value = getenv("CUPS_VALIDATECERTS")) != NULL) cc->validate_certs = cups_boolean_value(value); /* * Then apply defaults for those values that haven't been set... */ if (cc->trust_first < 0) cc->trust_first = 1; if (cc->any_root < 0) cc->any_root = 1; if (cc->encryption == (http_encryption_t)-1) cc->encryption = HTTP_ENCRYPTION_IF_REQUESTED; if (cc->expired_certs < 0) cc->expired_certs = 0; #ifdef HAVE_GSSAPI if (!cc->gss_service_name[0]) cups_set_gss_service_name(cc, CUPS_DEFAULT_GSSSERVICENAME); #endif /* HAVE_GSSAPI */ if (!cc->server_name[0]) { #ifdef CUPS_DEFAULT_DOMAINSOCKET /* * If we are compiled with domain socket support, only use the * domain socket if it exists and has the right permissions... */ if (!access(CUPS_DEFAULT_DOMAINSOCKET, R_OK)) cups_set_server_name(cc, CUPS_DEFAULT_DOMAINSOCKET); else #endif /* CUPS_DEFAULT_DOMAINSOCKET */ cups_set_server_name(cc, "localhost"); } if (!cc->user[0]) { #ifdef WIN32 /* * Get the current user name from the OS... */ DWORD size; /* Size of string */ size = sizeof(cc->user); if (!GetUserName(cc->user, &size)) #else /* * Try the USER environment variable as the default username... */ const char *envuser = getenv("USER"); /* Default username */ struct passwd *pw = NULL; /* Account information */ if (envuser) { /* * Validate USER matches the current UID, otherwise don't allow it to * override things... This makes sure that printing after doing su * or sudo records the correct username. */ if ((pw = getpwnam(envuser)) != NULL && pw->pw_uid != getuid()) pw = NULL; } if (!pw) pw = getpwuid(getuid()); if (pw) strlcpy(cc->user, pw->pw_name, sizeof(cc->user)); else #endif /* WIN32 */ { /* * Use the default "unknown" user name... */ strlcpy(cc->user, "unknown", sizeof(cc->user)); } } if (cc->validate_certs < 0) cc->validate_certs = 0; } /* * 'cups_init_client_conf()' - Initialize client.conf values. */ static void cups_init_client_conf( _cups_client_conf_t *cc) /* I - client.conf values */ { /* * Clear all values to "not set"... */ memset(cc, 0, sizeof(_cups_client_conf_t)); #ifdef HAVE_SSL cc->ssl_min_version = _HTTP_TLS_1_0; cc->ssl_max_version = _HTTP_TLS_MAX; #endif /* HAVE_SSL */ cc->encryption = (http_encryption_t)-1; cc->trust_first = -1; cc->any_root = -1; cc->expired_certs = -1; cc->validate_certs = -1; /* * Load settings from the org.cups.PrintingPrefs plist (which trump * everything...) */ #if defined(__APPLE__) && defined(HAVE_SSL) char sval[1024]; /* String value */ int bval; /* Boolean value */ if (cups_apple_get_boolean(kAllowAnyRootKey, &bval)) cc->any_root = bval; if (cups_apple_get_boolean(kAllowExpiredCertsKey, &bval)) cc->expired_certs = bval; if (cups_apple_get_string(kEncryptionKey, sval, sizeof(sval))) cups_set_encryption(cc, sval); if (cups_apple_get_string(kSSLOptionsKey, sval, sizeof(sval))) cups_set_ssl_options(cc, sval); if (cups_apple_get_boolean(kTrustOnFirstUseKey, &bval)) cc->trust_first = bval; if (cups_apple_get_boolean(kValidateCertsKey, &bval)) cc->validate_certs = bval; #endif /* __APPLE__ && HAVE_SSL */ } /* * 'cups_read_client_conf()' - Read a client.conf file. */ static void cups_read_client_conf( cups_file_t *fp, /* I - File to read */ _cups_client_conf_t *cc) /* I - client.conf values */ { int linenum; /* Current line number */ char line[1024], /* Line from file */ *value; /* Pointer into line */ /* * Read from the file... */ linenum = 0; while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) { if (!_cups_strcasecmp(line, "Encryption") && value) cups_set_encryption(cc, value); #ifndef __APPLE__ /* * The ServerName directive is not supported on macOS due to app * sandboxing restrictions, i.e. not all apps request network access. */ else if (!_cups_strcasecmp(line, "ServerName") && value) cups_set_server_name(cc, value); #endif /* !__APPLE__ */ else if (!_cups_strcasecmp(line, "User") && value) cups_set_user(cc, value); else if (!_cups_strcasecmp(line, "TrustOnFirstUse") && value) cc->trust_first = cups_boolean_value(value); else if (!_cups_strcasecmp(line, "AllowAnyRoot") && value) cc->any_root = cups_boolean_value(value); else if (!_cups_strcasecmp(line, "AllowExpiredCerts") && value) cc->expired_certs = cups_boolean_value(value); else if (!_cups_strcasecmp(line, "ValidateCerts") && value) cc->validate_certs = cups_boolean_value(value); #ifdef HAVE_GSSAPI else if (!_cups_strcasecmp(line, "GSSServiceName") && value) cups_set_gss_service_name(cc, value); #endif /* HAVE_GSSAPI */ #ifdef HAVE_SSL else if (!_cups_strcasecmp(line, "SSLOptions") && value) cups_set_ssl_options(cc, value); #endif /* HAVE_SSL */ } } /* * 'cups_set_default_ipp_port()' - Set the default IPP port value. */ static void cups_set_default_ipp_port( _cups_globals_t *cg) /* I - Global data */ { const char *ipp_port; /* IPP_PORT environment variable */ if ((ipp_port = getenv("IPP_PORT")) != NULL) { if ((cg->ipp_port = atoi(ipp_port)) <= 0) cg->ipp_port = CUPS_DEFAULT_IPP_PORT; } else cg->ipp_port = CUPS_DEFAULT_IPP_PORT; } /* * 'cups_set_encryption()' - Set the Encryption value. */ static void cups_set_encryption( _cups_client_conf_t *cc, /* I - client.conf values */ const char *value) /* I - Value */ { if (!_cups_strcasecmp(value, "never")) cc->encryption = HTTP_ENCRYPTION_NEVER; else if (!_cups_strcasecmp(value, "always")) cc->encryption = HTTP_ENCRYPTION_ALWAYS; else if (!_cups_strcasecmp(value, "required")) cc->encryption = HTTP_ENCRYPTION_REQUIRED; else cc->encryption = HTTP_ENCRYPTION_IF_REQUESTED; } /* * 'cups_set_gss_service_name()' - Set the GSSServiceName value. */ #ifdef HAVE_GSSAPI static void cups_set_gss_service_name( _cups_client_conf_t *cc, /* I - client.conf values */ const char *value) /* I - Value */ { strlcpy(cc->gss_service_name, value, sizeof(cc->gss_service_name)); } #endif /* HAVE_GSSAPI */ /* * 'cups_set_server_name()' - Set the ServerName value. */ static void cups_set_server_name( _cups_client_conf_t *cc, /* I - client.conf values */ const char *value) /* I - Value */ { strlcpy(cc->server_name, value, sizeof(cc->server_name)); } /* * 'cups_set_ssl_options()' - Set the SSLOptions value. */ #ifdef HAVE_SSL static void cups_set_ssl_options( _cups_client_conf_t *cc, /* I - client.conf values */ const char *value) /* I - Value */ { /* * SSLOptions [AllowRC4] [AllowSSL3] [AllowDH] [DenyTLS1.0] [None] */ int options = _HTTP_TLS_NONE, /* SSL/TLS options */ min_version = _HTTP_TLS_1_0, /* Minimum SSL/TLS version */ max_version = _HTTP_TLS_MAX; /* Maximum SSL/TLS version */ char temp[256], /* Copy of value */ *start, /* Start of option */ *end; /* End of option */ strlcpy(temp, value, sizeof(temp)); for (start = temp; *start; start = end) { /* * Find end of keyword... */ end = start; while (*end && !_cups_isspace(*end)) end ++; if (*end) *end++ = '\0'; /* * Compare... */ if (!_cups_strcasecmp(start, "AllowRC4")) options |= _HTTP_TLS_ALLOW_RC4; else if (!_cups_strcasecmp(start, "AllowSSL3")) min_version = _HTTP_TLS_SSL3; else if (!_cups_strcasecmp(start, "AllowDH")) options |= _HTTP_TLS_ALLOW_DH; else if (!_cups_strcasecmp(start, "DenyCBC")) options |= _HTTP_TLS_DENY_CBC; else if (!_cups_strcasecmp(start, "DenyTLS1.0")) min_version = _HTTP_TLS_1_1; else if (!_cups_strcasecmp(start, "MaxTLS1.0")) max_version = _HTTP_TLS_1_0; else if (!_cups_strcasecmp(start, "MaxTLS1.1")) max_version = _HTTP_TLS_1_1; else if (!_cups_strcasecmp(start, "MaxTLS1.2")) max_version = _HTTP_TLS_1_2; else if (!_cups_strcasecmp(start, "MaxTLS1.3")) max_version = _HTTP_TLS_1_3; else if (!_cups_strcasecmp(start, "MinTLS1.0")) min_version = _HTTP_TLS_1_0; else if (!_cups_strcasecmp(start, "MinTLS1.1")) min_version = _HTTP_TLS_1_1; else if (!_cups_strcasecmp(start, "MinTLS1.2")) min_version = _HTTP_TLS_1_2; else if (!_cups_strcasecmp(start, "MinTLS1.3")) min_version = _HTTP_TLS_1_3; else if (!_cups_strcasecmp(start, "None")) options = _HTTP_TLS_NONE; } cc->ssl_options = options; cc->ssl_max_version = max_version; cc->ssl_min_version = min_version; DEBUG_printf(("4cups_set_ssl_options(cc=%p, value=\"%s\") options=%x, min_version=%d, max_version=%d", (void *)cc, value, options, min_version, max_version)); } #endif /* HAVE_SSL */ /* * 'cups_set_user()' - Set the User value. */ static void cups_set_user( _cups_client_conf_t *cc, /* I - client.conf values */ const char *value) /* I - Value */ { strlcpy(cc->user, value, sizeof(cc->user)); } ippsample/cups/http-addr.c0000644000175000017500000005201713240604116014551 0ustar tilltill/* * HTTP address routines for CUPS. * * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #include #ifdef HAVE_RESOLV_H # include #endif /* HAVE_RESOLV_H */ #ifdef __APPLE__ # include # include #endif /* __APPLE__ */ /* * 'httpAddrAny()' - Check for the "any" address. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 1 if "any", 0 otherwise */ httpAddrAny(const http_addr_t *addr) /* I - Address to check */ { if (!addr) return (0); #ifdef AF_INET6 if (addr->addr.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr))) return (1); #endif /* AF_INET6 */ if (addr->addr.sa_family == AF_INET && ntohl(addr->ipv4.sin_addr.s_addr) == 0x00000000) return (1); return (0); } /* * 'httpAddrClose()' - Close a socket created by @link httpAddrConnect@ or * @link httpAddrListen@. * * Pass @code NULL@ for sockets created with @link httpAddrConnect2@ and the * listen address for sockets created with @link httpAddrListen@. This function * ensures that domain sockets are removed when closed. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 0 on success, -1 on failure */ httpAddrClose(http_addr_t *addr, /* I - Listen address or @code NULL@ */ int fd) /* I - Socket file descriptor */ { #ifdef WIN32 if (closesocket(fd)) #else if (close(fd)) #endif /* WIN32 */ return (-1); #ifdef AF_LOCAL if (addr && addr->addr.sa_family == AF_LOCAL) return (unlink(addr->un.sun_path)); #endif /* AF_LOCAL */ return (0); } /* * 'httpAddrEqual()' - Compare two addresses. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 1 if equal, 0 if not */ httpAddrEqual(const http_addr_t *addr1, /* I - First address */ const http_addr_t *addr2) /* I - Second address */ { if (!addr1 && !addr2) return (1); if (!addr1 || !addr2) return (0); if (addr1->addr.sa_family != addr2->addr.sa_family) return (0); #ifdef AF_LOCAL if (addr1->addr.sa_family == AF_LOCAL) return (!strcmp(addr1->un.sun_path, addr2->un.sun_path)); #endif /* AF_LOCAL */ #ifdef AF_INET6 if (addr1->addr.sa_family == AF_INET6) return (!memcmp(&(addr1->ipv6.sin6_addr), &(addr2->ipv6.sin6_addr), 16)); #endif /* AF_INET6 */ return (addr1->ipv4.sin_addr.s_addr == addr2->ipv4.sin_addr.s_addr); } /* * 'httpAddrLength()' - Return the length of the address in bytes. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - Length in bytes */ httpAddrLength(const http_addr_t *addr) /* I - Address */ { if (!addr) return (0); #ifdef AF_INET6 if (addr->addr.sa_family == AF_INET6) return (sizeof(addr->ipv6)); else #endif /* AF_INET6 */ #ifdef AF_LOCAL if (addr->addr.sa_family == AF_LOCAL) return ((int)(offsetof(struct sockaddr_un, sun_path) + strlen(addr->un.sun_path) + 1)); else #endif /* AF_LOCAL */ if (addr->addr.sa_family == AF_INET) return (sizeof(addr->ipv4)); else return (0); } /* * 'httpAddrListen()' - Create a listening socket bound to the specified * address and port. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - Socket or -1 on error */ httpAddrListen(http_addr_t *addr, /* I - Address to bind to */ int port) /* I - Port number to bind to */ { int fd = -1, /* Socket */ val, /* Socket value */ status; /* Bind status */ /* * Range check input... */ if (!addr || port < 0) return (-1); /* * Create the socket and set options... */ if ((fd = socket(addr->addr.sa_family, SOCK_STREAM, 0)) < 0) { _cupsSetHTTPError(HTTP_STATUS_ERROR); return (-1); } val = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val)); #ifdef IPV6_V6ONLY if (addr->addr.sa_family == AF_INET6) setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, CUPS_SOCAST &val, sizeof(val)); #endif /* IPV6_V6ONLY */ /* * Bind the socket... */ #ifdef AF_LOCAL if (addr->addr.sa_family == AF_LOCAL) { mode_t mask; /* Umask setting */ /* * Remove any existing domain socket file... */ unlink(addr->un.sun_path); /* * Save the current umask and set it to 0 so that all users can access * the domain socket... */ mask = umask(0); /* * Bind the domain socket... */ status = bind(fd, (struct sockaddr *)addr, (socklen_t)httpAddrLength(addr)); /* * Restore the umask and fix permissions... */ umask(mask); chmod(addr->un.sun_path, 0140777); } else #endif /* AF_LOCAL */ { _httpAddrSetPort(addr, port); status = bind(fd, (struct sockaddr *)addr, (socklen_t)httpAddrLength(addr)); } if (status) { _cupsSetHTTPError(HTTP_STATUS_ERROR); close(fd); return (-1); } /* * Listen... */ if (listen(fd, 5)) { _cupsSetHTTPError(HTTP_STATUS_ERROR); close(fd); return (-1); } /* * Close on exec... */ #ifndef WIN32 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); #endif /* !WIN32 */ #ifdef SO_NOSIGPIPE /* * Disable SIGPIPE for this socket. */ val = 1; setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val)); #endif /* SO_NOSIGPIPE */ return (fd); } /* * 'httpAddrLocalhost()' - Check for the local loopback address. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 1 if local host, 0 otherwise */ httpAddrLocalhost( const http_addr_t *addr) /* I - Address to check */ { if (!addr) return (1); #ifdef AF_INET6 if (addr->addr.sa_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr))) return (1); #endif /* AF_INET6 */ #ifdef AF_LOCAL if (addr->addr.sa_family == AF_LOCAL) return (1); #endif /* AF_LOCAL */ if (addr->addr.sa_family == AF_INET && (ntohl(addr->ipv4.sin_addr.s_addr) & 0xff000000) == 0x7f000000) return (1); return (0); } /* * 'httpAddrLookup()' - Lookup the hostname associated with the address. * * @since CUPS 1.2/macOS 10.5@ */ char * /* O - Host name */ httpAddrLookup( const http_addr_t *addr, /* I - Address to lookup */ char *name, /* I - Host name buffer */ int namelen) /* I - Size of name buffer */ { _cups_globals_t *cg = _cupsGlobals(); /* Global data */ DEBUG_printf(("httpAddrLookup(addr=%p, name=%p, namelen=%d)", (void *)addr, (void *)name, namelen)); /* * Range check input... */ if (!addr || !name || namelen <= 2) { if (name && namelen >= 1) *name = '\0'; return (NULL); } #ifdef AF_LOCAL if (addr->addr.sa_family == AF_LOCAL) { strlcpy(name, addr->un.sun_path, (size_t)namelen); return (name); } #endif /* AF_LOCAL */ /* * Optimize lookups for localhost/loopback addresses... */ if (httpAddrLocalhost(addr)) { strlcpy(name, "localhost", (size_t)namelen); return (name); } #ifdef HAVE_RES_INIT /* * STR #2920: Initialize resolver after failure in cups-polld * * If the previous lookup failed, re-initialize the resolver to prevent * temporary network errors from persisting. This *should* be handled by * the resolver libraries, but apparently the glibc folks do not agree. * * We set a flag at the end of this function if we encounter an error that * requires reinitialization of the resolver functions. We then call * res_init() if the flag is set on the next call here or in httpAddrLookup(). */ if (cg->need_res_init) { res_init(); cg->need_res_init = 0; } #endif /* HAVE_RES_INIT */ #ifdef HAVE_GETNAMEINFO { /* * STR #2486: httpAddrLookup() fails when getnameinfo() returns EAI_AGAIN * * FWIW, I think this is really a bug in the implementation of * getnameinfo(), but falling back on httpAddrString() is easy to * do... */ int error = getnameinfo(&addr->addr, (socklen_t)httpAddrLength(addr), name, (socklen_t)namelen, NULL, 0, 0); if (error) { if (error == EAI_FAIL) cg->need_res_init = 1; return (httpAddrString(addr, name, namelen)); } } #else { struct hostent *host; /* Host from name service */ # ifdef AF_INET6 if (addr->addr.sa_family == AF_INET6) host = gethostbyaddr((char *)&(addr->ipv6.sin6_addr), sizeof(struct in_addr), AF_INET6); else # endif /* AF_INET6 */ host = gethostbyaddr((char *)&(addr->ipv4.sin_addr), sizeof(struct in_addr), AF_INET); if (host == NULL) { /* * No hostname, so return the raw address... */ if (h_errno == NO_RECOVERY) cg->need_res_init = 1; return (httpAddrString(addr, name, namelen)); } strlcpy(name, host->h_name, (size_t)namelen); } #endif /* HAVE_GETNAMEINFO */ DEBUG_printf(("1httpAddrLookup: returning \"%s\"...", name)); return (name); } /* * 'httpAddrFamily()' - Get the address family of an address. */ int /* O - Address family */ httpAddrFamily(http_addr_t *addr) /* I - Address */ { if (addr) return (addr->addr.sa_family); else return (0); } /* * 'httpAddrPort()' - Get the port number associated with an address. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - Port number */ httpAddrPort(http_addr_t *addr) /* I - Address */ { if (!addr) return (-1); #ifdef AF_INET6 else if (addr->addr.sa_family == AF_INET6) return (ntohs(addr->ipv6.sin6_port)); #endif /* AF_INET6 */ else if (addr->addr.sa_family == AF_INET) return (ntohs(addr->ipv4.sin_port)); else return (0); } /* * '_httpAddrSetPort()' - Set the port number associated with an address. */ void _httpAddrSetPort(http_addr_t *addr, /* I - Address */ int port) /* I - Port */ { if (!addr || port <= 0) return; #ifdef AF_INET6 if (addr->addr.sa_family == AF_INET6) addr->ipv6.sin6_port = htons(port); else #endif /* AF_INET6 */ if (addr->addr.sa_family == AF_INET) addr->ipv4.sin_port = htons(port); } /* * 'httpAddrString()' - Convert an address to a numeric string. * * @since CUPS 1.2/macOS 10.5@ */ char * /* O - Numeric address string */ httpAddrString(const http_addr_t *addr, /* I - Address to convert */ char *s, /* I - String buffer */ int slen) /* I - Length of string */ { DEBUG_printf(("httpAddrString(addr=%p, s=%p, slen=%d)", (void *)addr, (void *)s, slen)); /* * Range check input... */ if (!addr || !s || slen <= 2) { if (s && slen >= 1) *s = '\0'; return (NULL); } #ifdef AF_LOCAL if (addr->addr.sa_family == AF_LOCAL) { if (addr->un.sun_path[0] == '/') strlcpy(s, addr->un.sun_path, (size_t)slen); else strlcpy(s, "localhost", (size_t)slen); } else #endif /* AF_LOCAL */ if (addr->addr.sa_family == AF_INET) { unsigned temp; /* Temporary address */ temp = ntohl(addr->ipv4.sin_addr.s_addr); snprintf(s, (size_t)slen, "%d.%d.%d.%d", (temp >> 24) & 255, (temp >> 16) & 255, (temp >> 8) & 255, temp & 255); } #ifdef AF_INET6 else if (addr->addr.sa_family == AF_INET6) { char *sptr, /* Pointer into string */ temps[64]; /* Temporary string for address */ # ifdef HAVE_GETNAMEINFO if (getnameinfo(&addr->addr, (socklen_t)httpAddrLength(addr), temps, sizeof(temps), NULL, 0, NI_NUMERICHOST)) { /* * If we get an error back, then the address type is not supported * and we should zero out the buffer... */ s[0] = '\0'; return (NULL); } else if ((sptr = strchr(temps, '%')) != NULL) { /* * Convert "%zone" to "+zone" to match URI form... */ *sptr = '+'; } # else int i; /* Looping var */ unsigned temp; /* Current value */ const char *prefix; /* Prefix for address */ prefix = ""; for (sptr = temps, i = 0; i < 4 && addr->ipv6.sin6_addr.s6_addr32[i]; i ++) { temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]); snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, (temp >> 16) & 0xffff); prefix = ":"; sptr += strlen(sptr); temp &= 0xffff; if (temp || i == 3 || addr->ipv6.sin6_addr.s6_addr32[i + 1]) { snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, temp); sptr += strlen(sptr); } } if (i < 4) { while (i < 4 && !addr->ipv6.sin6_addr.s6_addr32[i]) i ++; if (i < 4) { snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s:", prefix); prefix = ":"; sptr += strlen(sptr); for (; i < 4; i ++) { temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]); if ((temp & 0xffff0000) || (i > 0 && addr->ipv6.sin6_addr.s6_addr32[i - 1])) { snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, (temp >> 16) & 0xffff); sptr += strlen(sptr); } snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, temp & 0xffff); sptr += strlen(sptr); } } else if (sptr == s) { /* * Empty address... */ strlcpy(temps, "::", sizeof(temps)); } else { /* * Empty at end... */ strlcpy(sptr, "::", sizeof(temps) - (size_t)(sptr - temps)); } } # endif /* HAVE_GETNAMEINFO */ /* * Add "[v1." and "]" around IPv6 address to convert to URI form. */ snprintf(s, (size_t)slen, "[v1.%s]", temps); } #endif /* AF_INET6 */ else strlcpy(s, "UNKNOWN", (size_t)slen); DEBUG_printf(("1httpAddrString: returning \"%s\"...", s)); return (s); } /* * 'httpGetAddress()' - Get the address of the connected peer of a connection. * * For connections created with @link httpConnect2@, the address is for the * server. For connections created with @link httpAccept@, the address is for * the client. * * Returns @code NULL@ if the socket is currently unconnected. * * @since CUPS 2.0/OS 10.10@ */ http_addr_t * /* O - Connected address or @code NULL@ */ httpGetAddress(http_t *http) /* I - HTTP connection */ { if (http) return (http->hostaddr); else return (NULL); } /* * 'httpGetHostByName()' - Lookup a hostname or IPv4 address, and return * address records for the specified name. * * @deprecated@ @exclude all@ */ struct hostent * /* O - Host entry */ httpGetHostByName(const char *name) /* I - Hostname or IP address */ { const char *nameptr; /* Pointer into name */ unsigned ip[4]; /* IP address components */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ DEBUG_printf(("httpGetHostByName(name=\"%s\")", name)); /* * Avoid lookup delays and configuration problems when connecting * to the localhost address... */ if (!strcmp(name, "localhost")) name = "127.0.0.1"; /* * This function is needed because some operating systems have a * buggy implementation of gethostbyname() that does not support * IP addresses. If the first character of the name string is a * number, then sscanf() is used to extract the IP components. * We then pack the components into an IPv4 address manually, * since the inet_aton() function is deprecated. We use the * htonl() macro to get the right byte order for the address. * * We also support domain sockets when supported by the underlying * OS... */ #ifdef AF_LOCAL if (name[0] == '/') { /* * A domain socket address, so make an AF_LOCAL entry and return it... */ cg->hostent.h_name = (char *)name; cg->hostent.h_aliases = NULL; cg->hostent.h_addrtype = AF_LOCAL; cg->hostent.h_length = (int)strlen(name) + 1; cg->hostent.h_addr_list = cg->ip_ptrs; cg->ip_ptrs[0] = (char *)name; cg->ip_ptrs[1] = NULL; DEBUG_puts("1httpGetHostByName: returning domain socket address..."); return (&cg->hostent); } #endif /* AF_LOCAL */ for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++); if (!*nameptr) { /* * We have an IPv4 address; break it up and provide the host entry * to the caller. */ if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4) return (NULL); /* Must have 4 numbers */ if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255) return (NULL); /* Invalid byte ranges! */ cg->ip_addr = htonl((((((((unsigned)ip[0] << 8) | (unsigned)ip[1]) << 8) | (unsigned)ip[2]) << 8) | (unsigned)ip[3])); /* * Fill in the host entry and return it... */ cg->hostent.h_name = (char *)name; cg->hostent.h_aliases = NULL; cg->hostent.h_addrtype = AF_INET; cg->hostent.h_length = 4; cg->hostent.h_addr_list = cg->ip_ptrs; cg->ip_ptrs[0] = (char *)&(cg->ip_addr); cg->ip_ptrs[1] = NULL; DEBUG_puts("1httpGetHostByName: returning IPv4 address..."); return (&cg->hostent); } else { /* * Use the gethostbyname() function to get the IPv4 address for * the name... */ DEBUG_puts("1httpGetHostByName: returning domain lookup address(es)..."); return (gethostbyname(name)); } } /* * 'httpGetHostname()' - Get the FQDN for the connection or local system. * * When "http" points to a connected socket, return the hostname or * address that was used in the call to httpConnect() or httpConnectEncrypt(), * or the address of the client for the connection from httpAcceptConnection(). * Otherwise, return the FQDN for the local system using both gethostname() * and gethostbyname() to get the local hostname with domain. * * @since CUPS 1.2/macOS 10.5@ */ const char * /* O - FQDN for connection or system */ httpGetHostname(http_t *http, /* I - HTTP connection or NULL */ char *s, /* I - String buffer for name */ int slen) /* I - Size of buffer */ { if (http) { if (!s || slen <= 1) { if (http->hostname[0] == '/') return ("localhost"); else return (http->hostname); } else if (http->hostname[0] == '/') strlcpy(s, "localhost", (size_t)slen); else strlcpy(s, http->hostname, (size_t)slen); } else { /* * Get the hostname... */ if (!s || slen <= 1) return (NULL); if (gethostname(s, (size_t)slen) < 0) strlcpy(s, "localhost", (size_t)slen); if (!strchr(s, '.')) { #ifdef HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME /* * The hostname is not a FQDN, so use the local hostname from the * SystemConfiguration framework... */ SCDynamicStoreRef sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("libcups"), NULL, NULL); /* System configuration data */ CFStringRef local = sc ? SCDynamicStoreCopyLocalHostName(sc) : NULL; /* Local host name */ char localStr[1024]; /* Local host name C string */ if (local && CFStringGetCString(local, localStr, sizeof(localStr), kCFStringEncodingUTF8)) { /* * Append ".local." to the hostname we get... */ snprintf(s, (size_t)slen, "%s.local.", localStr); } if (local) CFRelease(local); if (sc) CFRelease(sc); #else /* * The hostname is not a FQDN, so look it up... */ struct hostent *host; /* Host entry to get FQDN */ if ((host = gethostbyname(s)) != NULL && host->h_name) { /* * Use the resolved hostname... */ strlcpy(s, host->h_name, (size_t)slen); } #endif /* HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME */ } /* * Make sure .local hostnames end with a period... */ if (strlen(s) > 6 && !strcmp(s + strlen(s) - 6, ".local")) strlcat(s, ".", (size_t)slen); } /* * Convert the hostname to lowercase as needed... */ if (s[0] != '/') { char *ptr; /* Pointer into string */ for (ptr = s; *ptr; ptr ++) *ptr = (char)_cups_tolower((int)*ptr); } /* * Return the hostname with as much domain info as we have... */ return (s); } /* * 'httpResolveHostname()' - Resolve the hostname of the HTTP connection * address. * * @since CUPS 2.0/OS 10.10@ */ const char * /* O - Resolved hostname or @code NULL@ */ httpResolveHostname(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Hostname buffer */ size_t bufsize) /* I - Size of buffer */ { if (!http) return (NULL); if (isdigit(http->hostname[0] & 255) || http->hostname[0] == '[') { char temp[1024]; /* Temporary string */ if (httpAddrLookup(http->hostaddr, temp, sizeof(temp))) strlcpy(http->hostname, temp, sizeof(http->hostname)); else return (NULL); } if (buffer) { if (http->hostname[0] == '/') strlcpy(buffer, "localhost", bufsize); else strlcpy(buffer, http->hostname, bufsize); return (buffer); } else if (http->hostname[0] == '/') return ("localhost"); else return (http->hostname); } ippsample/cups/tls.c0000644000175000017500000000372713240604116013470 0ustar tilltill/* * TLS routines for CUPS. * * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by * Jelmer Vernooij. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #include #include #ifdef WIN32 # include #else # include # include # include #endif /* WIN32 */ #ifdef HAVE_POLL # include #endif /* HAVE_POLL */ /* * Local functions... */ #ifdef HAVE_SSL # ifdef HAVE_GNUTLS # include "tls-gnutls.c" # elif defined(HAVE_CDSASSL) # include "tls-darwin.c" # elif defined(HAVE_SSPISSL) # include "tls-sspi.c" # endif /* HAVE_GNUTLS */ #else /* Stubs for when TLS is not supported/available */ int httpCopyCredentials(http_t *http, cups_array_t **credentials) { (void)http; if (credentials) *credentials = NULL; return (-1); } int httpCredentialsAreValidForName(cups_array_t *credentials, const char *common_name) { (void)credentials; (void)common_name; return (1); } time_t httpCredentialsGetExpiration(cups_array_t *credentials) { (void)credentials; return (INT_MAX); } http_trust_t httpCredentialsGetTrust(cups_array_t *credentials, const char *common_name) { (void)credentials; (void)common_name; return (HTTP_TRUST_OK); } size_t httpCredentialsString(cups_array_t *credentials, char *buffer, size_t bufsize) { (void)credentials; (void)bufsize; if (buffer) *buffer = '\0'; return (0); } int httpLoadCredentials(const char *path, cups_array_t **credentials, const char *common_name) { (void)path; (void)credentials; (void)common_name; return (-1); } int httpSaveCredentials(const char *path, cups_array_t *credentials, const char *common_name) { (void)path; (void)credentials; (void)common_name; return (-1); } #endif /* HAVE_SSL */ ippsample/cups/snprintf.c0000644000175000017500000001551213240604116014524 0ustar tilltill/* * snprintf functions for CUPS. * * Copyright 2007-2013 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "string-private.h" #ifndef HAVE_VSNPRINTF /* * '_cups_vsnprintf()' - Format a string into a fixed size buffer. */ int /* O - Number of bytes formatted */ _cups_vsnprintf(char *buffer, /* O - Output buffer */ size_t bufsize, /* O - Size of output buffer */ const char *format, /* I - printf-style format string */ va_list ap) /* I - Pointer to additional arguments */ { char *bufptr, /* Pointer to position in buffer */ *bufend, /* Pointer to end of buffer */ sign, /* Sign of format width */ size, /* Size character (h, l, L) */ type; /* Format type character */ int width, /* Width of field */ prec; /* Number of characters of precision */ char tformat[100], /* Temporary format string for sprintf() */ *tptr, /* Pointer into temporary format */ temp[1024]; /* Buffer for formatted numbers */ size_t templen; /* Length of "temp" */ char *s; /* Pointer to string */ int slen; /* Length of string */ int bytes; /* Total number of bytes needed */ /* * Loop through the format string, formatting as needed... */ bufptr = buffer; bufend = buffer + bufsize - 1; bytes = 0; while (*format) { if (*format == '%') { tptr = tformat; *tptr++ = *format++; if (*format == '%') { if (bufptr && bufptr < bufend) *bufptr++ = *format; bytes ++; format ++; continue; } else if (strchr(" -+#\'", *format)) { *tptr++ = *format; sign = *format++; } else sign = 0; if (*format == '*') { /* * Get width from argument... */ format ++; width = va_arg(ap, int); snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width); tptr += strlen(tptr); } else { width = 0; while (isdigit(*format & 255)) { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; width = width * 10 + *format++ - '0'; } } if (*format == '.') { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; format ++; if (*format == '*') { /* * Get precision from argument... */ format ++; prec = va_arg(ap, int); snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec); tptr += strlen(tptr); } else { prec = 0; while (isdigit(*format & 255)) { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; prec = prec * 10 + *format++ - '0'; } } } else prec = -1; if (*format == 'l' && format[1] == 'l') { size = 'L'; if (tptr < (tformat + sizeof(tformat) - 2)) { *tptr++ = 'l'; *tptr++ = 'l'; } format += 2; } else if (*format == 'h' || *format == 'l' || *format == 'L') { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; size = *format++; } if (!*format) break; if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; type = *format++; *tptr = '\0'; switch (type) { case 'E' : /* Floating point formats */ case 'G' : case 'e' : case 'f' : case 'g' : if ((width + 2) > sizeof(temp)) break; sprintf(temp, tformat, va_arg(ap, double)); templen = strlen(temp): bytes += (int)templen; if (bufptr) { if ((bufptr + templen) > bufend) { strlcpy(bufptr, temp, (size_t)(bufend - bufptr)); bufptr = bufend; } else { memcpy(bufptr, temp, templen + 1); bufptr += templen; } } break; case 'B' : /* Integer formats */ case 'X' : case 'b' : case 'd' : case 'i' : case 'o' : case 'u' : case 'x' : if ((width + 2) > sizeof(temp)) break; sprintf(temp, tformat, va_arg(ap, int)); templen = strlen(temp): bytes += (int)templen; if (bufptr) { if ((bufptr + templen) > bufend) { strlcpy(bufptr, temp, (size_t)(bufend - bufptr)); bufptr = bufend; } else { memcpy(bufptr, temp, templen + 1); bufptr += templen; } } break; case 'p' : /* Pointer value */ if ((width + 2) > sizeof(temp)) break; sprintf(temp, tformat, va_arg(ap, void *)); templen = strlen(temp): bytes += (int)templen; if (bufptr) { if ((bufptr + templen) > bufend) { strlcpy(bufptr, temp, (size_t)(bufend - bufptr)); bufptr = bufend; } else { memcpy(bufptr, temp, templen + 1); bufptr += templen; } } break; case 'c' : /* Character or character array */ bytes += width; if (bufptr) { if (width <= 1) *bufptr++ = va_arg(ap, int); else { if ((bufptr + width) > bufend) width = (int)(bufend - bufptr); memcpy(bufptr, va_arg(ap, char *), (size_t)width); bufptr += width; } } break; case 's' : /* String */ if ((s = va_arg(ap, char *)) == NULL) s = "(null)"; slen = (int)strlen(s); if (slen > width && prec != width) width = slen; bytes += width; if (bufptr) { if ((bufptr + width) > bufend) width = (int)(bufend - bufptr); if (slen > width) slen = width; if (sign == '-') { memcpy(bufptr, s, (size_t)slen); memset(bufptr + slen, ' ', (size_t)(width - slen)); } else { memset(bufptr, ' ', (size_t)(width - slen)); memcpy(bufptr + width - slen, s, (size_t)slen); } bufptr += width; } break; case 'n' : /* Output number of chars so far */ *(va_arg(ap, int *)) = bytes; break; } } else { bytes ++; if (bufptr && bufptr < bufend) *bufptr++ = *format; format ++; } } /* * Nul-terminate the string and return the number of characters needed. */ *bufptr = '\0'; return (bytes); } #endif /* !HAVE_VSNPRINT */ #ifndef HAVE_SNPRINTF /* * '_cups_snprintf()' - Format a string into a fixed size buffer. */ int /* O - Number of bytes formatted */ _cups_snprintf(char *buffer, /* O - Output buffer */ size_t bufsize, /* O - Size of output buffer */ const char *format, /* I - printf-style format string */ ...) /* I - Additional arguments as needed */ { int bytes; /* Number of bytes formatted */ va_list ap; /* Pointer to additional arguments */ va_start(ap, format); bytes = vsnprintf(buffer, bufsize, format, ap); va_end(ap); return (bytes); } #endif /* !HAVE_SNPRINTF */ ippsample/cups/ipp.h0000644000175000017500000015702213240604116013461 0ustar tilltill/* * Internet Printing Protocol definitions for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_IPP_H_ # define _CUPS_IPP_H_ /* * Include necessary headers... */ # include "http.h" # include /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * IPP version string... */ # define IPP_VERSION "\002\001" /* * IPP registered port number... * * Note: Applications should never use IPP_PORT, but instead use the * ippPort() function to allow overrides via the IPP_PORT environment * variable and services file if needed! */ # define IPP_PORT 631 /* * Common limits... */ # define IPP_MAX_CHARSET 64 /* Maximum length of charset values w/nul */ # define IPP_MAX_KEYWORD 256 /* Maximum length of keyword values w/nul */ # define IPP_MAX_LANGUAGE 64 /* Maximum length of naturalLanguage values w/nul */ # define IPP_MAX_LENGTH 32767 /* Maximum size of any single value */ # define IPP_MAX_MIMETYPE 256 /* Maximum length of mimeMediaType values w/nul */ # define IPP_MAX_NAME 256 /* Maximum length of common name values w/nul */ # define IPP_MAX_OCTETSTRING 1023 /* Maximum length of octetString values w/o nul */ # define IPP_MAX_TEXT 1024 /* Maximum length of text values w/nul */ # define IPP_MAX_URI 1024 /* Maximum length of uri values w/nul */ # define IPP_MAX_URISCHEME 64 /* Maximum length of uriScheme values w/nul */ # define IPP_MAX_VALUES 8 /* Power-of-2 allocation increment */ /* * Macro to flag a text string attribute as "const" (static storage) vs. * allocated. */ # define IPP_CONST_TAG(x) (ipp_tag_t)(IPP_TAG_CUPS_CONST | (x)) /* * Types and structures... */ typedef enum ipp_dstate_e /**** Document states @exclude all@ ****/ { IPP_DOCUMENT_PENDING = 3, /* Document is pending */ IPP_DOCUMENT_PROCESSING = 5, /* Document is processing */ IPP_DOCUMENT_CANCELED = 7, /* Document is canceled */ IPP_DOCUMENT_ABORTED, /* Document is aborted */ IPP_DOCUMENT_COMPLETED /* Document is completed */ # ifndef _CUPS_NO_DEPRECATED # define IPP_DOCUMENT_PENDING IPP_DSTATE_PENDING # define IPP_DOCUMENT_PROCESSING IPP_DSTATE_PROCESSING # define IPP_DOCUMENT_CANCELED IPP_DSTATE_CANCELED # define IPP_DOCUMENT_ABORTED IPP_DSTATE_ABORTED # define IPP_DOCUMENT_COMPLETED IPP_DSTATE_COMPLETED # endif /* !_CUPS_NO_DEPRECATED */ } ipp_dstate_t; typedef enum ipp_finishings_e /**** Finishings values ****/ { IPP_FINISHINGS_NONE = 3, /* No finishing */ IPP_FINISHINGS_STAPLE, /* Staple (any location/method) */ IPP_FINISHINGS_PUNCH, /* Punch (any location/count) */ IPP_FINISHINGS_COVER, /* Add cover */ IPP_FINISHINGS_BIND, /* Bind */ IPP_FINISHINGS_SADDLE_STITCH, /* Staple interior */ IPP_FINISHINGS_EDGE_STITCH, /* Stitch along any side */ IPP_FINISHINGS_FOLD, /* Fold (any type) */ IPP_FINISHINGS_TRIM, /* Trim (any type) */ IPP_FINISHINGS_BALE, /* Bale (any type) */ IPP_FINISHINGS_BOOKLET_MAKER, /* Fold to make booklet */ IPP_FINISHINGS_JOG_OFFSET, /* Offset for binding (any type) */ IPP_FINISHINGS_COAT, /* Apply protective liquid or powder coating */ IPP_FINISHINGS_LAMINATE, /* Apply protective (solid) material */ IPP_FINISHINGS_STAPLE_TOP_LEFT = 20, /* Staple top left corner */ IPP_FINISHINGS_STAPLE_BOTTOM_LEFT, /* Staple bottom left corner */ IPP_FINISHINGS_STAPLE_TOP_RIGHT, /* Staple top right corner */ IPP_FINISHINGS_STAPLE_BOTTOM_RIGHT, /* Staple bottom right corner */ IPP_FINISHINGS_EDGE_STITCH_LEFT, /* Stitch along left side */ IPP_FINISHINGS_EDGE_STITCH_TOP, /* Stitch along top edge */ IPP_FINISHINGS_EDGE_STITCH_RIGHT, /* Stitch along right side */ IPP_FINISHINGS_EDGE_STITCH_BOTTOM, /* Stitch along bottom edge */ IPP_FINISHINGS_STAPLE_DUAL_LEFT, /* Two staples on left */ IPP_FINISHINGS_STAPLE_DUAL_TOP, /* Two staples on top */ IPP_FINISHINGS_STAPLE_DUAL_RIGHT, /* Two staples on right */ IPP_FINISHINGS_STAPLE_DUAL_BOTTOM, /* Two staples on bottom */ IPP_FINISHINGS_STAPLE_TRIPLE_LEFT, /* Three staples on left */ IPP_FINISHINGS_STAPLE_TRIPLE_TOP, /* Three staples on top */ IPP_FINISHINGS_STAPLE_TRIPLE_RIGHT, /* Three staples on right */ IPP_FINISHINGS_STAPLE_TRIPLE_BOTTOM, /* Three staples on bottom */ IPP_FINISHINGS_BIND_LEFT = 50, /* Bind on left */ IPP_FINISHINGS_BIND_TOP, /* Bind on top */ IPP_FINISHINGS_BIND_RIGHT, /* Bind on right */ IPP_FINISHINGS_BIND_BOTTOM, /* Bind on bottom */ IPP_FINISHINGS_TRIM_AFTER_PAGES = 60, /* Trim output after each page */ IPP_FINISHINGS_TRIM_AFTER_DOCUMENTS, /* Trim output after each document */ IPP_FINISHINGS_TRIM_AFTER_COPIES, /* Trim output after each copy */ IPP_FINISHINGS_TRIM_AFTER_JOB, /* Trim output after job */ IPP_FINISHINGS_PUNCH_TOP_LEFT = 70, /* Punch 1 hole top left */ IPP_FINISHINGS_PUNCH_BOTTOM_LEFT, /* Punch 1 hole bottom left */ IPP_FINISHINGS_PUNCH_TOP_RIGHT, /* Punch 1 hole top right */ IPP_FINISHINGS_PUNCH_BOTTOM_RIGHT, /* Punch 1 hole bottom right */ IPP_FINISHINGS_PUNCH_DUAL_LEFT, /* Punch 2 holes left side */ IPP_FINISHINGS_PUNCH_DUAL_TOP, /* Punch 2 holes top edge */ IPP_FINISHINGS_PUNCH_DUAL_RIGHT, /* Punch 2 holes right side */ IPP_FINISHINGS_PUNCH_DUAL_BOTTOM, /* Punch 2 holes bottom edge */ IPP_FINISHINGS_PUNCH_TRIPLE_LEFT, /* Punch 3 holes left side */ IPP_FINISHINGS_PUNCH_TRIPLE_TOP, /* Punch 3 holes top edge */ IPP_FINISHINGS_PUNCH_TRIPLE_RIGHT, /* Punch 3 holes right side */ IPP_FINISHINGS_PUNCH_TRIPLE_BOTTOM, /* Punch 3 holes bottom edge */ IPP_FINISHINGS_PUNCH_QUAD_LEFT, /* Punch 4 holes left side */ IPP_FINISHINGS_PUNCH_QUAD_TOP, /* Punch 4 holes top edge */ IPP_FINISHINGS_PUNCH_QUAD_RIGHT, /* Punch 4 holes right side */ IPP_FINISHINGS_PUNCH_QUAD_BOTTOM, /* Punch 4 holes bottom edge */ IPP_FINISHINGS_PUNCH_MULTIPLE_LEFT, /* Pucnh multiple holes left side */ IPP_FINISHINGS_PUNCH_MULTIPLE_TOP, /* Pucnh multiple holes top edge */ IPP_FINISHINGS_PUNCH_MULTIPLE_RIGHT, /* Pucnh multiple holes right side */ IPP_FINISHINGS_PUNCH_MULTIPLE_BOTTOM, /* Pucnh multiple holes bottom edge */ IPP_FINISHINGS_FOLD_ACCORDIAN = 90, /* Accordian-fold the paper vertically into four sections */ IPP_FINISHINGS_FOLD_DOUBLE_GATE, /* Fold the top and bottom quarters of the paper towards the midline, then fold in half vertically */ IPP_FINISHINGS_FOLD_GATE, /* Fold the top and bottom quarters of the paper towards the midline */ IPP_FINISHINGS_FOLD_HALF, /* Fold the paper in half vertically */ IPP_FINISHINGS_FOLD_HALF_Z, /* Fold the paper in half horizontally, then Z-fold the paper vertically */ IPP_FINISHINGS_FOLD_LEFT_GATE, /* Fold the top quarter of the paper towards the midline */ IPP_FINISHINGS_FOLD_LETTER, /* Fold the paper into three sections vertically; sometimes also known as a C fold*/ IPP_FINISHINGS_FOLD_PARALLEL, /* Fold the paper in half vertically two times, yielding four sections */ IPP_FINISHINGS_FOLD_POSTER, /* Fold the paper in half horizontally and vertically; sometimes also called a cross fold */ IPP_FINISHINGS_FOLD_RIGHT_GATE, /* Fold the bottom quarter of the paper towards the midline */ IPP_FINISHINGS_FOLD_Z, /* Fold the paper vertically into three sections, forming a Z */ IPP_FINISHINGS_FOLD_ENGINEERING_Z, /* Fold the paper vertically into two small sections and one larger, forming an elongated Z */ /* CUPS extensions for finishings (pre-standard versions of values above) */ IPP_FINISHINGS_CUPS_PUNCH_TOP_LEFT = 0x40000046, /* Punch 1 hole top left @exclude all@ */ IPP_FINISHINGS_CUPS_PUNCH_BOTTOM_LEFT,/* Punch 1 hole bottom left @exclude all@ */ IPP_FINISHINGS_CUPS_PUNCH_TOP_RIGHT, /* Punch 1 hole top right @exclude all@ */ IPP_FINISHINGS_CUPS_PUNCH_BOTTOM_RIGHT, /* Punch 1 hole bottom right @exclude all@ */ IPP_FINISHINGS_CUPS_PUNCH_DUAL_LEFT, /* Punch 2 holes left side @exclude all@ */ IPP_FINISHINGS_CUPS_PUNCH_DUAL_TOP, /* Punch 2 holes top edge @exclude all@ */ IPP_FINISHINGS_CUPS_PUNCH_DUAL_RIGHT, /* Punch 2 holes right side @exclude all@ */ IPP_FINISHINGS_CUPS_PUNCH_DUAL_BOTTOM,/* Punch 2 holes bottom edge @exclude all@ */ IPP_FINISHINGS_CUPS_PUNCH_TRIPLE_LEFT,/* Punch 3 holes left side @exclude all@ */ IPP_FINISHINGS_CUPS_PUNCH_TRIPLE_TOP, /* Punch 3 holes top edge @exclude all@ */ IPP_FINISHINGS_CUPS_PUNCH_TRIPLE_RIGHT, /* Punch 3 holes right side @exclude all@ */ IPP_FINISHINGS_CUPS_PUNCH_TRIPLE_BOTTOM, /* Punch 3 holes bottom edge @exclude all@ */ IPP_FINISHINGS_CUPS_PUNCH_QUAD_LEFT, /* Punch 4 holes left side @exclude all@ */ IPP_FINISHINGS_CUPS_PUNCH_QUAD_TOP, /* Punch 4 holes top edge @exclude all@ */ IPP_FINISHINGS_CUPS_PUNCH_QUAD_RIGHT, /* Punch 4 holes right side @exclude all@ */ IPP_FINISHINGS_CUPS_PUNCH_QUAD_BOTTOM,/* Punch 4 holes bottom edge @exclude all@ */ IPP_FINISHINGS_CUPS_FOLD_ACCORDIAN = 0x4000005A, /* Accordian-fold the paper vertically into four sections @exclude all@ */ IPP_FINISHINGS_CUPS_FOLD_DOUBLE_GATE, /* Fold the top and bottom quarters of the paper towards the midline, then fold in half vertically @exclude all@ */ IPP_FINISHINGS_CUPS_FOLD_GATE, /* Fold the top and bottom quarters of the paper towards the midline @exclude all@ */ IPP_FINISHINGS_CUPS_FOLD_HALF, /* Fold the paper in half vertically @exclude all@ */ IPP_FINISHINGS_CUPS_FOLD_HALF_Z, /* Fold the paper in half horizontally, then Z-fold the paper vertically @exclude all@ */ IPP_FINISHINGS_CUPS_FOLD_LEFT_GATE, /* Fold the top quarter of the paper towards the midline @exclude all@ */ IPP_FINISHINGS_CUPS_FOLD_LETTER, /* Fold the paper into three sections vertically; sometimes also known as a C fold @exclude all@ */ IPP_FINISHINGS_CUPS_FOLD_PARALLEL, /* Fold the paper in half vertically two times, yielding four sections @exclude all@ */ IPP_FINISHINGS_CUPS_FOLD_POSTER, /* Fold the paper in half horizontally and vertically; sometimes also called a cross fold @exclude all@ */ IPP_FINISHINGS_CUPS_FOLD_RIGHT_GATE, /* Fold the bottom quarter of the paper towards the midline @exclude all@ */ IPP_FINISHINGS_CUPS_FOLD_Z /* Fold the paper vertically into three sections, forming a Z @exclude all@ */ } ipp_finishings_t; # ifndef _CUPS_NO_DEPRECATED # define IPP_FINISHINGS_JOB_OFFSET IPP_FINISHINGS_JOG_OFFSET /* Long-time misspelling... */ typedef enum ipp_finishings_e ipp_finish_t; # endif /* !_CUPS_NO_DEPRECATED */ typedef enum ipp_jcollate_e /**** Job collation types @deprecated@ @exclude all@ ****/ { IPP_JCOLLATE_UNCOLLATED_SHEETS = 3, IPP_JCOLLATE_COLLATED_DOCUMENTS, IPP_JCOLLATE_UNCOLLATED_DOCUMENTS # ifndef _CUPS_NO_DEPRECATED # define IPP_JOB_UNCOLLATED_SHEETS IPP_JCOLLATE_UNCOLLATED_SHEETS # define IPP_JOB_COLLATED_DOCUMENTS IPP_JCOLLATE_COLLATED_DOCUMENTS # define IPP_JOB_UNCOLLATED_DOCUMENTS IPP_JCOLLATE_UNCOLLATED_DOCUMENTS # endif /* !_CUPS_NO_DEPRECATED */ } ipp_jcollate_t; typedef enum ipp_jstate_e /**** Job states ****/ { IPP_JSTATE_PENDING = 3, /* Job is waiting to be printed */ IPP_JSTATE_HELD, /* Job is held for printing */ IPP_JSTATE_PROCESSING, /* Job is currently printing */ IPP_JSTATE_STOPPED, /* Job has been stopped */ IPP_JSTATE_CANCELED, /* Job has been canceled */ IPP_JSTATE_ABORTED, /* Job has aborted due to error */ IPP_JSTATE_COMPLETED /* Job has completed successfully */ # ifndef _CUPS_NO_DEPRECATED # define IPP_JOB_PENDING IPP_JSTATE_PENDING # define IPP_JOB_HELD IPP_JSTATE_HELD # define IPP_JOB_PROCESSING IPP_JSTATE_PROCESSING # define IPP_JOB_STOPPED IPP_JSTATE_STOPPED # define IPP_JOB_CANCELED IPP_JSTATE_CANCELED # define IPP_JOB_ABORTED IPP_JSTATE_ABORTED # define IPP_JOB_COMPLETED IPP_JSTATE_COMPLETED /* Legacy name for canceled state */ # define IPP_JOB_CANCELLED IPP_JSTATE_CANCELED # endif /* !_CUPS_NO_DEPRECATED */ } ipp_jstate_t; typedef enum ipp_op_e /**** IPP operations ****/ { IPP_OP_CUPS_INVALID = -1, /* Invalid operation name for @link ippOpValue@ */ IPP_OP_CUPS_NONE = 0, /* No operation @private@ */ IPP_OP_PRINT_JOB = 0x0002, /* Print-Job: Print a single file */ IPP_OP_PRINT_URI, /* Print-URI: Print a single URL @exclude all@ */ IPP_OP_VALIDATE_JOB, /* Validate-Job: Validate job values prior to submission */ IPP_OP_CREATE_JOB, /* Create-Job: Create an empty print job */ IPP_OP_SEND_DOCUMENT, /* Send-Document: Add a file to a job */ IPP_OP_SEND_URI, /* Send-URI: Add a URL to a job @exclude all@ */ IPP_OP_CANCEL_JOB, /* Cancel-Job: Cancel a job */ IPP_OP_GET_JOB_ATTRIBUTES, /* Get-Job-Attribute: Get information about a job */ IPP_OP_GET_JOBS, /* Get-Jobs: Get a list of jobs */ IPP_OP_GET_PRINTER_ATTRIBUTES, /* Get-Printer-Attributes: Get information about a printer */ IPP_OP_HOLD_JOB, /* Hold-Job: Hold a job for printing */ IPP_OP_RELEASE_JOB, /* Release-Job: Release a job for printing */ IPP_OP_RESTART_JOB, /* Restart-Job: Reprint a job @deprecated@ */ IPP_OP_PAUSE_PRINTER = 0x0010, /* Pause-Printer: Stop a printer */ IPP_OP_RESUME_PRINTER, /* Resume-Printer: Start a printer */ IPP_OP_PURGE_JOBS, /* Purge-Jobs: Delete all jobs @deprecated@ @exclude all@ */ IPP_OP_SET_PRINTER_ATTRIBUTES, /* Set-Printer-Attributes: Set printer values */ IPP_OP_SET_JOB_ATTRIBUTES, /* Set-Job-Attributes: Set job values */ IPP_OP_GET_PRINTER_SUPPORTED_VALUES, /* Get-Printer-Supported-Values: Get supported values */ IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS, /* Create-Printer-Subscriptions: Create one or more printer subscriptions @since CUPS 1.2/macOS 10.5@ */ IPP_OP_CREATE_JOB_SUBSCRIPTIONS, /* Create-Job-Subscriptions: Create one of more job subscriptions @since CUPS 1.2/macOS 10.5@ */ IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES, /* Get-Subscription-Attributes: Get subscription information @since CUPS 1.2/macOS 10.5@ */ IPP_OP_GET_SUBSCRIPTIONS, /* Get-Subscriptions: Get list of subscriptions @since CUPS 1.2/macOS 10.5@ */ IPP_OP_RENEW_SUBSCRIPTION, /* Renew-Subscription: Renew a printer subscription @since CUPS 1.2/macOS 10.5@ */ IPP_OP_CANCEL_SUBSCRIPTION, /* Cancel-Subscription: Cancel a subscription @since CUPS 1.2/macOS 10.5@ */ IPP_OP_GET_NOTIFICATIONS, /* Get-Notifications: Get notification events @since CUPS 1.2/macOS 10.5@ */ IPP_OP_SEND_NOTIFICATIONS, /* Send-Notifications: Send notification events @private@ */ IPP_OP_GET_RESOURCE_ATTRIBUTES, /* Get-Resource-Attributes: Get resource information @private@ */ IPP_OP_GET_RESOURCE_DATA, /* Get-Resource-Data: Get resource data @private@ @deprecated@ */ IPP_OP_GET_RESOURCES, /* Get-Resources: Get list of resources @private@ */ IPP_OP_GET_PRINT_SUPPORT_FILES, /* Get-Printer-Support-Files: Get printer support files @private@ */ IPP_OP_ENABLE_PRINTER, /* Enable-Printer: Accept new jobs for a printer */ IPP_OP_DISABLE_PRINTER, /* Disable-Printer: Reject new jobs for a printer */ IPP_OP_PAUSE_PRINTER_AFTER_CURRENT_JOB, /* Pause-Printer-After-Current-Job: Stop printer after the current job */ IPP_OP_HOLD_NEW_JOBS, /* Hold-New-Jobs: Hold new jobs */ IPP_OP_RELEASE_HELD_NEW_JOBS, /* Release-Held-New-Jobs: Release new jobs that were previously held */ IPP_OP_DEACTIVATE_PRINTER, /* Deactivate-Printer: Stop a printer and do not accept jobs @deprecated@ @exclude all@ */ IPP_OP_ACTIVATE_PRINTER, /* Activate-Printer: Start a printer and accept jobs @deprecated@ @exclude all@ */ IPP_OP_RESTART_PRINTER, /* Restart-Printer: Restart a printer @exclude all@ */ IPP_OP_SHUTDOWN_PRINTER, /* Shutdown-Printer: Turn a printer off @exclude all@ */ IPP_OP_STARTUP_PRINTER, /* Startup-Printer: Turn a printer on @exclude all@ */ IPP_OP_REPROCESS_JOB, /* Reprocess-Job: Reprint a job @deprecated@ @exclude all@*/ IPP_OP_CANCEL_CURRENT_JOB, /* Cancel-Current-Job: Cancel the current job */ IPP_OP_SUSPEND_CURRENT_JOB, /* Suspend-Current-Job: Suspend the current job */ IPP_OP_RESUME_JOB, /* Resume-Job: Resume the current job */ IPP_OP_PROMOTE_JOB, /* Promote-Job: Promote a job to print sooner */ IPP_OP_SCHEDULE_JOB_AFTER, /* Schedule-Job-After: Schedule a job to print after another */ IPP_OP_CANCEL_DOCUMENT = 0x0033, /* Cancel-Document: Cancel a document @exclude all@ */ IPP_OP_GET_DOCUMENT_ATTRIBUTES, /* Get-Document-Attributes: Get document information @exclude all@ */ IPP_OP_GET_DOCUMENTS, /* Get-Documents: Get a list of documents in a job @exclude all@ */ IPP_OP_DELETE_DOCUMENT, /* Delete-Document: Delete a document @deprecated@ @exclude all@ */ IPP_OP_SET_DOCUMENT_ATTRIBUTES, /* Set-Document-Attributes: Set document values @exclude all@ */ IPP_OP_CANCEL_JOBS, /* Cancel-Jobs: Cancel all jobs (administrative) */ IPP_OP_CANCEL_MY_JOBS, /* Cancel-My-Jobs: Cancel a user's jobs */ IPP_OP_RESUBMIT_JOB, /* Resubmit-Job: Copy and reprint a job @exclude all@ */ IPP_OP_CLOSE_JOB, /* Close-Job: Close a job and start printing */ IPP_OP_IDENTIFY_PRINTER, /* Identify-Printer: Make the printer beep, flash, or display a message for identification */ IPP_OP_VALIDATE_DOCUMENT, /* Validate-Document: Validate document values prior to submission @exclude all@ */ IPP_OP_ADD_DOCUMENT_IMAGES, /* Add-Document-Images: Add image(s) from the specified scanner source @exclude all@ */ IPP_OP_ACKNOWLEDGE_DOCUMENT, /* Acknowledge-Document: Acknowledge processing of a document @exclude all@ */ IPP_OP_ACKNOWLEDGE_IDENTIFY_PRINTER, /* Acknowledge-Identify-Printer: Acknowledge action on an Identify-Printer request @exclude all@ */ IPP_OP_ACKNOWLEDGE_JOB, /* Acknowledge-Job: Acknowledge processing of a job @exclude all@ */ IPP_OP_FETCH_DOCUMENT, /* Fetch-Document: Fetch a document for processing @exclude all@ */ IPP_OP_FETCH_JOB, /* Fetch-Job: Fetch a job for processing @exclude all@ */ IPP_OP_GET_OUTPUT_DEVICE_ATTRIBUTES, /* Get-Output-Device-Attributes: Get printer information for a specific output device @exclude all@ */ IPP_OP_UPDATE_ACTIVE_JOBS, /* Update-Active-Jobs: Update the list of active jobs that a proxy has processed @exclude all@ */ IPP_OP_DEREGISTER_OUTPUT_DEVICE, /* Deregister-Output-Device: Remove an output device @exclude all@ */ IPP_OP_UPDATE_DOCUMENT_STATUS, /* Update-Document-Status: Update document values @exclude all@ */ IPP_OP_UPDATE_JOB_STATUS, /* Update-Job-Status: Update job values @exclude all@ */ IPP_OP_UPDATE_OUTPUT_DEVICE_ATTRIBUTES, /* Update-Output-Device-Attributes: Update output device values @exclude all@ */ IPP_OP_GET_NEXT_DOCUMENT_DATA, /* Get-Next-Document-Data: Scan more document data @exclude all@ */ IPP_OP_ALLOCATE_PRINTER_RESOURCES, /* Allocate-Printer-Resources: Use resources for a printer. */ IPP_OP_CREATE_PRINTER, /* Create-Printer: Create a new service. */ IPP_OP_DEALLOCATE_PRINTER_RESOURCES, /* Deallocate-Printer-Resources: Stop using resources for a printer. */ IPP_OP_DELETE_PRINTER, /* Delete-Printer: Delete an existing service. */ IPP_OP_GET_PRINTERS, /* Get-Printers: Get a list of services. */ IPP_OP_SHUTDOWN_ONE_PRINTER, /* Shutdown-One-Printer: Shutdown a service. */ IPP_OP_STARTUP_ONE_PRINTER, /* Startup-One-Printer: Start a service. */ IPP_OP_CANCEL_RESOURCE, /* Cancel-Resource: Uninstall a resource. */ IPP_OP_CREATE_RESOURCE, /* Create-Resource: Create a new (empty) resource. */ IPP_OP_INSTALL_RESOURCE, /* Install-Resource: Install a resource. */ IPP_OP_SEND_RESOURCE_DATA, /* Send-Resource-Data: Upload the data for a resource. */ IPP_OP_SET_RESOURCE_ATTRIBUTES, /* Set-Resource-Attributes: Set resource object attributes. */ IPP_OP_CREATE_RESOURCE_SUBSCRIPTIONS, /* Create-Resource-Subscriptions: Create event subscriptions for a resource. */ IPP_OP_CREATE_SYSTEM_SUBSCRIPTIONS, /* Create-System-Subscriptions: Create event subscriptions for a system. */ IPP_OP_DISABLE_ALL_PRINTERS, /* Disable-All-Printers: Stop accepting new jobs on all services. */ IPP_OP_ENABLE_ALL_PRINTERS, /* Enable-All-Printers: Start accepting new jobs on all services. */ IPP_OP_GET_SYSTEM_ATTRIBUTES, /* Get-System-Attributes: Get system object attributes. */ IPP_OP_GET_SYSTEM_SUPPORTED_VALUES, /* Get-System-Supported-Values: Get supported values for system object attributes. */ IPP_OP_PAUSE_ALL_PRINTERS, /* Pause-All-Printers: Stop all services immediately. */ IPP_OP_PAUSE_ALL_PRINTERS_AFTER_CURRENT_JOB, /* Pause-All-Printers-After-Current-Job: Stop all services after processing the current jobs. */ IPP_OP_REGISTER_OUTPUT_DEVICE, /* Register-Output-Device: Register a remote service. */ IPP_OP_RESTART_SYSTEM, /* Restart-System: Restart all services. */ IPP_OP_RESUME_ALL_PRINTERS, /* Resume-All-Printers: Start job processing on all services. */ IPP_OP_SET_SYSTEM_ATTRIBUTES, /* Set-System-Attributes: Set system object attributes. */ IPP_OP_SHUTDOWN_ALL_PRINTERS, /* Shutdown-All-Printers: Shutdown all services. */ IPP_OP_STARTUP_ALL_PRINTERS, /* Startup-All-Printers: Startup all services. */ IPP_OP_PRIVATE = 0x4000, /* Reserved @private@ */ IPP_OP_CUPS_GET_DEFAULT, /* CUPS-Get-Default: Get the default printer */ IPP_OP_CUPS_GET_PRINTERS, /* CUPS-Get-Printers: Get a list of printers and/or classes */ IPP_OP_CUPS_ADD_MODIFY_PRINTER, /* CUPS-Add-Modify-Printer: Add or modify a printer */ IPP_OP_CUPS_DELETE_PRINTER, /* CUPS-Delete-Printer: Delete a printer */ IPP_OP_CUPS_GET_CLASSES, /* CUPS-Get-Classes: Get a list of classes @deprecated@ @exclude all@ */ IPP_OP_CUPS_ADD_MODIFY_CLASS, /* CUPS-Add-Modify-Class: Add or modify a class */ IPP_OP_CUPS_DELETE_CLASS, /* CUPS-Delete-Class: Delete a class */ IPP_OP_CUPS_ACCEPT_JOBS, /* CUPS-Accept-Jobs: Accept new jobs on a printer @exclude all@ */ IPP_OP_CUPS_REJECT_JOBS, /* CUPS-Reject-Jobs: Reject new jobs on a printer @exclude all@ */ IPP_OP_CUPS_SET_DEFAULT, /* CUPS-Set-Default: Set the default printer */ IPP_OP_CUPS_GET_DEVICES, /* CUPS-Get-Devices: Get a list of supported devices @deprecated@ */ IPP_OP_CUPS_GET_PPDS, /* CUPS-Get-PPDs: Get a list of supported drivers @deprecated@ */ IPP_OP_CUPS_MOVE_JOB, /* CUPS-Move-Job: Move a job to a different printer */ IPP_OP_CUPS_AUTHENTICATE_JOB, /* CUPS-Authenticate-Job: Authenticate a job @since CUPS 1.2/macOS 10.5@ */ IPP_OP_CUPS_GET_PPD, /* CUPS-Get-PPD: Get a PPD file @deprecated@ */ IPP_OP_CUPS_GET_DOCUMENT = 0x4027, /* CUPS-Get-Document: Get a document file @since CUPS 1.4/macOS 10.6@ */ IPP_OP_CUPS_CREATE_LOCAL_PRINTER /* CUPS-Create-Local-Printer: Create a local (temporary) printer @since CUPS 2.2@ */ # ifndef _CUPS_NO_DEPRECATED # define IPP_PRINT_JOB IPP_OP_PRINT_JOB # define IPP_PRINT_URI IPP_OP_PRINT_URI # define IPP_VALIDATE_JOB IPP_OP_VALIDATE_JOB # define IPP_CREATE_JOB IPP_OP_CREATE_JOB # define IPP_SEND_DOCUMENT IPP_OP_SEND_DOCUMENT # define IPP_SEND_URI IPP_OP_SEND_URI # define IPP_CANCEL_JOB IPP_OP_CANCEL_JOB # define IPP_GET_JOB_ATTRIBUTES IPP_OP_GET_JOB_ATTRIBUTES # define IPP_GET_JOBS IPP_OP_GET_JOBS # define IPP_GET_PRINTER_ATTRIBUTES IPP_OP_GET_PRINTER_ATTRIBUTES # define IPP_HOLD_JOB IPP_OP_HOLD_JOB # define IPP_RELEASE_JOB IPP_OP_RELEASE_JOB # define IPP_RESTART_JOB IPP_OP_RESTART_JOB # define IPP_PAUSE_PRINTER IPP_OP_PAUSE_PRINTER # define IPP_RESUME_PRINTER IPP_OP_RESUME_PRINTER # define IPP_PURGE_JOBS IPP_OP_PURGE_JOBS # define IPP_SET_PRINTER_ATTRIBUTES IPP_OP_SET_PRINTER_ATTRIBUTES # define IPP_SET_JOB_ATTRIBUTES IPP_OP_SET_JOB_ATTRIBUTES # define IPP_GET_PRINTER_SUPPORTED_VALUES IPP_OP_GET_PRINTER_SUPPORTED_VALUES # define IPP_CREATE_PRINTER_SUBSCRIPTION IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS # define IPP_CREATE_JOB_SUBSCRIPTION IPP_OP_CREATE_JOB_SUBSCRIPTIONS # define IPP_OP_CREATE_PRINTER_SUBSCRIPTION IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS # define IPP_OP_CREATE_JOB_SUBSCRIPTION IPP_OP_CREATE_JOB_SUBSCRIPTIONS # define IPP_GET_SUBSCRIPTION_ATTRIBUTES IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES # define IPP_GET_SUBSCRIPTIONS IPP_OP_GET_SUBSCRIPTIONS # define IPP_RENEW_SUBSCRIPTION IPP_OP_RENEW_SUBSCRIPTION # define IPP_CANCEL_SUBSCRIPTION IPP_OP_CANCEL_SUBSCRIPTION # define IPP_GET_NOTIFICATIONS IPP_OP_GET_NOTIFICATIONS # define IPP_SEND_NOTIFICATIONS IPP_OP_SEND_NOTIFICATIONS # define IPP_GET_RESOURCE_ATTRIBUTES IPP_OP_GET_RESOURCE_ATTRIBUTES # define IPP_GET_RESOURCE_DATA IPP_OP_GET_RESOURCE_DATA # define IPP_GET_RESOURCES IPP_OP_GET_RESOURCES # define IPP_GET_PRINT_SUPPORT_FILES IPP_OP_GET_PRINT_SUPPORT_FILES # define IPP_ENABLE_PRINTER IPP_OP_ENABLE_PRINTER # define IPP_DISABLE_PRINTER IPP_OP_DISABLE_PRINTER # define IPP_PAUSE_PRINTER_AFTER_CURRENT_JOB IPP_OP_PAUSE_PRINTER_AFTER_CURRENT_JOB # define IPP_HOLD_NEW_JOBS IPP_OP_HOLD_NEW_JOBS # define IPP_RELEASE_HELD_NEW_JOBS IPP_OP_RELEASE_HELD_NEW_JOBS # define IPP_DEACTIVATE_PRINTER IPP_OP_DEACTIVATE_PRINTER # define IPP_ACTIVATE_PRINTER IPP_OP_ACTIVATE_PRINTER # define IPP_RESTART_PRINTER IPP_OP_RESTART_PRINTER # define IPP_SHUTDOWN_PRINTER IPP_OP_SHUTDOWN_PRINTER # define IPP_STARTUP_PRINTER IPP_OP_STARTUP_PRINTER # define IPP_REPROCESS_JOB IPP_OP_REPROCESS_JOB # define IPP_CANCEL_CURRENT_JOB IPP_OP_CANCEL_CURRENT_JOB # define IPP_SUSPEND_CURRENT_JOB IPP_OP_SUSPEND_CURRENT_JOB # define IPP_RESUME_JOB IPP_OP_RESUME_JOB # define IPP_PROMOTE_JOB IPP_OP_PROMOTE_JOB # define IPP_SCHEDULE_JOB_AFTER IPP_OP_SCHEDULE_JOB_AFTER # define IPP_CANCEL_DOCUMENT IPP_OP_CANCEL_DOCUMENT # define IPP_GET_DOCUMENT_ATTRIBUTES IPP_OP_GET_DOCUMENT_ATTRIBUTES # define IPP_GET_DOCUMENTS IPP_OP_GET_DOCUMENTS # define IPP_DELETE_DOCUMENT IPP_OP_DELETE_DOCUMENT # define IPP_SET_DOCUMENT_ATTRIBUTES IPP_OP_SET_DOCUMENT_ATTRIBUTES # define IPP_CANCEL_JOBS IPP_OP_CANCEL_JOBS # define IPP_CANCEL_MY_JOBS IPP_OP_CANCEL_MY_JOBS # define IPP_RESUBMIT_JOB IPP_OP_RESUBMIT_JOB # define IPP_CLOSE_JOB IPP_OP_CLOSE_JOB # define IPP_IDENTIFY_PRINTER IPP_OP_IDENTIFY_PRINTER # define IPP_VALIDATE_DOCUMENT IPP_OP_VALIDATE_DOCUMENT # define IPP_OP_SEND_HARDCOPY_DOCUMENT IPP_OP_ADD_DOCUMENT_IMAGES # define IPP_PRIVATE IPP_OP_PRIVATE # define CUPS_GET_DEFAULT IPP_OP_CUPS_GET_DEFAULT # define CUPS_GET_PRINTERS IPP_OP_CUPS_GET_PRINTERS # define CUPS_ADD_MODIFY_PRINTER IPP_OP_CUPS_ADD_MODIFY_PRINTER # define CUPS_DELETE_PRINTER IPP_OP_CUPS_DELETE_PRINTER # define CUPS_GET_CLASSES IPP_OP_CUPS_GET_CLASSES # define CUPS_ADD_MODIFY_CLASS IPP_OP_CUPS_ADD_MODIFY_CLASS # define CUPS_DELETE_CLASS IPP_OP_CUPS_DELETE_CLASS # define CUPS_ACCEPT_JOBS IPP_OP_CUPS_ACCEPT_JOBS # define CUPS_REJECT_JOBS IPP_OP_CUPS_REJECT_JOBS # define CUPS_SET_DEFAULT IPP_OP_CUPS_SET_DEFAULT # define CUPS_GET_DEVICES IPP_OP_CUPS_GET_DEVICES # define CUPS_GET_PPDS IPP_OP_CUPS_GET_PPDS # define CUPS_MOVE_JOB IPP_OP_CUPS_MOVE_JOB # define CUPS_AUTHENTICATE_JOB IPP_OP_CUPS_AUTHENTICATE_JOB # define CUPS_GET_PPD IPP_OP_CUPS_GET_PPD # define CUPS_GET_DOCUMENT IPP_OP_CUPS_GET_DOCUMENT /* Legacy names */ # define CUPS_ADD_PRINTER IPP_OP_CUPS_ADD_MODIFY_PRINTER # define CUPS_ADD_CLASS IPP_OP_CUPS_ADD_MODIFY_CLASS # endif /* !_CUPS_NO_DEPRECATED */ } ipp_op_t; typedef enum ipp_orient_e /**** Orientation values ****/ { IPP_ORIENT_PORTRAIT = 3, /* No rotation */ IPP_ORIENT_LANDSCAPE, /* 90 degrees counter-clockwise */ IPP_ORIENT_REVERSE_LANDSCAPE, /* 90 degrees clockwise */ IPP_ORIENT_REVERSE_PORTRAIT, /* 180 degrees */ IPP_ORIENT_NONE /* No rotation */ # ifndef _CUPS_NO_DEPRECATED # define IPP_PORTRAIT IPP_ORIENT_PORTRAIT # define IPP_LANDSCAPE IPP_ORIENT_LANDSCAPE # define IPP_REVERSE_LANDSCAPE IPP_ORIENT_REVERSE_LANDSCAPE # define IPP_REVERSE_PORTRAIT IPP_ORIENT_REVERSE_PORTRAIT # endif /* !_CUPS_NO_DEPRECATED */ } ipp_orient_t; typedef enum ipp_pstate_e /**** Printer state values ****/ { IPP_PSTATE_IDLE = 3, /* Printer is idle */ IPP_PSTATE_PROCESSING, /* Printer is working */ IPP_PSTATE_STOPPED /* Printer is stopped */ # ifndef _CUPS_NO_DEPRECATED # define IPP_PRINTER_IDLE IPP_PSTATE_IDLE # define IPP_PRINTER_PROCESSING IPP_PSTATE_PROCESSING # define IPP_PRINTER_STOPPED IPP_PSTATE_STOPPED # endif /* _CUPS_NO_DEPRECATED */ } ipp_pstate_t; typedef enum ipp_quality_e /**** Print quality values ****/ { IPP_QUALITY_DRAFT = 3, /* Draft quality */ IPP_QUALITY_NORMAL, /* Normal quality */ IPP_QUALITY_HIGH /* High quality */ } ipp_quality_t; typedef enum ipp_res_e /**** Resolution units ****/ { IPP_RES_PER_INCH = 3, /* Pixels per inch */ IPP_RES_PER_CM /* Pixels per centimeter */ } ipp_res_t; typedef enum ipp_state_e /**** ipp_t state values ****/ { IPP_STATE_ERROR = -1, /* An error occurred */ IPP_STATE_IDLE, /* Nothing is happening/request completed */ IPP_STATE_HEADER, /* The request header needs to be sent/received */ IPP_STATE_ATTRIBUTE, /* One or more attributes need to be sent/received */ IPP_STATE_DATA /* IPP request data needs to be sent/received */ # ifndef _CUPS_NO_DEPRECATED # define IPP_ERROR IPP_STATE_ERROR # define IPP_IDLE IPP_STATE_IDLE # define IPP_HEADER IPP_STATE_HEADER # define IPP_ATTRIBUTE IPP_STATE_ATTRIBUTE # define IPP_DATA IPP_STATE_DATA # endif /* !_CUPS_NO_DEPRECATED */ } ipp_state_t; typedef enum ipp_status_e /**** IPP status code values ****/ { IPP_STATUS_CUPS_INVALID = -1, /* Invalid status name for @link ippErrorValue@ */ IPP_STATUS_OK = 0x0000, /* successful-ok */ IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED, /* successful-ok-ignored-or-substituted-attributes */ IPP_STATUS_OK_CONFLICTING, /* successful-ok-conflicting-attributes */ IPP_STATUS_OK_IGNORED_SUBSCRIPTIONS, /* successful-ok-ignored-subscriptions */ IPP_STATUS_OK_IGNORED_NOTIFICATIONS, /* successful-ok-ignored-notifications @private@ */ IPP_STATUS_OK_TOO_MANY_EVENTS, /* successful-ok-too-many-events */ IPP_STATUS_OK_BUT_CANCEL_SUBSCRIPTION,/* successful-ok-but-cancel-subscription @private@ */ IPP_STATUS_OK_EVENTS_COMPLETE, /* successful-ok-events-complete */ IPP_STATUS_REDIRECTION_OTHER_SITE = 0x0200, /* redirection-other-site @private@ */ IPP_STATUS_CUPS_SEE_OTHER = 0x0280, /* cups-see-other @private@ */ IPP_STATUS_ERROR_BAD_REQUEST = 0x0400,/* client-error-bad-request */ IPP_STATUS_ERROR_FORBIDDEN, /* client-error-forbidden */ IPP_STATUS_ERROR_NOT_AUTHENTICATED, /* client-error-not-authenticated */ IPP_STATUS_ERROR_NOT_AUTHORIZED, /* client-error-not-authorized */ IPP_STATUS_ERROR_NOT_POSSIBLE, /* client-error-not-possible */ IPP_STATUS_ERROR_TIMEOUT, /* client-error-timeout */ IPP_STATUS_ERROR_NOT_FOUND, /* client-error-not-found */ IPP_STATUS_ERROR_GONE, /* client-error-gone */ IPP_STATUS_ERROR_REQUEST_ENTITY, /* client-error-request-entity-too-large */ IPP_STATUS_ERROR_REQUEST_VALUE, /* client-error-request-value-too-long */ IPP_STATUS_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED, /* client-error-document-format-not-supported */ IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES,/* client-error-attributes-or-values-not-supported */ IPP_STATUS_ERROR_URI_SCHEME, /* client-error-uri-scheme-not-supported */ IPP_STATUS_ERROR_CHARSET, /* client-error-charset-not-supported */ IPP_STATUS_ERROR_CONFLICTING, /* client-error-conflicting-attributes */ IPP_STATUS_ERROR_COMPRESSION_NOT_SUPPORTED, /* client-error-compression-not-supported */ IPP_STATUS_ERROR_COMPRESSION_ERROR, /* client-error-compression-error */ IPP_STATUS_ERROR_DOCUMENT_FORMAT_ERROR, /* client-error-document-format-error */ IPP_STATUS_ERROR_DOCUMENT_ACCESS, /* client-error-document-access-error */ IPP_STATUS_ERROR_ATTRIBUTES_NOT_SETTABLE, /* client-error-attributes-not-settable */ IPP_STATUS_ERROR_IGNORED_ALL_SUBSCRIPTIONS, /* client-error-ignored-all-subscriptions */ IPP_STATUS_ERROR_TOO_MANY_SUBSCRIPTIONS, /* client-error-too-many-subscriptions */ IPP_STATUS_ERROR_IGNORED_ALL_NOTIFICATIONS, /* client-error-ignored-all-notifications @private@ */ IPP_STATUS_ERROR_PRINT_SUPPORT_FILE_NOT_FOUND, /* client-error-print-support-file-not-found @private@ */ IPP_STATUS_ERROR_DOCUMENT_PASSWORD, /* client-error-document-password-error */ IPP_STATUS_ERROR_DOCUMENT_PERMISSION, /* client-error-document-permission-error */ IPP_STATUS_ERROR_DOCUMENT_SECURITY, /* client-error-document-security-error */ IPP_STATUS_ERROR_DOCUMENT_UNPRINTABLE,/* client-error-document-unprintable-error */ IPP_STATUS_ERROR_ACCOUNT_INFO_NEEDED, /* client-error-account-info-needed */ IPP_STATUS_ERROR_ACCOUNT_CLOSED, /* client-error-account-closed */ IPP_STATUS_ERROR_ACCOUNT_LIMIT_REACHED, /* client-error-account-limit-reached */ IPP_STATUS_ERROR_ACCOUNT_AUTHORIZATION_FAILED, /* client-error-account-authorization-failed */ IPP_STATUS_ERROR_NOT_FETCHABLE, /* client-error-not-fetchable */ /* Legacy status codes for paid printing */ IPP_STATUS_ERROR_CUPS_ACCOUNT_INFO_NEEDED = 0x049C, /* cups-error-account-info-needed @deprecated@ */ IPP_STATUS_ERROR_CUPS_ACCOUNT_CLOSED, /* cups-error-account-closed @deprecate@ */ IPP_STATUS_ERROR_CUPS_ACCOUNT_LIMIT_REACHED, /* cups-error-account-limit-reached @deprecated@ */ IPP_STATUS_ERROR_CUPS_ACCOUNT_AUTHORIZATION_FAILED, /* cups-error-account-authorization-failed @deprecated@ */ IPP_STATUS_ERROR_INTERNAL = 0x0500, /* server-error-internal-error */ IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED, /* server-error-operation-not-supported */ IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, /* server-error-service-unavailable */ IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, /* server-error-version-not-supported */ IPP_STATUS_ERROR_DEVICE, /* server-error-device-error */ IPP_STATUS_ERROR_TEMPORARY, /* server-error-temporary-error */ IPP_STATUS_ERROR_NOT_ACCEPTING_JOBS, /* server-error-not-accepting-jobs */ IPP_STATUS_ERROR_BUSY, /* server-error-busy */ IPP_STATUS_ERROR_JOB_CANCELED, /* server-error-job-canceled */ IPP_STATUS_ERROR_MULTIPLE_JOBS_NOT_SUPPORTED, /* server-error-multiple-document-jobs-not-supported */ IPP_STATUS_ERROR_PRINTER_IS_DEACTIVATED, /* server-error-printer-is-deactivated */ IPP_STATUS_ERROR_TOO_MANY_JOBS, /* server-error-too-many-jobs */ IPP_STATUS_ERROR_TOO_MANY_DOCUMENTS, /* server-error-too-many-documents */ /* These are internal and never sent over the wire... */ IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED = 0x1000, /* cups-authentication-canceled - Authentication canceled by user @since CUPS 1.5/macOS 10.7@ */ IPP_STATUS_ERROR_CUPS_PKI, /* cups-pki-error - Error negotiating a secure connection @since CUPS 1.5/macOS 10.7@ */ IPP_STATUS_ERROR_CUPS_UPGRADE_REQUIRED/* cups-upgrade-required - TLS upgrade required @since CUPS 1.5/macOS 10.7@ */ # ifndef _CUPS_NO_DEPRECATED # define IPP_OK IPP_STATUS_OK # define IPP_OK_SUBST IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED # define IPP_OK_CONFLICT IPP_STATUS_OK_CONFLICTING # define IPP_OK_IGNORED_SUBSCRIPTIONS IPP_STATUS_OK_IGNORED_SUBSCRIPTIONS # define IPP_OK_IGNORED_NOTIFICATIONS IPP_STATUS_OK_IGNORED_NOTIFICATIONS # define IPP_OK_TOO_MANY_EVENTS IPP_STATUS_OK_TOO_MANY_EVENTS # define IPP_OK_BUT_CANCEL_SUBSCRIPTION IPP_STATUS_OK_BUT_CANCEL_SUBSCRIPTION # define IPP_OK_EVENTS_COMPLETE IPP_STATUS_OK_EVENTS_COMPLETE # define IPP_REDIRECTION_OTHER_SITE IPP_STATUS_REDIRECTION_OTHER_SITE # define CUPS_SEE_OTHER IPP_STATUS_CUPS_SEE_OTHER # define IPP_BAD_REQUEST IPP_STATUS_ERROR_BAD_REQUEST # define IPP_FORBIDDEN IPP_STATUS_ERROR_FORBIDDEN # define IPP_NOT_AUTHENTICATED IPP_STATUS_ERROR_NOT_AUTHENTICATED # define IPP_NOT_AUTHORIZED IPP_STATUS_ERROR_NOT_AUTHORIZED # define IPP_NOT_POSSIBLE IPP_STATUS_ERROR_NOT_POSSIBLE # define IPP_TIMEOUT IPP_STATUS_ERROR_TIMEOUT # define IPP_NOT_FOUND IPP_STATUS_ERROR_NOT_FOUND # define IPP_GONE IPP_STATUS_ERROR_GONE # define IPP_REQUEST_ENTITY IPP_STATUS_ERROR_REQUEST_ENTITY # define IPP_REQUEST_VALUE IPP_STATUS_ERROR_REQUEST_VALUE # define IPP_DOCUMENT_FORMAT IPP_STATUS_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED # define IPP_ATTRIBUTES IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES # define IPP_URI_SCHEME IPP_STATUS_ERROR_URI_SCHEME # define IPP_CHARSET IPP_STATUS_ERROR_CHARSET # define IPP_CONFLICT IPP_STATUS_ERROR_CONFLICTING # define IPP_COMPRESSION_NOT_SUPPORTED IPP_STATUS_ERROR_COMPRESSION_NOT_SUPPORTED # define IPP_COMPRESSION_ERROR IPP_STATUS_ERROR_COMPRESSION_ERROR # define IPP_DOCUMENT_FORMAT_ERROR IPP_STATUS_ERROR_DOCUMENT_FORMAT_ERROR # define IPP_DOCUMENT_ACCESS_ERROR IPP_STATUS_ERROR_DOCUMENT_ACCESS # define IPP_ATTRIBUTES_NOT_SETTABLE IPP_STATUS_ERROR_ATTRIBUTES_NOT_SETTABLE # define IPP_IGNORED_ALL_SUBSCRIPTIONS IPP_STATUS_ERROR_IGNORED_ALL_SUBSCRIPTIONS # define IPP_TOO_MANY_SUBSCRIPTIONS IPP_STATUS_ERROR_TOO_MANY_SUBSCRIPTIONS # define IPP_IGNORED_ALL_NOTIFICATIONS IPP_STATUS_ERROR_IGNORED_ALL_NOTIFICATIONS # define IPP_PRINT_SUPPORT_FILE_NOT_FOUND IPP_STATUS_ERROR_PRINT_SUPPORT_FILE_NOT_FOUND # define IPP_DOCUMENT_PASSWORD_ERROR IPP_STATUS_ERROR_DOCUMENT_PASSWORD # define IPP_DOCUMENT_PERMISSION_ERROR IPP_STATUS_ERROR_DOCUMENT_PERMISSION # define IPP_DOCUMENT_SECURITY_ERROR IPP_STATUS_ERROR_DOCUMENT_SECURITY # define IPP_DOCUMENT_UNPRINTABLE_ERROR IPP_STATUS_ERROR_DOCUMENT_UNPRINTABLE # define IPP_INTERNAL_ERROR IPP_STATUS_ERROR_INTERNAL # define IPP_OPERATION_NOT_SUPPORTED IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED # define IPP_SERVICE_UNAVAILABLE IPP_STATUS_ERROR_SERVICE_UNAVAILABLE # define IPP_VERSION_NOT_SUPPORTED IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED # define IPP_DEVICE_ERROR IPP_STATUS_ERROR_DEVICE # define IPP_TEMPORARY_ERROR IPP_STATUS_ERROR_TEMPORARY # define IPP_NOT_ACCEPTING IPP_STATUS_ERROR_NOT_ACCEPTING_JOBS # define IPP_PRINTER_BUSY IPP_STATUS_ERROR_BUSY # define IPP_ERROR_JOB_CANCELED IPP_STATUS_ERROR_JOB_CANCELED # define IPP_MULTIPLE_JOBS_NOT_SUPPORTED IPP_STATUS_ERROR_MULTIPLE_JOBS_NOT_SUPPORTED # define IPP_PRINTER_IS_DEACTIVATED IPP_STATUS_ERROR_PRINTER_IS_DEACTIVATED # define IPP_TOO_MANY_JOBS IPP_STATUS_ERROR_TOO_MANY_JOBS # define IPP_TOO_MANY_DOCUMENTS IPP_STATUS_ERROR_TOO_MANY_DOCUMENTS # define IPP_AUTHENTICATION_CANCELED IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED # define IPP_PKI_ERROR IPP_STATUS_ERROR_CUPS_PKI # define IPP_UPGRADE_REQUIRED IPP_STATUS_ERROR_CUPS_UPGRADE_REQUIRED /* Legacy name for canceled status */ # define IPP_ERROR_JOB_CANCELLED IPP_STATUS_ERROR_JOB_CANCELED # endif /* _CUPS_NO_DEPRECATED */ } ipp_status_t; typedef enum ipp_tag_e /**** Value and group tag values for attributes ****/ { IPP_TAG_CUPS_INVALID = -1, /* Invalid tag name for @link ippTagValue@ */ IPP_TAG_ZERO = 0x00, /* Zero tag - used for separators */ IPP_TAG_OPERATION, /* Operation group */ IPP_TAG_JOB, /* Job group */ IPP_TAG_END, /* End-of-attributes */ IPP_TAG_PRINTER, /* Printer group */ IPP_TAG_UNSUPPORTED_GROUP, /* Unsupported attributes group */ IPP_TAG_SUBSCRIPTION, /* Subscription group */ IPP_TAG_EVENT_NOTIFICATION, /* Event group */ IPP_TAG_RESOURCE, /* Resource group */ IPP_TAG_DOCUMENT, /* Document group */ IPP_TAG_SYSTEM, /* System group */ IPP_TAG_UNSUPPORTED_VALUE = 0x10, /* Unsupported value */ IPP_TAG_DEFAULT, /* Default value */ IPP_TAG_UNKNOWN, /* Unknown value */ IPP_TAG_NOVALUE, /* No-value value */ IPP_TAG_NOTSETTABLE = 0x15, /* Not-settable value */ IPP_TAG_DELETEATTR, /* Delete-attribute value */ IPP_TAG_ADMINDEFINE, /* Admin-defined value */ IPP_TAG_INTEGER = 0x21, /* Integer value */ IPP_TAG_BOOLEAN, /* Boolean value */ IPP_TAG_ENUM, /* Enumeration value */ IPP_TAG_STRING = 0x30, /* Octet string value */ IPP_TAG_DATE, /* Date/time value */ IPP_TAG_RESOLUTION, /* Resolution value */ IPP_TAG_RANGE, /* Range value */ IPP_TAG_BEGIN_COLLECTION, /* Beginning of collection value @exclude all@ */ IPP_TAG_TEXTLANG, /* Text-with-language value */ IPP_TAG_NAMELANG, /* Name-with-language value */ IPP_TAG_END_COLLECTION, /* End of collection value @exclude all@ */ IPP_TAG_TEXT = 0x41, /* Text value */ IPP_TAG_NAME, /* Name value */ IPP_TAG_RESERVED_STRING, /* Reserved for future string value @private@ */ IPP_TAG_KEYWORD, /* Keyword value */ IPP_TAG_URI, /* URI value */ IPP_TAG_URISCHEME, /* URI scheme value */ IPP_TAG_CHARSET, /* Character set value */ IPP_TAG_LANGUAGE, /* Language value */ IPP_TAG_MIMETYPE, /* MIME media type value */ IPP_TAG_MEMBERNAME, /* Collection member name value @exclude all@ */ IPP_TAG_EXTENSION = 0x7f, /* Extension point for 32-bit tags @exclude all@ */ IPP_TAG_CUPS_MASK = 0x7fffffff, /* Mask for copied attribute values @private@ */ /* The following expression is used to avoid compiler warnings with +/-0x80000000 */ IPP_TAG_CUPS_CONST = -0x7fffffff-1 /* Bitflag for copied/const attribute values @private@ */ # ifndef _CUPS_NO_DEPRECATED # define IPP_TAG_MASK IPP_TAG_CUPS_MASK # define IPP_TAG_COPY IPP_TAG_CUPS_CONST # endif /* !_CUPS_NO_DEPRECATED */ } ipp_tag_t; typedef unsigned char ipp_uchar_t; /**** Unsigned 8-bit integer/character @exclude all@ ****/ typedef struct _ipp_s ipp_t; /**** IPP request/response data ****/ typedef struct _ipp_attribute_s ipp_attribute_t; /**** IPP attribute ****/ /**** New in CUPS 1.2/macOS 10.5 ****/ typedef ssize_t (*ipp_iocb_t)(void *context, ipp_uchar_t *buffer, size_t bytes); /**** ippReadIO/ippWriteIO callback function @since CUPS 1.2/macOS 10.5@ ****/ /**** New in CUPS 1.6/macOS 10.8 ****/ typedef int (*ipp_copycb_t)(void *context, ipp_t *dst, ipp_attribute_t *attr); /**** ippCopyAttributes callback function @since CUPS 1.6/macOS 10.8 ****/ /* * The following structures are PRIVATE starting with CUPS 1.6/macOS 10.8. * Please use the new accessor functions available in CUPS 1.6 and later, as * these definitions will be moved to a private header file in a future release. * * Define _IPP_PRIVATE_STRUCTURES to 1 to cause the private IPP structures to be * exposed in CUPS 1.6. This happens automatically on macOS when compiling for * a deployment target of 10.7 or earlier. * * Define _IPP_PRIVATE_STRUCTURES to 0 to prevent the private IPP structures * from being exposed. This is useful when migrating existing code to the new * accessors. */ # ifdef _IPP_PRIVATE_STRUCTURES /* Somebody has overridden the value */ # elif defined(_CUPS_SOURCE) || defined(_CUPS_IPP_PRIVATE_H_) /* Building CUPS */ # define _IPP_PRIVATE_STRUCTURES 1 # elif defined(__APPLE__) # if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8 /* Building for 10.7 and earlier */ # define _IPP_PRIVATE_STRUCTURES 1 # elif !defined(MAC_OS_X_VERSION_10_8) /* Building for 10.7 and earlier */ # define _IPP_PRIVATE_STRUCTURES 1 # endif /* MAC_OS_X_VERSION_10_8 && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8 */ # else # define _IPP_PRIVATE_STRUCTURES 0 # endif /* _CUPS_SOURCE || _CUPS_IPP_PRIVATE_H_ */ # if _IPP_PRIVATE_STRUCTURES typedef union _ipp_request_u /**** Request Header ****/ { struct /* Any Header */ { ipp_uchar_t version[2]; /* Protocol version number */ int op_status; /* Operation ID or status code*/ int request_id; /* Request ID */ } any; struct /* Operation Header */ { ipp_uchar_t version[2]; /* Protocol version number */ ipp_op_t operation_id; /* Operation ID */ int request_id; /* Request ID */ } op; struct /* Status Header */ { ipp_uchar_t version[2]; /* Protocol version number */ ipp_status_t status_code; /* Status code */ int request_id; /* Request ID */ } status; /**** New in CUPS 1.1.19 ****/ struct /* Event Header @since CUPS 1.1.19/macOS 10.3@ */ { ipp_uchar_t version[2]; /* Protocol version number */ ipp_status_t status_code; /* Status code */ int request_id; /* Request ID */ } event; } _ipp_request_t; /**** New in CUPS 1.1.19 ****/ typedef union _ipp_value_u /**** Attribute Value ****/ { int integer; /* Integer/enumerated value */ char boolean; /* Boolean value */ ipp_uchar_t date[11]; /* Date/time value */ struct { int xres, /* Horizontal resolution */ yres; /* Vertical resolution */ ipp_res_t units; /* Resolution units */ } resolution; /* Resolution value */ struct { int lower, /* Lower value */ upper; /* Upper value */ } range; /* Range of integers value */ struct { char *language; /* Language code */ char *text; /* String */ } string; /* String with language value */ struct { int length; /* Length of attribute */ void *data; /* Data in attribute */ } unknown; /* Unknown attribute type */ /**** New in CUPS 1.1.19 ****/ ipp_t *collection; /* Collection value @since CUPS 1.1.19/macOS 10.3@ */ } _ipp_value_t; typedef _ipp_value_t ipp_value_t; /**** Convenience typedef that will be removed @private@ ****/ struct _ipp_attribute_s /**** IPP attribute ****/ { ipp_attribute_t *next; /* Next attribute in list */ ipp_tag_t group_tag, /* Job/Printer/Operation group tag */ value_tag; /* What type of value is it? */ char *name; /* Name of attribute */ int num_values; /* Number of values */ _ipp_value_t values[1]; /* Values */ }; struct _ipp_s /**** IPP Request/Response/Notification ****/ { ipp_state_t state; /* State of request */ _ipp_request_t request; /* Request header */ ipp_attribute_t *attrs; /* Attributes */ ipp_attribute_t *last; /* Last attribute in list */ ipp_attribute_t *current; /* Current attribute (for read/write) */ ipp_tag_t curtag; /* Current attribute group tag */ /**** New in CUPS 1.2 ****/ ipp_attribute_t *prev; /* Previous attribute (for read) @since CUPS 1.2/macOS 10.5@ */ /**** New in CUPS 1.4.4 ****/ int use; /* Use count @since CUPS 1.4.4/macOS 10.6.?@ */ /**** New in CUPS 2.0 ****/ int atend, /* At end of list? */ curindex; /* Current attribute index for hierarchical search */ }; # endif /* _IPP_PRIVATE_STRUCTURES */ /* * Prototypes... */ extern ipp_attribute_t *ippAddBoolean(ipp_t *ipp, ipp_tag_t group, const char *name, char value); extern ipp_attribute_t *ippAddBooleans(ipp_t *ipp, ipp_tag_t group, const char *name, int num_values, const char *values); extern ipp_attribute_t *ippAddDate(ipp_t *ipp, ipp_tag_t group, const char *name, const ipp_uchar_t *value); extern ipp_attribute_t *ippAddInteger(ipp_t *ipp, ipp_tag_t group, ipp_tag_t value_tag, const char *name, int value); extern ipp_attribute_t *ippAddIntegers(ipp_t *ipp, ipp_tag_t group, ipp_tag_t value_tag, const char *name, int num_values, const int *values); extern ipp_attribute_t *ippAddRange(ipp_t *ipp, ipp_tag_t group, const char *name, int lower, int upper); extern ipp_attribute_t *ippAddRanges(ipp_t *ipp, ipp_tag_t group, const char *name, int num_values, const int *lower, const int *upper); extern ipp_attribute_t *ippAddResolution(ipp_t *ipp, ipp_tag_t group, const char *name, ipp_res_t units, int xres, int yres); extern ipp_attribute_t *ippAddResolutions(ipp_t *ipp, ipp_tag_t group, const char *name, int num_values, ipp_res_t units, const int *xres, const int *yres); extern ipp_attribute_t *ippAddSeparator(ipp_t *ipp); extern ipp_attribute_t *ippAddString(ipp_t *ipp, ipp_tag_t group, ipp_tag_t value_tag, const char *name, const char *language, const char *value); extern ipp_attribute_t *ippAddStrings(ipp_t *ipp, ipp_tag_t group, ipp_tag_t value_tag, const char *name, int num_values, const char *language, const char * const *values); extern time_t ippDateToTime(const ipp_uchar_t *date); extern void ippDelete(ipp_t *ipp); extern const char *ippErrorString(ipp_status_t error); extern ipp_attribute_t *ippFindAttribute(ipp_t *ipp, const char *name, ipp_tag_t value_tag); extern ipp_attribute_t *ippFindNextAttribute(ipp_t *ipp, const char *name, ipp_tag_t value_tag); extern size_t ippLength(ipp_t *ipp); extern ipp_t *ippNew(void); extern ipp_state_t ippRead(http_t *http, ipp_t *ipp); extern const ipp_uchar_t *ippTimeToDate(time_t t); extern ipp_state_t ippWrite(http_t *http, ipp_t *ipp); extern int ippPort(void); extern void ippSetPort(int p); /**** New in CUPS 1.1.19 ****/ extern ipp_attribute_t *ippAddCollection(ipp_t *ipp, ipp_tag_t group, const char *name, ipp_t *value) _CUPS_API_1_1_19; extern ipp_attribute_t *ippAddCollections(ipp_t *ipp, ipp_tag_t group, const char *name, int num_values, const ipp_t **values) _CUPS_API_1_1_19; extern void ippDeleteAttribute(ipp_t *ipp, ipp_attribute_t *attr) _CUPS_API_1_1_19; extern ipp_state_t ippReadFile(int fd, ipp_t *ipp) _CUPS_API_1_1_19; extern ipp_state_t ippWriteFile(int fd, ipp_t *ipp) _CUPS_API_1_1_19; /**** New in CUPS 1.2/macOS 10.5 ****/ extern ipp_attribute_t *ippAddOctetString(ipp_t *ipp, ipp_tag_t group, const char *name, const void *data, int datalen) _CUPS_API_1_2; extern ipp_status_t ippErrorValue(const char *name) _CUPS_API_1_2; extern ipp_t *ippNewRequest(ipp_op_t op) _CUPS_API_1_2; extern const char *ippOpString(ipp_op_t op) _CUPS_API_1_2; extern ipp_op_t ippOpValue(const char *name) _CUPS_API_1_2; extern ipp_state_t ippReadIO(void *src, ipp_iocb_t cb, int blocking, ipp_t *parent, ipp_t *ipp) _CUPS_API_1_2; extern ipp_state_t ippWriteIO(void *dst, ipp_iocb_t cb, int blocking, ipp_t *parent, ipp_t *ipp) _CUPS_API_1_2; /**** New in CUPS 1.4/macOS 10.6 ****/ extern const char *ippTagString(ipp_tag_t tag) _CUPS_API_1_4; extern ipp_tag_t ippTagValue(const char *name) _CUPS_API_1_4; /**** New in CUPS 1.6/macOS 10.8 ****/ extern ipp_attribute_t *ippAddOutOfBand(ipp_t *ipp, ipp_tag_t group, ipp_tag_t value_tag, const char *name) _CUPS_API_1_6; extern size_t ippAttributeString(ipp_attribute_t *attr, char *buffer, size_t bufsize) _CUPS_API_1_6; extern ipp_attribute_t *ippCopyAttribute(ipp_t *dst, ipp_attribute_t *attr, int quickcopy) _CUPS_API_1_6; extern int ippCopyAttributes(ipp_t *dst, ipp_t *src, int quickcopy, ipp_copycb_t cb, void *context) _CUPS_API_1_6; extern int ippDeleteValues(ipp_t *ipp, ipp_attribute_t **attr, int element, int count) _CUPS_API_1_6; extern const char *ippEnumString(const char *attrname, int enumvalue) _CUPS_API_1_6; extern int ippEnumValue(const char *attrname, const char *enumstring) _CUPS_API_1_6; extern ipp_attribute_t *ippFirstAttribute(ipp_t *ipp) _CUPS_API_1_6; extern int ippGetBoolean(ipp_attribute_t *attr, int element) _CUPS_API_1_6; extern ipp_t *ippGetCollection(ipp_attribute_t *attr, int element) _CUPS_API_1_6; extern int ippGetCount(ipp_attribute_t *attr) _CUPS_API_1_6; extern const ipp_uchar_t *ippGetDate(ipp_attribute_t *attr, int element) _CUPS_API_1_6; extern ipp_tag_t ippGetGroupTag(ipp_attribute_t *attr) _CUPS_API_1_6; extern int ippGetInteger(ipp_attribute_t *attr, int element) _CUPS_API_1_6; extern const char *ippGetName(ipp_attribute_t *attr) _CUPS_API_1_6; extern ipp_op_t ippGetOperation(ipp_t *ipp) _CUPS_API_1_6; extern int ippGetRange(ipp_attribute_t *attr, int element, int *upper) _CUPS_API_1_6; extern int ippGetRequestId(ipp_t *ipp) _CUPS_API_1_6; extern int ippGetResolution(ipp_attribute_t *attr, int element, int *yres, ipp_res_t *units) _CUPS_API_1_6; extern ipp_state_t ippGetState(ipp_t *ipp) _CUPS_API_1_6; extern ipp_status_t ippGetStatusCode(ipp_t *ipp) _CUPS_API_1_6; extern const char *ippGetString(ipp_attribute_t *attr, int element, const char **language) _CUPS_API_1_6; extern ipp_tag_t ippGetValueTag(ipp_attribute_t *attr) _CUPS_API_1_6; extern int ippGetVersion(ipp_t *ipp, int *minor) _CUPS_API_1_6; extern ipp_attribute_t *ippNextAttribute(ipp_t *ipp) _CUPS_API_1_6; extern int ippSetBoolean(ipp_t *ipp, ipp_attribute_t **attr, int element, int boolvalue) _CUPS_API_1_6; extern int ippSetCollection(ipp_t *ipp, ipp_attribute_t **attr, int element, ipp_t *colvalue) _CUPS_API_1_6; extern int ippSetDate(ipp_t *ipp, ipp_attribute_t **attr, int element, const ipp_uchar_t *datevalue) _CUPS_API_1_6; extern int ippSetGroupTag(ipp_t *ipp, ipp_attribute_t **attr, ipp_tag_t group_tag) _CUPS_API_1_6; extern int ippSetInteger(ipp_t *ipp, ipp_attribute_t **attr, int element, int intvalue) _CUPS_API_1_6; extern int ippSetName(ipp_t *ipp, ipp_attribute_t **attr, const char *name) _CUPS_API_1_6; extern int ippSetOperation(ipp_t *ipp, ipp_op_t op) _CUPS_API_1_6; extern int ippSetRange(ipp_t *ipp, ipp_attribute_t **attr, int element, int lowervalue, int uppervalue) _CUPS_API_1_6; extern int ippSetRequestId(ipp_t *ipp, int request_id) _CUPS_API_1_6; extern int ippSetResolution(ipp_t *ipp, ipp_attribute_t **attr, int element, ipp_res_t unitsvalue, int xresvalue, int yresvalue) _CUPS_API_1_6; extern int ippSetState(ipp_t *ipp, ipp_state_t state) _CUPS_API_1_6; extern int ippSetStatusCode(ipp_t *ipp, ipp_status_t status) _CUPS_API_1_6; extern int ippSetString(ipp_t *ipp, ipp_attribute_t **attr, int element, const char *strvalue) _CUPS_API_1_6; extern int ippSetValueTag(ipp_t *ipp, ipp_attribute_t **attr, ipp_tag_t value_tag) _CUPS_API_1_6; extern int ippSetVersion(ipp_t *ipp, int major, int minor) _CUPS_API_1_6; /**** New in CUPS 1.7 ****/ extern ipp_attribute_t *ippAddStringf(ipp_t *ipp, ipp_tag_t group, ipp_tag_t value_tag, const char *name, const char *language, const char *format, ...) _CUPS_API_1_7; extern ipp_attribute_t *ippAddStringfv(ipp_t *ipp, ipp_tag_t group, ipp_tag_t value_tag, const char *name, const char *language, const char *format, va_list ap) _CUPS_API_1_7; extern int ippContainsInteger(ipp_attribute_t *attr, int value) _CUPS_API_1_7; extern int ippContainsString(ipp_attribute_t *attr, const char *value) _CUPS_API_1_7; extern cups_array_t *ippCreateRequestedArray(ipp_t *request) _CUPS_API_1_7; extern void *ippGetOctetString(ipp_attribute_t *attr, int element, int *datalen) _CUPS_API_1_7; extern ipp_t *ippNewResponse(ipp_t *request) _CUPS_API_1_7; extern int ippSetOctetString(ipp_t *ipp, ipp_attribute_t **attr, int element, const void *data, int datalen) _CUPS_API_1_7; extern int ippSetStringf(ipp_t *ipp, ipp_attribute_t **attr, int element, const char *format, ...) _CUPS_API_1_7; extern int ippSetStringfv(ipp_t *ipp, ipp_attribute_t **attr, int element, const char *format, va_list ap) _CUPS_API_1_7; extern int ippValidateAttribute(ipp_attribute_t *attr) _CUPS_API_1_7; extern int ippValidateAttributes(ipp_t *ipp) _CUPS_API_1_7; /**** New in CUPS 2.0 ****/ extern const char *ippStateString(ipp_state_t state) _CUPS_API_2_0; /* * C++ magic... */ # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_IPP_H_ */ ippsample/cups/request.c0000644000175000017500000007151413240604116014355 0ustar tilltill/* * IPP utilities for CUPS. * * Copyright © 2007-2018 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #include #include #if defined(WIN32) || defined(__EMX__) # include #else # include #endif /* WIN32 || __EMX__ */ #ifndef O_BINARY # define O_BINARY 0 #endif /* O_BINARY */ #ifndef MSG_DONTWAIT # define MSG_DONTWAIT 0 #endif /* !MSG_DONTWAIT */ /* * 'cupsDoFileRequest()' - Do an IPP request with a file. * * This function sends the IPP request and attached file to the specified * server, retrying and authenticating as necessary. The request is freed with * @link ippDelete@. */ ipp_t * /* O - Response data */ cupsDoFileRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ ipp_t *request, /* I - IPP request */ const char *resource, /* I - HTTP resource for POST */ const char *filename) /* I - File to send or @code NULL@ for none */ { ipp_t *response; /* IPP response data */ int infile; /* Input file */ DEBUG_printf(("cupsDoFileRequest(http=%p, request=%p(%s), resource=\"%s\", filename=\"%s\")", (void *)http, (void *)request, request ? ippOpString(request->request.op.operation_id) : "?", resource, filename)); if (filename) { if ((infile = open(filename, O_RDONLY | O_BINARY)) < 0) { /* * Can't get file information! */ _cupsSetError(errno == ENOENT ? IPP_STATUS_ERROR_NOT_FOUND : IPP_STATUS_ERROR_NOT_AUTHORIZED, NULL, 0); ippDelete(request); return (NULL); } } else infile = -1; response = cupsDoIORequest(http, request, resource, infile, -1); if (infile >= 0) close(infile); return (response); } /* * 'cupsDoIORequest()' - Do an IPP request with file descriptors. * * This function sends the IPP request with the optional input file "infile" to * the specified server, retrying and authenticating as necessary. The request * is freed with @link ippDelete@. * * If "infile" is a valid file descriptor, @code cupsDoIORequest@ copies * all of the data from the file after the IPP request message. * * If "outfile" is a valid file descriptor, @code cupsDoIORequest@ copies * all of the data after the IPP response message to the file. * * @since CUPS 1.3/macOS 10.5@ */ ipp_t * /* O - Response data */ cupsDoIORequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ ipp_t *request, /* I - IPP request */ const char *resource, /* I - HTTP resource for POST */ int infile, /* I - File to read from or -1 for none */ int outfile) /* I - File to write to or -1 for none */ { ipp_t *response = NULL; /* IPP response data */ size_t length = 0; /* Content-Length value */ http_status_t status; /* Status of HTTP request */ struct stat fileinfo; /* File information */ ssize_t bytes; /* Number of bytes read/written */ char buffer[32768]; /* Output buffer */ DEBUG_printf(("cupsDoIORequest(http=%p, request=%p(%s), resource=\"%s\", infile=%d, outfile=%d)", (void *)http, (void *)request, request ? ippOpString(request->request.op.operation_id) : "?", resource, infile, outfile)); /* * Range check input... */ if (!request || !resource) { ippDelete(request); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (NULL); } /* * Get the default connection as needed... */ if (!http && (http = _cupsConnect()) == NULL) { ippDelete(request); return (NULL); } /* * See if we have a file to send... */ if (infile >= 0) { if (fstat(infile, &fileinfo)) { /* * Can't get file information! */ _cupsSetError(errno == EBADF ? IPP_STATUS_ERROR_NOT_FOUND : IPP_STATUS_ERROR_NOT_AUTHORIZED, NULL, 0); ippDelete(request); return (NULL); } #ifdef WIN32 if (fileinfo.st_mode & _S_IFDIR) #else if (S_ISDIR(fileinfo.st_mode)) #endif /* WIN32 */ { /* * Can't send a directory... */ _cupsSetError(IPP_STATUS_ERROR_NOT_POSSIBLE, strerror(EISDIR), 0); ippDelete(request); return (NULL); } #ifndef WIN32 if (!S_ISREG(fileinfo.st_mode)) length = 0; /* Chunk when piping */ else #endif /* !WIN32 */ length = ippLength(request) + (size_t)fileinfo.st_size; } else length = ippLength(request); DEBUG_printf(("2cupsDoIORequest: Request length=%ld, total length=%ld", (long)ippLength(request), (long)length)); /* * Clear any "Local" authentication data since it is probably stale... */ if (http->authstring && !strncmp(http->authstring, "Local ", 6)) httpSetAuthString(http, NULL, NULL); /* * Loop until we can send the request without authorization problems. */ while (response == NULL) { DEBUG_puts("2cupsDoIORequest: setup..."); /* * Send the request... */ status = cupsSendRequest(http, request, resource, length); DEBUG_printf(("2cupsDoIORequest: status=%d", status)); if (status == HTTP_STATUS_CONTINUE && request->state == IPP_STATE_DATA && infile >= 0) { DEBUG_puts("2cupsDoIORequest: file write..."); /* * Send the file with the request... */ #ifndef WIN32 if (S_ISREG(fileinfo.st_mode)) #endif /* WIN32 */ lseek(infile, 0, SEEK_SET); while ((bytes = read(infile, buffer, sizeof(buffer))) > 0) { if ((status = cupsWriteRequestData(http, buffer, (size_t)bytes)) != HTTP_STATUS_CONTINUE) break; } } /* * Get the server's response... */ if (status <= HTTP_STATUS_CONTINUE || status == HTTP_STATUS_OK) { response = cupsGetResponse(http, resource); status = httpGetStatus(http); } DEBUG_printf(("2cupsDoIORequest: status=%d", status)); if (status == HTTP_STATUS_ERROR || (status >= HTTP_STATUS_BAD_REQUEST && status != HTTP_STATUS_UNAUTHORIZED && status != HTTP_STATUS_UPGRADE_REQUIRED)) { _cupsSetHTTPError(status); break; } if (response && outfile >= 0) { /* * Write trailing data to file... */ while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) if (write(outfile, buffer, (size_t)bytes) < bytes) break; } if (http->state != HTTP_STATE_WAITING) { /* * Flush any remaining data... */ httpFlush(http); } } /* * Delete the original request and return the response... */ ippDelete(request); return (response); } /* * 'cupsDoRequest()' - Do an IPP request. * * This function sends the IPP request to the specified server, retrying * and authenticating as necessary. The request is freed with @link ippDelete@. */ ipp_t * /* O - Response data */ cupsDoRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ ipp_t *request, /* I - IPP request */ const char *resource) /* I - HTTP resource for POST */ { DEBUG_printf(("cupsDoRequest(http=%p, request=%p(%s), resource=\"%s\")", (void *)http, (void *)request, request ? ippOpString(request->request.op.operation_id) : "?", resource)); return (cupsDoIORequest(http, request, resource, -1, -1)); } /* * 'cupsGetResponse()' - Get a response to an IPP request. * * Use this function to get the response for an IPP request sent using * @link cupsSendRequest@. For requests that return additional data, use * @link cupsReadResponseData@ after getting a successful response, * otherwise call @link httpFlush@ to complete the response processing. * * @since CUPS 1.4/macOS 10.6@ */ ipp_t * /* O - Response or @code NULL@ on HTTP error */ cupsGetResponse(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *resource) /* I - HTTP resource for POST */ { http_status_t status; /* HTTP status */ ipp_state_t state; /* IPP read state */ ipp_t *response = NULL; /* IPP response */ DEBUG_printf(("cupsGetResponse(http=%p, resource=\"%s\")", (void *)http, resource)); DEBUG_printf(("1cupsGetResponse: http->state=%d", http ? http->state : HTTP_STATE_ERROR)); /* * Connect to the default server as needed... */ if (!http) { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ if ((http = cg->http) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No active connection."), 1); DEBUG_puts("1cupsGetResponse: No active connection - returning NULL."); return (NULL); } } if (http->state != HTTP_STATE_POST_RECV && http->state != HTTP_STATE_POST_SEND) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No request sent."), 1); DEBUG_puts("1cupsGetResponse: Not in POST state - returning NULL."); return (NULL); } /* * Check for an unfinished chunked request... */ if (http->data_encoding == HTTP_ENCODING_CHUNKED) { /* * Send a 0-length chunk to finish off the request... */ DEBUG_puts("2cupsGetResponse: Finishing chunked POST..."); if (httpWrite2(http, "", 0) < 0) return (NULL); } /* * Wait for a response from the server... */ DEBUG_printf(("2cupsGetResponse: Update loop, http->status=%d...", http->status)); do { status = httpUpdate(http); } while (status == HTTP_STATUS_CONTINUE); DEBUG_printf(("2cupsGetResponse: status=%d", status)); if (status == HTTP_STATUS_OK) { /* * Get the IPP response... */ response = ippNew(); while ((state = ippRead(http, response)) != IPP_STATE_DATA) if (state == IPP_STATE_ERROR) break; if (state == IPP_STATE_ERROR) { /* * Flush remaining data and delete the response... */ DEBUG_puts("1cupsGetResponse: IPP read error!"); httpFlush(http); ippDelete(response); response = NULL; http->status = status = HTTP_STATUS_ERROR; http->error = EINVAL; } } else if (status != HTTP_STATUS_ERROR) { /* * Flush any error message... */ httpFlush(http); /* * Then handle encryption and authentication... */ if (status == HTTP_STATUS_UNAUTHORIZED) { /* * See if we can do authentication... */ DEBUG_puts("2cupsGetResponse: Need authorization..."); if (!cupsDoAuthentication(http, "POST", resource)) httpReconnect2(http, 30000, NULL); else http->status = status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; } #ifdef HAVE_SSL else if (status == HTTP_STATUS_UPGRADE_REQUIRED) { /* * Force a reconnect with encryption... */ DEBUG_puts("2cupsGetResponse: Need encryption..."); if (!httpReconnect2(http, 30000, NULL)) httpEncryption(http, HTTP_ENCRYPTION_REQUIRED); } #endif /* HAVE_SSL */ } if (response) { ipp_attribute_t *attr; /* status-message attribute */ attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT); DEBUG_printf(("1cupsGetResponse: status-code=%s, status-message=\"%s\"", ippErrorString(response->request.status.status_code), attr ? attr->values[0].string.text : "")); _cupsSetError(response->request.status.status_code, attr ? attr->values[0].string.text : ippErrorString(response->request.status.status_code), 0); } return (response); } /* * 'cupsLastError()' - Return the last IPP status code received on the current * thread. */ ipp_status_t /* O - IPP status code from last request */ cupsLastError(void) { return (_cupsGlobals()->last_error); } /* * 'cupsLastErrorString()' - Return the last IPP status-message received on the * current thread. * * @since CUPS 1.2/macOS 10.5@ */ const char * /* O - status-message text from last request */ cupsLastErrorString(void) { return (_cupsGlobals()->last_status_message); } /* * '_cupsNextDelay()' - Return the next retry delay value. * * This function currently returns the Fibonacci sequence 1 1 2 3 5 8. * * Pass 0 for the current delay value to initialize the sequence. */ int /* O - Next delay value */ _cupsNextDelay(int current, /* I - Current delay value or 0 */ int *previous) /* IO - Previous delay value */ { int next; /* Next delay value */ if (current > 0) { next = (current + *previous) % 12; *previous = next < current ? 0 : current; } else { next = 1; *previous = 0; } return (next); } /* * 'cupsReadResponseData()' - Read additional data after the IPP response. * * This function is used after @link cupsGetResponse@ to read the PPD or document * files from @code CUPS_GET_PPD@ and @code CUPS_GET_DOCUMENT@ requests, * respectively. * * @since CUPS 1.4/macOS 10.6@ */ ssize_t /* O - Bytes read, 0 on EOF, -1 on error */ cupsReadResponseData( http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ char *buffer, /* I - Buffer to use */ size_t length) /* I - Number of bytes to read */ { /* * Get the default connection as needed... */ DEBUG_printf(("cupsReadResponseData(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length)); if (!http) { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ if ((http = cg->http) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No active connection"), 1); return (-1); } } /* * Then read from the HTTP connection... */ return (httpRead2(http, buffer, length)); } /* * 'cupsSendRequest()' - Send an IPP request. * * Use @link cupsWriteRequestData@ to write any additional data (document, PPD * file, etc.) for the request, @link cupsGetResponse@ to get the IPP response, * and @link cupsReadResponseData@ to read any additional data following the * response. Only one request can be sent/queued at a time per @code http_t@ * connection. * * Returns the initial HTTP status code, which will be @code HTTP_STATUS_CONTINUE@ * on a successful send of the request. * * Note: Unlike @link cupsDoFileRequest@, @link cupsDoIORequest@, and * @link cupsDoRequest@, the request is NOT freed with @link ippDelete@. * * @since CUPS 1.4/macOS 10.6@ */ http_status_t /* O - Initial HTTP status */ cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ ipp_t *request, /* I - IPP request */ const char *resource, /* I - Resource path */ size_t length) /* I - Length of data to follow or @code CUPS_LENGTH_VARIABLE@ */ { http_status_t status; /* Status of HTTP request */ int got_status; /* Did we get the status? */ ipp_state_t state; /* State of IPP processing */ http_status_t expect; /* Expect: header to use */ char date[256]; /* Date: header value */ DEBUG_printf(("cupsSendRequest(http=%p, request=%p(%s), resource=\"%s\", length=" CUPS_LLFMT ")", (void *)http, (void *)request, request ? ippOpString(request->request.op.operation_id) : "?", resource, CUPS_LLCAST length)); /* * Range check input... */ if (!request || !resource) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (HTTP_STATUS_ERROR); } /* * Get the default connection as needed... */ if (!http && (http = _cupsConnect()) == NULL) return (HTTP_STATUS_SERVICE_UNAVAILABLE); /* * If the prior request was not flushed out, do so now... */ if (http->state == HTTP_STATE_GET_SEND || http->state == HTTP_STATE_POST_SEND) { DEBUG_puts("2cupsSendRequest: Flush prior response."); httpFlush(http); } else if (http->state != HTTP_STATE_WAITING) { DEBUG_printf(("1cupsSendRequest: Unknown HTTP state (%d), " "reconnecting.", http->state)); if (httpReconnect2(http, 30000, NULL)) return (HTTP_STATUS_ERROR); } #ifdef HAVE_SSL /* * See if we have an auth-info attribute and are communicating over * a non-local link. If so, encrypt the link so that we can pass * the authentication information securely... */ if (ippFindAttribute(request, "auth-info", IPP_TAG_TEXT) && !httpAddrLocalhost(http->hostaddr) && !http->tls && httpEncryption(http, HTTP_ENCRYPTION_REQUIRED)) { DEBUG_puts("1cupsSendRequest: Unable to encrypt connection."); return (HTTP_STATUS_SERVICE_UNAVAILABLE); } #endif /* HAVE_SSL */ /* * Reconnect if the last response had a "Connection: close"... */ if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) { DEBUG_puts("2cupsSendRequest: Connection: close"); httpClearFields(http); if (httpReconnect2(http, 30000, NULL)) { DEBUG_puts("1cupsSendRequest: Unable to reconnect."); return (HTTP_STATUS_SERVICE_UNAVAILABLE); } } /* * Loop until we can send the request without authorization problems. */ expect = HTTP_STATUS_CONTINUE; for (;;) { DEBUG_puts("2cupsSendRequest: Setup..."); /* * Setup the HTTP variables needed... */ httpClearFields(http); httpSetExpect(http, expect); httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp"); httpSetField(http, HTTP_FIELD_DATE, httpGetDateString2(time(NULL), date, (int)sizeof(date))); httpSetLength(http, length); #ifdef HAVE_GSSAPI if (http->authstring && !strncmp(http->authstring, "Negotiate", 9)) { /* * Do not use cached Kerberos credentials since they will look like a * "replay" attack... */ _cupsSetNegotiateAuthString(http, "POST", resource); } #endif /* HAVE_GSSAPI */ httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); DEBUG_printf(("2cupsSendRequest: authstring=\"%s\"", http->authstring)); /* * Try the request... */ DEBUG_puts("2cupsSendRequest: Sending HTTP POST..."); if (httpPost(http, resource)) { DEBUG_puts("2cupsSendRequest: POST failed, reconnecting."); if (httpReconnect2(http, 30000, NULL)) { DEBUG_puts("1cupsSendRequest: Unable to reconnect."); return (HTTP_STATUS_SERVICE_UNAVAILABLE); } else continue; } /* * Send the IPP data... */ DEBUG_puts("2cupsSendRequest: Writing IPP request..."); request->state = IPP_STATE_IDLE; status = HTTP_STATUS_CONTINUE; got_status = 0; while ((state = ippWrite(http, request)) != IPP_STATE_DATA) { if (httpCheck(http)) { got_status = 1; _httpUpdate(http, &status); if (status >= HTTP_STATUS_MULTIPLE_CHOICES) break; } else if (state == IPP_STATE_ERROR) break; } if (state == IPP_STATE_ERROR) { /* * We weren't able to send the IPP request. But did we already get a HTTP * error status? */ if (!got_status || status < HTTP_STATUS_MULTIPLE_CHOICES) { /* * No, something else went wrong. */ DEBUG_puts("1cupsSendRequest: Unable to send IPP request."); http->status = HTTP_STATUS_ERROR; http->state = HTTP_STATE_WAITING; return (HTTP_STATUS_ERROR); } } /* * Wait up to 1 second to get the 100-continue response as needed... */ if (!got_status) { if (expect == HTTP_STATUS_CONTINUE) { DEBUG_puts("2cupsSendRequest: Waiting for 100-continue..."); if (httpWait(http, 1000)) _httpUpdate(http, &status); } else if (httpCheck(http)) _httpUpdate(http, &status); } DEBUG_printf(("2cupsSendRequest: status=%d", status)); /* * Process the current HTTP status... */ if (status >= HTTP_STATUS_MULTIPLE_CHOICES) { int temp_status; /* Temporary status */ _cupsSetHTTPError(status); do { temp_status = httpUpdate(http); } while (temp_status != HTTP_STATUS_ERROR && http->state == HTTP_STATE_POST_RECV); httpFlush(http); } switch (status) { case HTTP_STATUS_CONTINUE : case HTTP_STATUS_OK : case HTTP_STATUS_ERROR : DEBUG_printf(("1cupsSendRequest: Returning %d.", status)); return (status); case HTTP_STATUS_UNAUTHORIZED : if (cupsDoAuthentication(http, "POST", resource)) { DEBUG_puts("1cupsSendRequest: Returning HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED."); return (HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED); } DEBUG_puts("2cupsSendRequest: Reconnecting after HTTP_STATUS_UNAUTHORIZED."); if (httpReconnect2(http, 30000, NULL)) { DEBUG_puts("1cupsSendRequest: Unable to reconnect."); return (HTTP_STATUS_SERVICE_UNAVAILABLE); } break; #ifdef HAVE_SSL case HTTP_STATUS_UPGRADE_REQUIRED : /* * Flush any error message, reconnect, and then upgrade with * encryption... */ DEBUG_puts("2cupsSendRequest: Reconnecting after " "HTTP_STATUS_UPGRADE_REQUIRED."); if (httpReconnect2(http, 30000, NULL)) { DEBUG_puts("1cupsSendRequest: Unable to reconnect."); return (HTTP_STATUS_SERVICE_UNAVAILABLE); } DEBUG_puts("2cupsSendRequest: Upgrading to TLS."); if (httpEncryption(http, HTTP_ENCRYPTION_REQUIRED)) { DEBUG_puts("1cupsSendRequest: Unable to encrypt connection."); return (HTTP_STATUS_SERVICE_UNAVAILABLE); } break; #endif /* HAVE_SSL */ case HTTP_STATUS_EXPECTATION_FAILED : /* * Don't try using the Expect: header the next time around... */ expect = (http_status_t)0; DEBUG_puts("2cupsSendRequest: Reconnecting after " "HTTP_EXPECTATION_FAILED."); if (httpReconnect2(http, 30000, NULL)) { DEBUG_puts("1cupsSendRequest: Unable to reconnect."); return (HTTP_STATUS_SERVICE_UNAVAILABLE); } break; default : /* * Some other error... */ return (status); } } } /* * 'cupsWriteRequestData()' - Write additional data after an IPP request. * * This function is used after @link cupsSendRequest@ to provide a PPD and * after @link cupsStartDocument@ to provide a document file. * * @since CUPS 1.4/macOS 10.6@ */ http_status_t /* O - @code HTTP_STATUS_CONTINUE@ if OK or HTTP status on error */ cupsWriteRequestData( http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *buffer, /* I - Bytes to write */ size_t length) /* I - Number of bytes to write */ { int wused; /* Previous bytes in buffer */ /* * Get the default connection as needed... */ DEBUG_printf(("cupsWriteRequestData(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length)); if (!http) { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ if ((http = cg->http) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No active connection"), 1); DEBUG_puts("1cupsWriteRequestData: Returning HTTP_STATUS_ERROR."); return (HTTP_STATUS_ERROR); } } /* * Then write to the HTTP connection... */ wused = http->wused; if (httpWrite2(http, buffer, length) < 0) { DEBUG_puts("1cupsWriteRequestData: Returning HTTP_STATUS_ERROR."); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(http->error), 0); return (HTTP_STATUS_ERROR); } /* * Finally, check if we have any pending data from the server... */ if (length >= HTTP_MAX_BUFFER || http->wused < wused || (wused > 0 && (size_t)http->wused == length)) { /* * We've written something to the server, so check for response data... */ if (_httpWait(http, 0, 1)) { http_status_t status; /* Status from _httpUpdate */ _httpUpdate(http, &status); if (status >= HTTP_STATUS_MULTIPLE_CHOICES) { _cupsSetHTTPError(status); do { status = httpUpdate(http); } while (status != HTTP_STATUS_ERROR && http->state == HTTP_STATE_POST_RECV); httpFlush(http); } DEBUG_printf(("1cupsWriteRequestData: Returning %d.\n", status)); return (status); } } DEBUG_puts("1cupsWriteRequestData: Returning HTTP_STATUS_CONTINUE."); return (HTTP_STATUS_CONTINUE); } /* * '_cupsConnect()' - Get the default server connection... */ http_t * /* O - HTTP connection */ _cupsConnect(void) { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ /* * See if we are connected to the same server... */ if (cg->http) { /* * Compare the connection hostname, port, and encryption settings to * the cached defaults; these were initialized the first time we * connected... */ if (strcmp(cg->http->hostname, cg->server) || #ifdef AF_LOCAL (httpAddrFamily(cg->http->hostaddr) != AF_LOCAL && cg->ipp_port != httpAddrPort(cg->http->hostaddr)) || #else cg->ipp_port != httpAddrPort(cg->http->hostaddr) || #endif /* AF_LOCAL */ (cg->http->encryption != cg->encryption && cg->http->encryption == HTTP_ENCRYPTION_NEVER)) { /* * Need to close the current connection because something has changed... */ httpClose(cg->http); cg->http = NULL; } else { /* * Same server, see if the connection is still established... */ char ch; /* Connection check byte */ ssize_t n; /* Number of bytes */ #ifdef WIN32 if ((n = recv(cg->http->fd, &ch, 1, MSG_PEEK)) == 0 || (n < 0 && WSAGetLastError() != WSAEWOULDBLOCK)) #else if ((n = recv(cg->http->fd, &ch, 1, MSG_PEEK | MSG_DONTWAIT)) == 0 || (n < 0 && errno != EWOULDBLOCK)) #endif /* WIN32 */ { /* * Nope, close the connection... */ httpClose(cg->http); cg->http = NULL; } } } /* * (Re)connect as needed... */ if (!cg->http) { if ((cg->http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL)) == NULL) { if (errno) _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, NULL, 0); else _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, _("Unable to connect to host."), 1); } } /* * Return the cached connection... */ return (cg->http); } /* * '_cupsSetError()' - Set the last IPP status code and status-message. */ void _cupsSetError(ipp_status_t status, /* I - IPP status code */ const char *message, /* I - status-message value */ int localize) /* I - Localize the message? */ { _cups_globals_t *cg; /* Global data */ if (!message && errno) { message = strerror(errno); localize = 0; } cg = _cupsGlobals(); cg->last_error = status; if (cg->last_status_message) { _cupsStrFree(cg->last_status_message); cg->last_status_message = NULL; } if (message) { if (localize) { /* * Get the message catalog... */ if (!cg->lang_default) cg->lang_default = cupsLangDefault(); cg->last_status_message = _cupsStrAlloc(_cupsLangString(cg->lang_default, message)); } else cg->last_status_message = _cupsStrAlloc(message); } DEBUG_printf(("4_cupsSetError: last_error=%s, last_status_message=\"%s\"", ippErrorString(cg->last_error), cg->last_status_message)); } /* * '_cupsSetHTTPError()' - Set the last error using the HTTP status. */ void _cupsSetHTTPError(http_status_t status) /* I - HTTP status code */ { switch (status) { case HTTP_STATUS_NOT_FOUND : _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, httpStatus(status), 0); break; case HTTP_STATUS_UNAUTHORIZED : _cupsSetError(IPP_STATUS_ERROR_NOT_AUTHENTICATED, httpStatus(status), 0); break; case HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED : _cupsSetError(IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED, httpStatus(status), 0); break; case HTTP_STATUS_FORBIDDEN : _cupsSetError(IPP_STATUS_ERROR_FORBIDDEN, httpStatus(status), 0); break; case HTTP_STATUS_BAD_REQUEST : _cupsSetError(IPP_STATUS_ERROR_BAD_REQUEST, httpStatus(status), 0); break; case HTTP_STATUS_REQUEST_TOO_LARGE : _cupsSetError(IPP_STATUS_ERROR_REQUEST_VALUE, httpStatus(status), 0); break; case HTTP_STATUS_NOT_IMPLEMENTED : _cupsSetError(IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED, httpStatus(status), 0); break; case HTTP_STATUS_NOT_SUPPORTED : _cupsSetError(IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, httpStatus(status), 0); break; case HTTP_STATUS_UPGRADE_REQUIRED : _cupsSetError(IPP_STATUS_ERROR_CUPS_UPGRADE_REQUIRED, httpStatus(status), 0); break; case HTTP_STATUS_CUPS_PKI_ERROR : _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, httpStatus(status), 0); break; case HTTP_STATUS_ERROR : _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); break; default : DEBUG_printf(("4_cupsSetHTTPError: HTTP error %d mapped to " "IPP_STATUS_ERROR_SERVICE_UNAVAILABLE!", status)); _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, httpStatus(status), 0); break; } } ippsample/cups/testoptions.c0000644000175000017500000001165013240604116015253 0ustar tilltill/* * Option unit test program for CUPS. * * Copyright 2008-2016 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" /* * 'main()' - Test option processing functions. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int status = 0, /* Exit status */ num_options; /* Number of options */ cups_option_t *options; /* Options */ const char *value; /* Value of an option */ ipp_t *request; /* IPP request */ ipp_attribute_t *attr; /* IPP attribute */ int count; /* Number of attributes */ if (argc == 1) { /* * cupsParseOptions() */ fputs("cupsParseOptions: ", stdout); num_options = cupsParseOptions("foo=1234 " "bar=\"One Fish\",\"Two Fish\",\"Red Fish\"," "\"Blue Fish\" " "baz={param1=1 param2=2} " "foobar=FOO\\ BAR " "barfoo=barfoo " "barfoo=\"\'BAR FOO\'\" " "auth-info=user,pass\\\\,word\\\\\\\\", 0, &options); if (num_options != 6) { printf("FAIL (num_options=%d, expected 6)\n", num_options); status ++; } else if ((value = cupsGetOption("foo", num_options, options)) == NULL || strcmp(value, "1234")) { printf("FAIL (foo=\"%s\", expected \"1234\")\n", value); status ++; } else if ((value = cupsGetOption("bar", num_options, options)) == NULL || strcmp(value, "One Fish,Two Fish,Red Fish,Blue Fish")) { printf("FAIL (bar=\"%s\", expected \"One Fish,Two Fish,Red Fish,Blue " "Fish\")\n", value); status ++; } else if ((value = cupsGetOption("baz", num_options, options)) == NULL || strcmp(value, "{param1=1 param2=2}")) { printf("FAIL (baz=\"%s\", expected \"{param1=1 param2=2}\")\n", value); status ++; } else if ((value = cupsGetOption("foobar", num_options, options)) == NULL || strcmp(value, "FOO BAR")) { printf("FAIL (foobar=\"%s\", expected \"FOO BAR\")\n", value); status ++; } else if ((value = cupsGetOption("barfoo", num_options, options)) == NULL || strcmp(value, "\'BAR FOO\'")) { printf("FAIL (barfoo=\"%s\", expected \"\'BAR FOO\'\")\n", value); status ++; } else if ((value = cupsGetOption("auth-info", num_options, options)) == NULL || strcmp(value, "user,pass\\,word\\\\")) { printf("FAIL (auth-info=\"%s\", expected \"user,pass\\,word\\\\\")\n", value); status ++; } else puts("PASS"); fputs("cupsEncodeOptions2: ", stdout); request = ippNew(); ippSetOperation(request, IPP_OP_PRINT_JOB); cupsEncodeOptions2(request, num_options, options, IPP_TAG_JOB); for (count = 0, attr = ippFirstAttribute(request); attr; attr = ippNextAttribute(request), count ++); if (count != 6) { printf("FAIL (%d attributes, expected 6)\n", count); status ++; } else if ((attr = ippFindAttribute(request, "foo", IPP_TAG_ZERO)) == NULL) { puts("FAIL (Unable to find attribute \"foo\")"); status ++; } else if (ippGetValueTag(attr) != IPP_TAG_NAME) { printf("FAIL (\"foo\" of type %s, expected name)\n", ippTagString(ippGetValueTag(attr))); status ++; } else if (ippGetCount(attr) != 1) { printf("FAIL (\"foo\" has %d values, expected 1)\n", (int)ippGetCount(attr)); status ++; } else if (strcmp(ippGetString(attr, 0, NULL), "1234")) { printf("FAIL (\"foo\" has value %s, expected 1234)\n", ippGetString(attr, 0, NULL)); status ++; } else if ((attr = ippFindAttribute(request, "auth-info", IPP_TAG_ZERO)) == NULL) { puts("FAIL (Unable to find attribute \"auth-info\")"); status ++; } else if (ippGetValueTag(attr) != IPP_TAG_TEXT) { printf("FAIL (\"auth-info\" of type %s, expected text)\n", ippTagString(ippGetValueTag(attr))); status ++; } else if (ippGetCount(attr) != 2) { printf("FAIL (\"auth-info\" has %d values, expected 2)\n", (int)ippGetCount(attr)); status ++; } else if (strcmp(ippGetString(attr, 0, NULL), "user")) { printf("FAIL (\"auth-info\"[0] has value \"%s\", expected \"user\")\n", ippGetString(attr, 0, NULL)); status ++; } else if (strcmp(ippGetString(attr, 1, NULL), "pass,word\\")) { printf("FAIL (\"auth-info\"[1] has value \"%s\", expected \"pass,word\\\")\n", ippGetString(attr, 1, NULL)); status ++; } else puts("PASS"); } else { int i; /* Looping var */ cups_option_t *option; /* Current option */ num_options = cupsParseOptions(argv[1], 0, &options); for (i = 0, option = options; i < num_options; i ++, option ++) printf("options[%d].name=\"%s\", value=\"%s\"\n", i, option->name, option->value); } exit (status); } ippsample/cups/md5-private.h0000644000175000017500000000504013240604116015016 0ustar tilltill/* * Private MD5 definitions for CUPS. * * Copyright 2007-2010 by Apple Inc. * Copyright 2005 by Easy Software Products * * Copyright (C) 1999 Aladdin Enterprises. All rights reserved. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * L. Peter Deutsch * ghost@aladdin.com */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321. It is derived directly from the text of the RFC and not from the reference implementation. The original and principal author of md5.h is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ #ifndef _CUPS_MD5_PRIVATE_H_ # define _CUPS_MD5_PRIVATE_H_ /* Define the state of the MD5 Algorithm. */ typedef struct _cups_md5_state_s { unsigned int count[2]; /* message length in bits, lsw first */ unsigned int abcd[4]; /* digest buffer */ unsigned char buf[64]; /* accumulate block */ } _cups_md5_state_t; # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* Initialize the algorithm. */ void _cupsMD5Init(_cups_md5_state_t *pms); /* Append a string to the message. */ void _cupsMD5Append(_cups_md5_state_t *pms, const unsigned char *data, int nbytes); /* Finish the message and return the digest. */ void _cupsMD5Finish(_cups_md5_state_t *pms, unsigned char digest[16]); # ifdef __cplusplus } /* end extern "C" */ # endif /* __cplusplus */ #endif /* !_CUPS_MD5_PRIVATE_H_ */ ippsample/cups/pwg-private.h0000644000175000017500000000174013240604116015131 0ustar tilltill/* * Private PWG media API definitions for CUPS. * * Copyright 2009-2016 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_PWG_PRIVATE_H_ # define _CUPS_PWG_PRIVATE_H_ /* * Include necessary headers... */ # include /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Functions... */ extern void _pwgGenerateSize(char *keyword, size_t keysize, const char *prefix, const char *name, int width, int length) _CUPS_INTERNAL_MSG("Use pwgFormatSizeName instead."); extern int _pwgInitSize(pwg_size_t *size, ipp_t *job, int *margins_set) _CUPS_INTERNAL_MSG("Use pwgInitSize instead."); extern const pwg_media_t *_pwgMediaTable(size_t *num_media); extern pwg_media_t *_pwgMediaNearSize(int width, int length, int epsilon); # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_PWG_PRIVATE_H_ */ ippsample/cups/Makefile0000644000175000017500000001256113240604116014156 0ustar tilltill# # API library Makefile for the CUPS library. # # Copyright © 2014-2018 by the IEEE-ISTO Printer Working Group. # Copyright © 2007-2018 by Apple Inc. # Copyright © 1997-2006 by Easy Software Products, all rights reserved. # # Licensed under Apache License v2.0. See the file "LICENSE" for more # information. # include ../Makedefs # # Options to build libcups without the use of deprecated APIs... # OPTIONS = -D_CUPS_NO_DEPRECATED=1 # # Object files... # LIBOBJS = \ array.o \ auth.o \ debug.o \ dest.o \ dest-job.o \ dest-localization.o \ dest-options.o \ dir.o \ encode.o \ error.o \ file.o \ getputfile.o \ globals.o \ hash.o \ http.o \ http-addr.o \ http-addrlist.o \ http-support.o \ ipp.o \ ipp-file.o \ ipp-support.o \ ipp-vars.o \ langprintf.o \ language.o \ md5.o \ md5passwd.o \ notify.o \ options.o \ pwg-media.o \ raster.o \ request.o \ snprintf.o \ string.o \ tempfile.o \ thread.o \ tls.o \ transcode.o \ usersys.o \ util.o TESTOBJS = \ testarray.o \ testclient.o \ testdest.o \ testfile.o \ testhttp.o \ testi18n.o \ testipp.o \ testoptions.o \ testraster.o OBJS = \ $(LIBOBJS) \ $(TESTOBJS) HEADERS = \ array.h \ cups.h \ dir.h \ file.h \ http.h \ ipp.h \ language.h \ pwg.h \ raster.h \ transcode.h \ versioning.h # # Targets in this directory... # TARGETS = libcups.a TESTS = $(TESTOBJS:.o=) # # Make all targets... # all: $(TARGETS) # # Remove object and target files... # clean: $(RM) $(OBJS) $(TARGETS) $(TESTS) # # Update dependencies (without system header dependencies...) # depend: $(CC) -MM $(ALL_CFLAGS) $(OBJS:.o=.c) >Dependencies # # Install the client library... # install: all $(INSTALL_DIR) -m 755 $(BUILDROOT)$(libdir) $(INSTALL_LIB) -m 755 libcups.a $(BUILDROOT)$(libdir) $(RANLIB) $(BUILDROOT)$(libdir)/libcups.a $(INSTALL_DIR) -m 755 $(BUILDROOT)$(includedir)/cups for file in $(HEADERS); do \ $(INSTALL_DATA) $$file $(BUILDROOT)$(includedir)/cups; \ done # # Test the library. # test: $(TESTS) echo Running unit tests... for test in $(TESTS); do \ echo ""; \ echo Running $$test...; \ ./$$test || exit 1; \ done # # libcups.a # libcups.a: $(LIBOBJS) echo Archiving $@... $(RM) $@ $(AR) $(ARFLAGS) $@ $(LIBOBJS) $(RANLIB) $@ # # libcups2.def (Windows DLL exports file...) # libcups2.def: $(OBJS) Makefile echo Generating $@... echo "LIBRARY libcups2" >libcups2.def echo "VERSION 2.12" >>libcups2.def echo "EXPORTS" >>libcups2.def (nm $(OBJS) 2>/dev/null | grep "T _" | awk '{print $$3}'; \ echo __cups_strcpy; echo __cups_strlcat; echo __cups_strlcpy) | \ grep -v -E \ -e 'cups_debug|Apple|GSSService|SetNegotiate' \ -e 'Block$$' | \ sed -e '1,$$s/^_//' | sort >>libcups2.def # # Unit tests # testarray: testarray.o echo Linking $@... $(CC) $(LDFLAGS) -o $@ testarray.o $(LIBS) testclient: testclient.o echo Linking $@... $(CC) $(LDFLAGS) -o $@ testclient.o $(LIBS) testdest: testdest.o echo Linking $@... $(CC) $(LDFLAGS) -o $@ testdest.o $(LIBS) testfile: testfile.o echo Linking $@... $(CC) $(LDFLAGS) -o $@ testfile.o $(LIBS) testhttp: testhttp.o echo Linking $@... $(CC) $(LDFLAGS) -o $@ testhttp.o $(LIBS) testi18n: testi18n.o echo Linking $@... $(CC) $(LDFLAGS) -o $@ testi18n.o $(LIBS) testipp: testipp.o echo Linking $@... $(CC) $(LDFLAGS) -o $@ testipp.o $(LIBS) testoptions: testoptions.o echo Linking $@... $(CC) $(LDFLAGS) -o $@ testoptions.o $(LIBS) testraster: testraster.o echo Linking $@... $(CC) $(LDFLAGS) -o $@ testraster.o $(LIBS) # # Automatic API help files... # APISOURCES = \ auth.c \ cups.h \ dest.c \ dest-job.c \ dest-localization.c \ dest-options.c \ encode.c \ error.c \ getputfile.c \ hash.c \ http.c \ http.h \ http-addr.c \ http-addrlist.c \ http-support.c \ ipp.c \ ipp.h \ ipp-support.c \ md5passwd.c \ notify.c \ options.c \ pwg.h \ pwg-media.c \ raster.c \ raster.h \ request.c \ tls.c \ usersys.c \ util.c apihelp: echo Generating CUPS API help files... mxmldoc --title "CUPS API Programming Guide" \ --author "Michael R Sweet" \ --copyright "Copyright 2007-2017 by Apple Inc." \ --docversion $(IPPSAMPLE_VERSION) \ --intro api.intro \ api.xml $(APISOURCES) >../doc/api.html mxmldoc --title "CUPS API Programming Guide" \ --author "Michael R Sweet" \ --copyright "Copyright 2007-2017 by Apple Inc." \ --docversion $(IPPSAMPLE_VERSION) \ --intro api.intro \ --epub ../doc/api.epub \ api.xml if test `uname` = Darwin; then \ mxmldoc --title "CUPS API Programming Guide" \ --author "Michael R Sweet" \ --copyright "Copyright 2007-2017 by Apple Inc." \ --docversion $(IPPSAMPLE_VERSION) \ --intro api.intro \ --docset org.pwg.ippsample.docset \ --feedname org.pwg.ippsample \ --feedurl https://istopwg.github.io/ippsample/org.pwg.ippsample.atom \ api.xml; \ $(RM) org.pwg.ippsample.atom; \ xcrun docsetutil package --output org.pwg.ippsample.xar \ --atom org.pwg.ippsample.atom \ --download-url https://istopwg.github.io/ippsample/org.pwg.ippsample.xar \ org.pwg.ippsample.docset || exit 1; \ fi $(RM) api.xml # # Dependencies... # include Dependencies tls.o: tls-darwin.c tls-gnutls.c tls-sspi.c ippsample/cups/dest-options.c0000644000175000017500000023101513240604116015307 0ustar tilltill/* * Destination option/media support for CUPS. * * Copyright © 2012-2018 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ /* * Include necessary headers... */ #include "cups-private.h" /* * Local constants... */ #define _CUPS_MEDIA_READY_TTL 30 /* Life of xxx-ready values */ /* * Local functions... */ static void cups_add_dconstres(cups_array_t *a, ipp_t *collection); static int cups_collection_contains(ipp_t *test, ipp_t *match); static size_t cups_collection_string(ipp_attribute_t *attr, char *buffer, size_t bufsize); static int cups_compare_dconstres(_cups_dconstres_t *a, _cups_dconstres_t *b); static int cups_compare_media_db(_cups_media_db_t *a, _cups_media_db_t *b); static _cups_media_db_t *cups_copy_media_db(_cups_media_db_t *mdb); static void cups_create_cached(http_t *http, cups_dinfo_t *dinfo, unsigned flags); static void cups_create_constraints(cups_dinfo_t *dinfo); static void cups_create_defaults(cups_dinfo_t *dinfo); static void cups_create_media_db(cups_dinfo_t *dinfo, unsigned flags); static void cups_free_media_db(_cups_media_db_t *mdb); static int cups_get_media_db(http_t *http, cups_dinfo_t *dinfo, pwg_media_t *pwg, unsigned flags, cups_size_t *size); static int cups_is_close_media_db(_cups_media_db_t *a, _cups_media_db_t *b); static cups_array_t *cups_test_constraints(cups_dinfo_t *dinfo, const char *new_option, const char *new_value, int num_options, cups_option_t *options, int *num_conflicts, cups_option_t **conflicts); static void cups_update_ready(http_t *http, cups_dinfo_t *dinfo); /* * 'cupsAddDestMediaOptions()' - Add the option corresponding to the specified media size. * * @since CUPS 2.3@ */ int /* O - New number of options */ cupsAddDestMediaOptions( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ unsigned flags, /* I - Media matching flags */ cups_size_t *size, /* I - Media size */ int num_options, /* I - Current number of options */ cups_option_t **options) /* IO - Options */ { cups_array_t *db; /* Media database */ _cups_media_db_t *mdb; /* Media database entry */ char value[2048]; /* Option value */ /* * Range check input... */ if (!http || !dest || !dinfo || !size || !options) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (num_options); } /* * Find the matching media size... */ if (flags & CUPS_MEDIA_FLAGS_READY) db = dinfo->ready_db; else db = dinfo->media_db; DEBUG_printf(("1cupsAddDestMediaOptions: size->media=\"%s\"", size->media)); for (mdb = (_cups_media_db_t *)cupsArrayFirst(db); mdb; mdb = (_cups_media_db_t *)cupsArrayNext(db)) { if (mdb->key && !strcmp(mdb->key, size->media)) break; else if (mdb->size_name && !strcmp(mdb->size_name, size->media)) break; } if (!mdb) { for (mdb = (_cups_media_db_t *)cupsArrayFirst(db); mdb; mdb = (_cups_media_db_t *)cupsArrayNext(db)) { if (mdb->width == size->width && mdb->length == size->length && mdb->bottom == size->bottom && mdb->left == size->left && mdb->right == size->right && mdb->top == size->top) break; } } if (!mdb) { for (mdb = (_cups_media_db_t *)cupsArrayFirst(db); mdb; mdb = (_cups_media_db_t *)cupsArrayNext(db)) { if (mdb->width == size->width && mdb->length == size->length) break; } } if (!mdb) { DEBUG_puts("1cupsAddDestMediaOptions: Unable to find matching size."); return (num_options); } DEBUG_printf(("1cupsAddDestMediaOptions: MATCH mdb%p [key=\"%s\" size_name=\"%s\" source=\"%s\" type=\"%s\" width=%d length=%d B%d L%d R%d T%d]", (void *)mdb, mdb->key, mdb->size_name, mdb->source, mdb->type, mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top)); if (mdb->source) { if (mdb->type) snprintf(value, sizeof(value), "{media-size={x-dimension=%d y-dimension=%d} media-bottom-margin=%d media-left-margin=%d media-right-margin=%d media-top-margin=%d media-source=\"%s\" media-type=\"%s\"}", mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top, mdb->source, mdb->type); else snprintf(value, sizeof(value), "{media-size={x-dimension=%d y-dimension=%d} media-bottom-margin=%d media-left-margin=%d media-right-margin=%d media-top-margin=%d media-source=\"%s\"}", mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top, mdb->source); } else if (mdb->type) { snprintf(value, sizeof(value), "{media-size={x-dimension=%d y-dimension=%d} media-bottom-margin=%d media-left-margin=%d media-right-margin=%d media-top-margin=%d media-type=\"%s\"}", mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top, mdb->type); } else { snprintf(value, sizeof(value), "{media-size={x-dimension=%d y-dimension=%d} media-bottom-margin=%d media-left-margin=%d media-right-margin=%d media-top-margin=%d}", mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top); } num_options = cupsAddOption("media-col", value, num_options, options); return (num_options); } /* * 'cupsCheckDestSupported()' - Check that the option and value are supported * by the destination. * * Returns 1 if supported, 0 otherwise. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 if supported, 0 otherwise */ cupsCheckDestSupported( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ const char *option, /* I - Option */ const char *value) /* I - Value or @code NULL@ */ { int i; /* Looping var */ char temp[1024]; /* Temporary string */ int int_value; /* Integer value */ int xres_value, /* Horizontal resolution */ yres_value; /* Vertical resolution */ ipp_res_t units_value; /* Resolution units */ ipp_attribute_t *attr; /* Attribute */ _ipp_value_t *attrval; /* Current attribute value */ /* * Get the default connection as needed... */ if (!http) http = _cupsConnect(); /* * Range check input... */ if (!http || !dest || !dinfo || !option) return (0); /* * Lookup the attribute... */ if (strstr(option, "-supported")) attr = ippFindAttribute(dinfo->attrs, option, IPP_TAG_ZERO); else { snprintf(temp, sizeof(temp), "%s-supported", option); attr = ippFindAttribute(dinfo->attrs, temp, IPP_TAG_ZERO); } if (!attr) return (0); if (!value) return (1); /* * Compare values... */ if (!strcmp(option, "media") && !strncmp(value, "custom_", 7)) { /* * Check range of custom media sizes... */ pwg_media_t *pwg; /* Current PWG media size info */ int min_width, /* Minimum width */ min_length, /* Minimum length */ max_width, /* Maximum width */ max_length; /* Maximum length */ /* * Get the minimum and maximum size... */ min_width = min_length = INT_MAX; max_width = max_length = 0; for (i = attr->num_values, attrval = attr->values; i > 0; i --, attrval ++) { if (!strncmp(attrval->string.text, "custom_min_", 11) && (pwg = pwgMediaForPWG(attrval->string.text)) != NULL) { min_width = pwg->width; min_length = pwg->length; } else if (!strncmp(attrval->string.text, "custom_max_", 11) && (pwg = pwgMediaForPWG(attrval->string.text)) != NULL) { max_width = pwg->width; max_length = pwg->length; } } /* * Check the range... */ if (min_width < INT_MAX && max_width > 0 && (pwg = pwgMediaForPWG(value)) != NULL && pwg->width >= min_width && pwg->width <= max_width && pwg->length >= min_length && pwg->length <= max_length) return (1); } else { /* * Check literal values... */ switch (attr->value_tag) { case IPP_TAG_INTEGER : case IPP_TAG_ENUM : int_value = atoi(value); for (i = 0; i < attr->num_values; i ++) if (attr->values[i].integer == int_value) return (1); break; case IPP_TAG_BOOLEAN : return (attr->values[0].boolean); case IPP_TAG_RANGE : int_value = atoi(value); for (i = 0; i < attr->num_values; i ++) if (int_value >= attr->values[i].range.lower && int_value <= attr->values[i].range.upper) return (1); break; case IPP_TAG_RESOLUTION : if (sscanf(value, "%dx%d%15s", &xres_value, &yres_value, temp) != 3) { if (sscanf(value, "%d%15s", &xres_value, temp) != 2) return (0); yres_value = xres_value; } if (!strcmp(temp, "dpi")) units_value = IPP_RES_PER_INCH; else if (!strcmp(temp, "dpc") || !strcmp(temp, "dpcm")) units_value = IPP_RES_PER_CM; else return (0); for (i = attr->num_values, attrval = attr->values; i > 0; i --, attrval ++) { if (attrval->resolution.xres == xres_value && attrval->resolution.yres == yres_value && attrval->resolution.units == units_value) return (1); } break; case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : case IPP_TAG_CHARSET : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_MIMETYPE : case IPP_TAG_LANGUAGE : case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : for (i = 0; i < attr->num_values; i ++) if (!strcmp(attr->values[i].string.text, value)) return (1); break; default : break; } } /* * If we get there the option+value is not supported... */ return (0); } /* * 'cupsCopyDestConflicts()' - Get conflicts and resolutions for a new * option/value pair. * * "num_options" and "options" represent the currently selected options by the * user. "new_option" and "new_value" are the setting the user has just * changed. * * Returns 1 if there is a conflict, 0 if there are no conflicts, and -1 if * there was an unrecoverable error such as a resolver loop. * * If "num_conflicts" and "conflicts" are not @code NULL@, they are set to * contain the list of conflicting option/value pairs. Similarly, if * "num_resolved" and "resolved" are not @code NULL@ they will be set to the * list of changes needed to resolve the conflict. * * If cupsCopyDestConflicts returns 1 but "num_resolved" and "resolved" are set * to 0 and @code NULL@, respectively, then the conflict cannot be resolved. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 if there is a conflict, 0 if none, -1 on error */ cupsCopyDestConflicts( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ int num_options, /* I - Number of current options */ cups_option_t *options, /* I - Current options */ const char *new_option, /* I - New option */ const char *new_value, /* I - New value */ int *num_conflicts, /* O - Number of conflicting options */ cups_option_t **conflicts, /* O - Conflicting options */ int *num_resolved, /* O - Number of options to resolve */ cups_option_t **resolved) /* O - Resolved options */ { int i, /* Looping var */ have_conflicts = 0, /* Do we have conflicts? */ changed, /* Did we change something? */ tries, /* Number of tries for resolution */ num_myconf = 0, /* My number of conflicting options */ num_myres = 0; /* My number of resolved options */ cups_option_t *myconf = NULL, /* My conflicting options */ *myres = NULL, /* My resolved options */ *myoption, /* My current option */ *option; /* Current option */ cups_array_t *active = NULL, /* Active conflicts */ *pass = NULL, /* Resolvers for this pass */ *resolvers = NULL, /* Resolvers we have used */ *test; /* Test array for conflicts */ _cups_dconstres_t *c, /* Current constraint */ *r; /* Current resolver */ ipp_attribute_t *attr; /* Current attribute */ char value[2048]; /* Current attribute value as string */ const char *myvalue; /* Current value of an option */ /* * Clear returned values... */ if (num_conflicts) *num_conflicts = 0; if (conflicts) *conflicts = NULL; if (num_resolved) *num_resolved = 0; if (resolved) *resolved = NULL; /* * Get the default connection as needed... */ if (!http) http = _cupsConnect(); /* * Range check input... */ if (!http || !dest || !dinfo || (num_conflicts != NULL) != (conflicts != NULL) || (num_resolved != NULL) != (resolved != NULL)) return (0); /* * Load constraints as needed... */ if (!dinfo->constraints) cups_create_constraints(dinfo); if (cupsArrayCount(dinfo->constraints) == 0) return (0); if (!dinfo->num_defaults) cups_create_defaults(dinfo); /* * If we are resolving, create a shadow array... */ if (num_resolved) { for (i = num_options, option = options; i > 0; i --, option ++) num_myres = cupsAddOption(option->name, option->value, num_myres, &myres); if (new_option && new_value) num_myres = cupsAddOption(new_option, new_value, num_myres, &myres); } else { num_myres = num_options; myres = options; } /* * Check for any conflicts... */ if (num_resolved) pass = cupsArrayNew((cups_array_func_t)cups_compare_dconstres, NULL); for (tries = 0; tries < 100; tries ++) { /* * Check for any conflicts... */ if (num_conflicts || num_resolved) { cupsFreeOptions(num_myconf, myconf); num_myconf = 0; myconf = NULL; active = cups_test_constraints(dinfo, new_option, new_value, num_myres, myres, &num_myconf, &myconf); } else active = cups_test_constraints(dinfo, new_option, new_value, num_myres, myres, NULL, NULL); have_conflicts = (active != NULL); if (!active || !num_resolved) break; /* All done */ /* * Scan the constraints that were triggered to apply resolvers... */ if (!resolvers) resolvers = cupsArrayNew((cups_array_func_t)cups_compare_dconstres, NULL); for (c = (_cups_dconstres_t *)cupsArrayFirst(active), changed = 0; c; c = (_cups_dconstres_t *)cupsArrayNext(active)) { if (cupsArrayFind(pass, c)) continue; /* Already applied this resolver... */ if (cupsArrayFind(resolvers, c)) { DEBUG_printf(("1cupsCopyDestConflicts: Resolver loop with %s.", c->name)); have_conflicts = -1; goto cleanup; } if ((r = cupsArrayFind(dinfo->resolvers, c)) == NULL) { DEBUG_printf(("1cupsCopyDestConflicts: Resolver %s not found.", c->name)); have_conflicts = -1; goto cleanup; } /* * Add the options from the resolver... */ cupsArrayAdd(pass, r); cupsArrayAdd(resolvers, r); for (attr = ippFirstAttribute(r->collection); attr; attr = ippNextAttribute(r->collection)) { if (new_option && !strcmp(attr->name, new_option)) continue; /* Ignore this if we just changed it */ if (ippAttributeString(attr, value, sizeof(value)) >= sizeof(value)) continue; /* Ignore if the value is too long */ if ((test = cups_test_constraints(dinfo, attr->name, value, num_myres, myres, NULL, NULL)) == NULL) { /* * That worked, flag it... */ changed = 1; } else cupsArrayDelete(test); /* * Add the option/value from the resolver regardless of whether it * worked; this makes sure that we can cascade several changes to * make things resolve... */ num_myres = cupsAddOption(attr->name, value, num_myres, &myres); } } if (!changed) { DEBUG_puts("1cupsCopyDestConflicts: Unable to resolve constraints."); have_conflicts = -1; goto cleanup; } cupsArrayClear(pass); cupsArrayDelete(active); active = NULL; } if (tries >= 100) { DEBUG_puts("1cupsCopyDestConflicts: Unable to resolve after 100 tries."); have_conflicts = -1; goto cleanup; } /* * Copy resolved options as needed... */ if (num_resolved) { for (i = num_myres, myoption = myres; i > 0; i --, myoption ++) { if ((myvalue = cupsGetOption(myoption->name, num_options, options)) == NULL || strcmp(myvalue, myoption->value)) { if (new_option && !strcmp(new_option, myoption->name) && new_value && !strcmp(new_value, myoption->value)) continue; *num_resolved = cupsAddOption(myoption->name, myoption->value, *num_resolved, resolved); } } } /* * Clean up... */ cleanup: cupsArrayDelete(active); cupsArrayDelete(pass); cupsArrayDelete(resolvers); if (num_resolved) { /* * Free shadow copy of options... */ cupsFreeOptions(num_myres, myres); } if (num_conflicts) { /* * Return conflicting options to caller... */ *num_conflicts = num_myconf; *conflicts = myconf; } else { /* * Free conflicting options... */ cupsFreeOptions(num_myconf, myconf); } return (have_conflicts); } /* * 'cupsCopyDestInfo()' - Get the supported values/capabilities for the * destination. * * The caller is responsible for calling @link cupsFreeDestInfo@ on the return * value. @code NULL@ is returned on error. * * @since CUPS 1.6/macOS 10.8@ */ cups_dinfo_t * /* O - Destination information */ cupsCopyDestInfo( http_t *http, /* I - Connection to destination */ cups_dest_t *dest) /* I - Destination */ { cups_dinfo_t *dinfo; /* Destination information */ unsigned dflags; /* Destination flags */ ipp_t *request, /* Get-Printer-Attributes request */ *response; /* Supported attributes */ int tries, /* Number of tries so far */ delay, /* Current retry delay */ prev_delay; /* Next retry delay */ const char *uri; /* Printer URI */ char resource[1024]; /* Resource path */ int version; /* IPP version */ ipp_status_t status; /* Status of request */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ static const char * const requested_attrs[] = { /* Requested attributes */ "job-template", "media-col-database", "printer-description" }; DEBUG_printf(("cupsCopyDestInfo(http=%p, dest=%p(%s))", (void *)http, (void *)dest, dest ? dest->name : "")); /* * Get the default connection as needed... */ if (!http) { DEBUG_puts("1cupsCopyDestInfo: Default server connection."); http = _cupsConnect(); dflags = CUPS_DEST_FLAGS_NONE; } #ifdef AF_LOCAL else if (httpAddrFamily(http->hostaddr) == AF_LOCAL) { DEBUG_puts("1cupsCopyDestInfo: Connection to server (domain socket)."); dflags = CUPS_DEST_FLAGS_NONE; } #endif /* AF_LOCAL */ else if ((strcmp(http->hostname, cg->server) && cg->server[0] != '/') || cg->ipp_port != httpAddrPort(http->hostaddr)) { DEBUG_printf(("1cupsCopyDestInfo: Connection to device (%s).", http->hostname)); dflags = CUPS_DEST_FLAGS_DEVICE; } else { DEBUG_printf(("1cupsCopyDestInfo: Connection to server (%s).", http->hostname)); dflags = CUPS_DEST_FLAGS_NONE; } /* * Range check input... */ if (!http || !dest) return (NULL); /* * Get the printer URI and resource path... */ if ((uri = _cupsGetDestResource(dest, dflags, resource, sizeof(resource))) == NULL) { DEBUG_puts("1cupsCopyDestInfo: Unable to get resource."); return (NULL); } /* * Get the supported attributes... */ delay = 1; prev_delay = 1; tries = 0; version = 20; do { /* * Send a Get-Printer-Attributes request... */ request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); ippSetVersion(request, version / 10, version % 10); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(requested_attrs) / sizeof(requested_attrs[0])), NULL, requested_attrs); response = cupsDoRequest(http, request, resource); status = cupsLastError(); if (status > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED) { DEBUG_printf(("1cupsCopyDestInfo: Get-Printer-Attributes for '%s' returned %s (%s)", dest->name, ippErrorString(status), cupsLastErrorString())); ippDelete(response); response = NULL; if ((status == IPP_STATUS_ERROR_BAD_REQUEST || status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED) && version > 11) { version = 11; } else if (status == IPP_STATUS_ERROR_BUSY) { sleep((unsigned)delay); delay = _cupsNextDelay(delay, &prev_delay); } else return (NULL); } tries ++; } while (!response && tries < 10); if (!response) { DEBUG_puts("1cupsCopyDestInfo: Unable to get printer attributes."); return (NULL); } /* * Allocate a cups_dinfo_t structure and return it... */ if ((dinfo = calloc(1, sizeof(cups_dinfo_t))) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); ippDelete(response); return (NULL); } DEBUG_printf(("1cupsCopyDestInfo: version=%d, uri=\"%s\", resource=\"%s\".", version, uri, resource)); dinfo->version = version; dinfo->uri = uri; dinfo->resource = _cupsStrAlloc(resource); dinfo->attrs = response; return (dinfo); } /* * 'cupsFindDestDefault()' - Find the default value(s) for the given option. * * The returned value is an IPP attribute. Use the @code ippGetBoolean@, * @code ippGetCollection@, @code ippGetCount@, @code ippGetDate@, * @code ippGetInteger@, @code ippGetOctetString@, @code ippGetRange@, * @code ippGetResolution@, @code ippGetString@, and @code ippGetValueTag@ * functions to inspect the default value(s) as needed. * * @since CUPS 1.7/macOS 10.9@ */ ipp_attribute_t * /* O - Default attribute or @code NULL@ for none */ cupsFindDestDefault( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ const char *option) /* I - Option/attribute name */ { char name[IPP_MAX_NAME]; /* Attribute name */ /* * Get the default connection as needed... */ if (!http) http = _cupsConnect(); /* * Range check input... */ if (!http || !dest || !dinfo || !option) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (NULL); } /* * Find and return the attribute... */ snprintf(name, sizeof(name), "%s-default", option); return (ippFindAttribute(dinfo->attrs, name, IPP_TAG_ZERO)); } /* * 'cupsFindDestReady()' - Find the default value(s) for the given option. * * The returned value is an IPP attribute. Use the @code ippGetBoolean@, * @code ippGetCollection@, @code ippGetCount@, @code ippGetDate@, * @code ippGetInteger@, @code ippGetOctetString@, @code ippGetRange@, * @code ippGetResolution@, @code ippGetString@, and @code ippGetValueTag@ * functions to inspect the default value(s) as needed. * * @since CUPS 1.7/macOS 10.9@ */ ipp_attribute_t * /* O - Default attribute or @code NULL@ for none */ cupsFindDestReady( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ const char *option) /* I - Option/attribute name */ { char name[IPP_MAX_NAME]; /* Attribute name */ /* * Get the default connection as needed... */ if (!http) http = _cupsConnect(); /* * Range check input... */ if (!http || !dest || !dinfo || !option) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (NULL); } /* * Find and return the attribute... */ cups_update_ready(http, dinfo); snprintf(name, sizeof(name), "%s-ready", option); return (ippFindAttribute(dinfo->ready_attrs, name, IPP_TAG_ZERO)); } /* * 'cupsFindDestSupported()' - Find the default value(s) for the given option. * * The returned value is an IPP attribute. Use the @code ippGetBoolean@, * @code ippGetCollection@, @code ippGetCount@, @code ippGetDate@, * @code ippGetInteger@, @code ippGetOctetString@, @code ippGetRange@, * @code ippGetResolution@, @code ippGetString@, and @code ippGetValueTag@ * functions to inspect the default value(s) as needed. * * @since CUPS 1.7/macOS 10.9@ */ ipp_attribute_t * /* O - Default attribute or @code NULL@ for none */ cupsFindDestSupported( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ const char *option) /* I - Option/attribute name */ { char name[IPP_MAX_NAME]; /* Attribute name */ /* * Get the default connection as needed... */ if (!http) http = _cupsConnect(); /* * Range check input... */ if (!http || !dest || !dinfo || !option) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (NULL); } /* * Find and return the attribute... */ snprintf(name, sizeof(name), "%s-supported", option); return (ippFindAttribute(dinfo->attrs, name, IPP_TAG_ZERO)); } /* * 'cupsFreeDestInfo()' - Free destination information obtained using * @link cupsCopyDestInfo@. * * @since CUPS 1.6/macOS 10.8@ */ void cupsFreeDestInfo(cups_dinfo_t *dinfo) /* I - Destination information */ { /* * Range check input... */ if (!dinfo) return; /* * Free memory and return... */ _cupsStrFree(dinfo->resource); cupsArrayDelete(dinfo->constraints); cupsArrayDelete(dinfo->resolvers); cupsArrayDelete(dinfo->localizations); cupsArrayDelete(dinfo->media_db); cupsArrayDelete(dinfo->cached_db); ippDelete(dinfo->ready_attrs); cupsArrayDelete(dinfo->ready_db); ippDelete(dinfo->attrs); free(dinfo); } /* * 'cupsGetDestMediaByIndex()' - Get a media name, dimension, and margins for a * specific size. * * The @code flags@ parameter determines which set of media are indexed. For * example, passing @code CUPS_MEDIA_FLAGS_BORDERLESS@ will get the Nth * borderless size supported by the printer. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - 1 on success, 0 on failure */ cupsGetDestMediaByIndex( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ int n, /* I - Media size number (0-based) */ unsigned flags, /* I - Media flags */ cups_size_t *size) /* O - Media size information */ { _cups_media_db_t *nsize; /* Size for N */ pwg_media_t *pwg; /* PWG media name for size */ /* * Get the default connection as needed... */ if (!http) http = _cupsConnect(); /* * Range check input... */ if (size) memset(size, 0, sizeof(cups_size_t)); if (!http || !dest || !dinfo || n < 0 || !size) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (0); } /* * Load media list as needed... */ if (flags & CUPS_MEDIA_FLAGS_READY) cups_update_ready(http, dinfo); if (!dinfo->cached_db || dinfo->cached_flags != flags) cups_create_cached(http, dinfo, flags); /* * Copy the size over and return... */ if ((nsize = (_cups_media_db_t *)cupsArrayIndex(dinfo->cached_db, n)) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (0); } if (nsize->key) strlcpy(size->media, nsize->key, sizeof(size->media)); else if (nsize->size_name) strlcpy(size->media, nsize->size_name, sizeof(size->media)); else if ((pwg = pwgMediaForSize(nsize->width, nsize->length)) != NULL) strlcpy(size->media, pwg->pwg, sizeof(size->media)); else { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (0); } size->width = nsize->width; size->length = nsize->length; size->bottom = nsize->bottom; size->left = nsize->left; size->right = nsize->right; size->top = nsize->top; return (1); } /* * 'cupsGetDestMediaByName()' - Get media names, dimensions, and margins. * * The "media" string is a PWG media name. "Flags" provides some matching * guidance (multiple flags can be combined): * * CUPS_MEDIA_FLAGS_DEFAULT = find the closest size supported by the printer, * CUPS_MEDIA_FLAGS_BORDERLESS = find a borderless size, * CUPS_MEDIA_FLAGS_DUPLEX = find a size compatible with 2-sided printing, * CUPS_MEDIA_FLAGS_EXACT = find an exact match for the size, and * CUPS_MEDIA_FLAGS_READY = if the printer supports media sensing, find the * size amongst the "ready" media. * * The matching result (if any) is returned in the "cups_size_t" structure. * * Returns 1 when there is a match and 0 if there is not a match. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on match, 0 on failure */ cupsGetDestMediaByName( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ const char *media, /* I - Media name */ unsigned flags, /* I - Media matching flags */ cups_size_t *size) /* O - Media size information */ { pwg_media_t *pwg; /* PWG media info */ /* * Get the default connection as needed... */ if (!http) http = _cupsConnect(); /* * Range check input... */ if (size) memset(size, 0, sizeof(cups_size_t)); if (!http || !dest || !dinfo || !media || !size) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (0); } /* * Lookup the media size name... */ if ((pwg = pwgMediaForPWG(media)) == NULL) if ((pwg = pwgMediaForLegacy(media)) == NULL) { DEBUG_printf(("1cupsGetDestMediaByName: Unknown size '%s'.", media)); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown media size name."), 1); return (0); } /* * Lookup the size... */ return (cups_get_media_db(http, dinfo, pwg, flags, size)); } /* * 'cupsGetDestMediaBySize()' - Get media names, dimensions, and margins. * * "Width" and "length" are the dimensions in hundredths of millimeters. * "Flags" provides some matching guidance (multiple flags can be combined): * * CUPS_MEDIA_FLAGS_DEFAULT = find the closest size supported by the printer, * CUPS_MEDIA_FLAGS_BORDERLESS = find a borderless size, * CUPS_MEDIA_FLAGS_DUPLEX = find a size compatible with 2-sided printing, * CUPS_MEDIA_FLAGS_EXACT = find an exact match for the size, and * CUPS_MEDIA_FLAGS_READY = if the printer supports media sensing, find the * size amongst the "ready" media. * * The matching result (if any) is returned in the "cups_size_t" structure. * * Returns 1 when there is a match and 0 if there is not a match. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on match, 0 on failure */ cupsGetDestMediaBySize( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ int width, /* I - Media width in hundredths of * of millimeters */ int length, /* I - Media length in hundredths of * of millimeters */ unsigned flags, /* I - Media matching flags */ cups_size_t *size) /* O - Media size information */ { pwg_media_t *pwg; /* PWG media info */ /* * Get the default connection as needed... */ if (!http) http = _cupsConnect(); /* * Range check input... */ if (size) memset(size, 0, sizeof(cups_size_t)); if (!http || !dest || !dinfo || width <= 0 || length <= 0 || !size) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (0); } /* * Lookup the media size name... */ if ((pwg = pwgMediaForSize(width, length)) == NULL) { DEBUG_printf(("1cupsGetDestMediaBySize: Invalid size %dx%d.", width, length)); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid media size."), 1); return (0); } /* * Lookup the size... */ return (cups_get_media_db(http, dinfo, pwg, flags, size)); } /* * 'cupsGetDestMediaCount()' - Get the number of sizes supported by a * destination. * * The @code flags@ parameter determines the set of media sizes that are * counted. For example, passing @code CUPS_MEDIA_FLAGS_BORDERLESS@ will return * the number of borderless sizes. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - Number of sizes */ cupsGetDestMediaCount( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ unsigned flags) /* I - Media flags */ { /* * Get the default connection as needed... */ if (!http) http = _cupsConnect(); /* * Range check input... */ if (!http || !dest || !dinfo) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (0); } /* * Load media list as needed... */ if (flags & CUPS_MEDIA_FLAGS_READY) cups_update_ready(http, dinfo); if (!dinfo->cached_db || dinfo->cached_flags != flags) cups_create_cached(http, dinfo, flags); return (cupsArrayCount(dinfo->cached_db)); } /* * 'cupsGetDestMediaDefault()' - Get the default size for a destination. * * The @code flags@ parameter determines which default size is returned. For * example, passing @code CUPS_MEDIA_FLAGS_BORDERLESS@ will return the default * borderless size, typically US Letter or A4, but sometimes 4x6 photo media. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - 1 on success, 0 on failure */ cupsGetDestMediaDefault( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ unsigned flags, /* I - Media flags */ cups_size_t *size) /* O - Media size information */ { const char *media; /* Default media size */ /* * Get the default connection as needed... */ if (!http) http = _cupsConnect(); /* * Range check input... */ if (size) memset(size, 0, sizeof(cups_size_t)); if (!http || !dest || !dinfo || !size) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (0); } /* * Get the default media size, if any... */ if ((media = cupsGetOption("media", dest->num_options, dest->options)) == NULL) media = "na_letter_8.5x11in"; if (cupsGetDestMediaByName(http, dest, dinfo, media, flags, size)) return (1); if (strcmp(media, "na_letter_8.5x11in") && cupsGetDestMediaByName(http, dest, dinfo, "iso_a4_210x297mm", flags, size)) return (1); if (strcmp(media, "iso_a4_210x297mm") && cupsGetDestMediaByName(http, dest, dinfo, "na_letter_8.5x11in", flags, size)) return (1); if ((flags & CUPS_MEDIA_FLAGS_BORDERLESS) && cupsGetDestMediaByName(http, dest, dinfo, "na_index_4x6in", flags, size)) return (1); /* * Fall back to the first matching media size... */ return (cupsGetDestMediaByIndex(http, dest, dinfo, 0, flags, size)); } /* * 'cups_add_dconstres()' - Add a constraint or resolver to an array. */ static void cups_add_dconstres( cups_array_t *a, /* I - Array */ ipp_t *collection) /* I - Collection value */ { ipp_attribute_t *attr; /* Attribute */ _cups_dconstres_t *temp; /* Current constraint/resolver */ if ((attr = ippFindAttribute(collection, "resolver-name", IPP_TAG_NAME)) == NULL) return; if ((temp = calloc(1, sizeof(_cups_dconstres_t))) == NULL) return; temp->name = attr->values[0].string.text; temp->collection = collection; cupsArrayAdd(a, temp); } /* * 'cups_collection_contains()' - Check whether test collection is contained in the matching collection. */ static int /* O - 1 on a match, 0 on a non-match */ cups_collection_contains(ipp_t *test, /* I - Collection to test */ ipp_t *match) /* I - Matching values */ { int i, j, /* Looping vars */ mcount, /* Number of match values */ tcount; /* Number of test values */ ipp_attribute_t *tattr, /* Testing attribute */ *mattr; /* Matching attribute */ const char *tval; /* Testing string value */ for (mattr = ippFirstAttribute(match); mattr; mattr = ippNextAttribute(match)) { if ((tattr = ippFindAttribute(test, ippGetName(mattr), IPP_TAG_ZERO)) == NULL) return (0); tcount = ippGetCount(tattr); switch (ippGetValueTag(mattr)) { case IPP_TAG_INTEGER : case IPP_TAG_ENUM : if (ippGetValueTag(tattr) != ippGetValueTag(mattr)) return (0); for (i = 0; i < tcount; i ++) { if (!ippContainsInteger(mattr, ippGetInteger(tattr, i))) return (0); } break; case IPP_TAG_RANGE : if (ippGetValueTag(tattr) != IPP_TAG_INTEGER) return (0); for (i = 0; i < tcount; i ++) { if (!ippContainsInteger(mattr, ippGetInteger(tattr, i))) return (0); } break; case IPP_TAG_BOOLEAN : if (ippGetValueTag(tattr) != IPP_TAG_BOOLEAN || ippGetBoolean(tattr, 0) != ippGetBoolean(mattr, 0)) return (0); break; case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : for (i = 0; i < tcount; i ++) { if ((tval = ippGetString(tattr, i, NULL)) == NULL || !ippContainsString(mattr, tval)) return (0); } break; case IPP_TAG_BEGIN_COLLECTION : for (i = 0; i < tcount; i ++) { ipp_t *tcol = ippGetCollection(tattr, i); /* Testing collection */ for (j = 0, mcount = ippGetCount(mattr); j < mcount; j ++) if (!cups_collection_contains(tcol, ippGetCollection(mattr, j))) return (0); } break; default : return (0); } } return (1); } /* * 'cups_collection_string()' - Convert an IPP collection to an option string. */ static size_t /* O - Number of bytes needed */ cups_collection_string( ipp_attribute_t *attr, /* I - Collection attribute */ char *buffer, /* I - String buffer */ size_t bufsize) /* I - Size of buffer */ { int i, j, /* Looping vars */ count, /* Number of collection values */ mcount; /* Number of member values */ ipp_t *col; /* Collection */ ipp_attribute_t *first, /* First member attribute */ *member; /* Member attribute */ char *bufptr, /* Pointer into buffer */ *bufend, /* End of buffer */ temp[100]; /* Temporary string */ const char *mptr; /* Pointer into member value */ int mlen; /* Length of octetString */ bufptr = buffer; bufend = buffer + bufsize - 1; for (i = 0, count = ippGetCount(attr); i < count; i ++) { col = ippGetCollection(attr, i); if (i) { if (bufptr < bufend) *bufptr++ = ','; else bufptr ++; } if (bufptr < bufend) *bufptr++ = '{'; else bufptr ++; for (member = first = ippFirstAttribute(col); member; member = ippNextAttribute(col)) { const char *mname = ippGetName(member); if (member != first) { if (bufptr < bufend) *bufptr++ = ' '; else bufptr ++; } if (ippGetValueTag(member) == IPP_TAG_BOOLEAN) { if (!ippGetBoolean(member, 0)) { if (bufptr < bufend) strlcpy(bufptr, "no", (size_t)(bufend - bufptr + 1)); bufptr += 2; } if (bufptr < bufend) strlcpy(bufptr, mname, (size_t)(bufend - bufptr + 1)); bufptr += strlen(mname); continue; } if (bufptr < bufend) strlcpy(bufptr, mname, (size_t)(bufend - bufptr + 1)); bufptr += strlen(mname); if (bufptr < bufend) *bufptr++ = '='; else bufptr ++; if (ippGetValueTag(member) == IPP_TAG_BEGIN_COLLECTION) { /* * Convert sub-collection... */ bufptr += cups_collection_string(member, bufptr, bufptr < bufend ? (size_t)(bufend - bufptr + 1) : 0); } else { /* * Convert simple type... */ for (j = 0, mcount = ippGetCount(member); j < mcount; j ++) { if (j) { if (bufptr < bufend) *bufptr++ = ','; else bufptr ++; } switch (ippGetValueTag(member)) { case IPP_TAG_INTEGER : case IPP_TAG_ENUM : bufptr += snprintf(bufptr, bufptr < bufend ? (size_t)(bufend - bufptr + 1) : 0, "%d", ippGetInteger(member, j)); break; case IPP_TAG_STRING : if (bufptr < bufend) *bufptr++ = '\"'; else bufptr ++; for (mptr = (const char *)ippGetOctetString(member, j, &mlen); mlen > 0; mlen --, mptr ++) { if (*mptr == '\"' || *mptr == '\\') { if (bufptr < bufend) *bufptr++ = '\\'; else bufptr ++; } if (bufptr < bufend) *bufptr++ = *mptr; else bufptr ++; } if (bufptr < bufend) *bufptr++ = '\"'; else bufptr ++; break; case IPP_TAG_DATE : { unsigned year; /* Year */ const ipp_uchar_t *date = ippGetDate(member, j); /* Date value */ year = ((unsigned)date[0] << 8) + (unsigned)date[1]; if (date[9] == 0 && date[10] == 0) snprintf(temp, sizeof(temp), "%04u-%02u-%02uT%02u:%02u:%02uZ", year, date[2], date[3], date[4], date[5], date[6]); else snprintf(temp, sizeof(temp), "%04u-%02u-%02uT%02u:%02u:%02u%c%02u%02u", year, date[2], date[3], date[4], date[5], date[6], date[8], date[9], date[10]); if (buffer && bufptr < bufend) strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1)); bufptr += strlen(temp); } break; case IPP_TAG_RESOLUTION : { int xres, /* Horizontal resolution */ yres; /* Vertical resolution */ ipp_res_t units; /* Resolution units */ xres = ippGetResolution(member, j, &yres, &units); if (xres == yres) snprintf(temp, sizeof(temp), "%d%s", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); else snprintf(temp, sizeof(temp), "%dx%d%s", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); if (buffer && bufptr < bufend) strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1)); bufptr += strlen(temp); } break; case IPP_TAG_RANGE : { int lower, /* Lower bound */ upper; /* Upper bound */ lower = ippGetRange(member, j, &upper); snprintf(temp, sizeof(temp), "%d-%d", lower, upper); if (buffer && bufptr < bufend) strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1)); bufptr += strlen(temp); } break; case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : if (bufptr < bufend) *bufptr++ = '\"'; else bufptr ++; for (mptr = ippGetString(member, j, NULL); *mptr; mptr ++) { if (*mptr == '\"' || *mptr == '\\') { if (bufptr < bufend) *bufptr++ = '\\'; else bufptr ++; } if (bufptr < bufend) *bufptr++ = *mptr; else bufptr ++; } if (bufptr < bufend) *bufptr++ = '\"'; else bufptr ++; break; default : break; } } } } if (bufptr < bufend) *bufptr++ = '}'; else bufptr ++; } *bufptr = '\0'; return ((size_t)(bufptr - buffer + 1)); } /* * 'cups_compare_dconstres()' - Compare to resolver entries. */ static int /* O - Result of comparison */ cups_compare_dconstres( _cups_dconstres_t *a, /* I - First resolver */ _cups_dconstres_t *b) /* I - Second resolver */ { return (strcmp(a->name, b->name)); } /* * 'cups_compare_media_db()' - Compare two media entries. */ static int /* O - Result of comparison */ cups_compare_media_db( _cups_media_db_t *a, /* I - First media entries */ _cups_media_db_t *b) /* I - Second media entries */ { int result; /* Result of comparison */ if ((result = a->width - b->width) == 0) result = a->length - b->length; return (result); } /* * 'cups_copy_media_db()' - Copy a media entry. */ static _cups_media_db_t * /* O - New media entry */ cups_copy_media_db( _cups_media_db_t *mdb) /* I - Media entry to copy */ { _cups_media_db_t *temp; /* New media entry */ if ((temp = calloc(1, sizeof(_cups_media_db_t))) == NULL) return (NULL); if (mdb->color) temp->color = _cupsStrAlloc(mdb->color); if (mdb->key) temp->key = _cupsStrAlloc(mdb->key); if (mdb->info) temp->info = _cupsStrAlloc(mdb->info); if (mdb->size_name) temp->size_name = _cupsStrAlloc(mdb->size_name); if (mdb->source) temp->source = _cupsStrAlloc(mdb->source); if (mdb->type) temp->type = _cupsStrAlloc(mdb->type); temp->width = mdb->width; temp->length = mdb->length; temp->bottom = mdb->bottom; temp->left = mdb->left; temp->right = mdb->right; temp->top = mdb->top; return (temp); } /* * 'cups_create_cached()' - Create the media selection cache. */ static void cups_create_cached(http_t *http, /* I - Connection to destination */ cups_dinfo_t *dinfo, /* I - Destination information */ unsigned flags) /* I - Media selection flags */ { cups_array_t *db; /* Media database array to use */ _cups_media_db_t *mdb, /* Media database entry */ *first; /* First entry this size */ DEBUG_printf(("3cups_create_cached(http=%p, dinfo=%p, flags=%u)", (void *)http, (void *)dinfo, flags)); if (dinfo->cached_db) cupsArrayDelete(dinfo->cached_db); dinfo->cached_db = cupsArrayNew(NULL, NULL); dinfo->cached_flags = flags; if (flags & CUPS_MEDIA_FLAGS_READY) { DEBUG_puts("4cups_create_cached: ready media"); cups_update_ready(http, dinfo); db = dinfo->ready_db; } else { DEBUG_puts("4cups_create_cached: supported media"); if (!dinfo->media_db) cups_create_media_db(dinfo, CUPS_MEDIA_FLAGS_DEFAULT); db = dinfo->media_db; } for (mdb = (_cups_media_db_t *)cupsArrayFirst(db), first = mdb; mdb; mdb = (_cups_media_db_t *)cupsArrayNext(db)) { DEBUG_printf(("4cups_create_cached: %p key=\"%s\", type=\"%s\", %dx%d, B%d L%d R%d T%d", (void *)mdb, mdb->key, mdb->type, mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top)); if (flags & CUPS_MEDIA_FLAGS_BORDERLESS) { if (!mdb->left && !mdb->right && !mdb->top && !mdb->bottom) { DEBUG_printf(("4cups_create_cached: add %p", (void *)mdb)); cupsArrayAdd(dinfo->cached_db, mdb); } } else if (flags & CUPS_MEDIA_FLAGS_DUPLEX) { if (first->width != mdb->width || first->length != mdb->length) { DEBUG_printf(("4cups_create_cached: add %p", (void *)first)); cupsArrayAdd(dinfo->cached_db, first); first = mdb; } else if (mdb->left >= first->left && mdb->right >= first->right && mdb->top >= first->top && mdb->bottom >= first->bottom && (mdb->left != first->left || mdb->right != first->right || mdb->top != first->top || mdb->bottom != first->bottom)) first = mdb; } else { DEBUG_printf(("4cups_create_cached: add %p", (void *)mdb)); cupsArrayAdd(dinfo->cached_db, mdb); } } if (flags & CUPS_MEDIA_FLAGS_DUPLEX) { DEBUG_printf(("4cups_create_cached: add %p", (void *)first)); cupsArrayAdd(dinfo->cached_db, first); } } /* * 'cups_create_constraints()' - Create the constraints and resolvers arrays. */ static void cups_create_constraints( cups_dinfo_t *dinfo) /* I - Destination information */ { int i; /* Looping var */ ipp_attribute_t *attr; /* Attribute */ _ipp_value_t *val; /* Current value */ dinfo->constraints = cupsArrayNew3(NULL, NULL, NULL, 0, NULL, (cups_afree_func_t)free); dinfo->resolvers = cupsArrayNew3((cups_array_func_t)cups_compare_dconstres, NULL, NULL, 0, NULL, (cups_afree_func_t)free); if ((attr = ippFindAttribute(dinfo->attrs, "job-constraints-supported", IPP_TAG_BEGIN_COLLECTION)) != NULL) { for (i = attr->num_values, val = attr->values; i > 0; i --, val ++) cups_add_dconstres(dinfo->constraints, val->collection); } if ((attr = ippFindAttribute(dinfo->attrs, "job-resolvers-supported", IPP_TAG_BEGIN_COLLECTION)) != NULL) { for (i = attr->num_values, val = attr->values; i > 0; i --, val ++) cups_add_dconstres(dinfo->resolvers, val->collection); } } /* * 'cups_create_defaults()' - Create the -default option array. */ static void cups_create_defaults( cups_dinfo_t *dinfo) /* I - Destination information */ { ipp_attribute_t *attr; /* Current attribute */ char name[IPP_MAX_NAME + 1], /* Current name */ *nameptr, /* Pointer into current name */ value[2048]; /* Current value */ /* * Iterate through the printer attributes looking for xxx-default and adding * xxx=value to the defaults option array. */ for (attr = ippFirstAttribute(dinfo->attrs); attr; attr = ippNextAttribute(dinfo->attrs)) { if (!ippGetName(attr) || ippGetGroupTag(attr) != IPP_TAG_PRINTER) continue; strlcpy(name, ippGetName(attr), sizeof(name)); if ((nameptr = name + strlen(name) - 8) <= name || strcmp(nameptr, "-default")) continue; *nameptr = '\0'; if (ippGetValueTag(attr) == IPP_TAG_BEGIN_COLLECTION) { if (cups_collection_string(attr, value, sizeof(value)) >= sizeof(value)) continue; } else if (ippAttributeString(attr, value, sizeof(value)) >= sizeof(value)) continue; dinfo->num_defaults = cupsAddOption(name, value, dinfo->num_defaults, &dinfo->defaults); } } /* * 'cups_create_media_db()' - Create the media database. */ static void cups_create_media_db( cups_dinfo_t *dinfo, /* I - Destination information */ unsigned flags) /* I - Media flags */ { int i; /* Looping var */ _ipp_value_t *val; /* Current value */ ipp_attribute_t *media_col_db, /* media-col-database */ *media_attr, /* media-xxx */ *x_dimension, /* x-dimension */ *y_dimension; /* y-dimension */ pwg_media_t *pwg; /* PWG media info */ cups_array_t *db; /* New media database array */ _cups_media_db_t mdb; /* Media entry */ char media_key[256]; /* Synthesized media-key value */ db = cupsArrayNew3((cups_array_func_t)cups_compare_media_db, NULL, NULL, 0, (cups_acopy_func_t)cups_copy_media_db, (cups_afree_func_t)cups_free_media_db); if (flags == CUPS_MEDIA_FLAGS_READY) { dinfo->ready_db = db; media_col_db = ippFindAttribute(dinfo->ready_attrs, "media-col-ready", IPP_TAG_BEGIN_COLLECTION); media_attr = ippFindAttribute(dinfo->ready_attrs, "media-ready", IPP_TAG_ZERO); } else { dinfo->media_db = db; dinfo->min_size.width = INT_MAX; dinfo->min_size.length = INT_MAX; dinfo->max_size.width = 0; dinfo->max_size.length = 0; media_col_db = ippFindAttribute(dinfo->attrs, "media-col-database", IPP_TAG_BEGIN_COLLECTION); media_attr = ippFindAttribute(dinfo->attrs, "media-supported", IPP_TAG_ZERO); } if (media_col_db) { _ipp_value_t *custom = NULL; /* Custom size range value */ for (i = media_col_db->num_values, val = media_col_db->values; i > 0; i --, val ++) { memset(&mdb, 0, sizeof(mdb)); if ((media_attr = ippFindAttribute(val->collection, "media-size", IPP_TAG_BEGIN_COLLECTION)) != NULL) { ipp_t *media_size = media_attr->values[0].collection; /* media-size collection value */ if ((x_dimension = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER)) != NULL && (y_dimension = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER)) != NULL) { /* * Fixed size... */ mdb.width = x_dimension->values[0].integer; mdb.length = y_dimension->values[0].integer; } else if ((x_dimension = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER)) != NULL && (y_dimension = ippFindAttribute(media_size, "y-dimension", IPP_TAG_RANGE)) != NULL) { /* * Roll limits... */ mdb.width = x_dimension->values[0].integer; mdb.length = y_dimension->values[0].range.upper; } else if (flags != CUPS_MEDIA_FLAGS_READY && (x_dimension = ippFindAttribute(media_size, "x-dimension", IPP_TAG_RANGE)) != NULL && (y_dimension = ippFindAttribute(media_size, "y-dimension", IPP_TAG_RANGE)) != NULL) { /* * Custom size range; save this as the custom size value with default * margins, then continue; we'll capture the real margins below... */ custom = val; dinfo->min_size.width = x_dimension->values[0].range.lower; dinfo->min_size.length = y_dimension->values[0].range.lower; dinfo->min_size.left = dinfo->min_size.right = 635; /* Default 1/4" side margins */ dinfo->min_size.top = dinfo->min_size.bottom = 1270; /* Default 1/2" top/bottom margins */ dinfo->max_size.width = x_dimension->values[0].range.upper; dinfo->max_size.length = y_dimension->values[0].range.upper; dinfo->max_size.left = dinfo->max_size.right = 635; /* Default 1/4" side margins */ dinfo->max_size.top = dinfo->max_size.bottom = 1270; /* Default 1/2" top/bottom margins */ continue; } } if ((media_attr = ippFindAttribute(val->collection, "media-color", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD)) mdb.color = media_attr->values[0].string.text; if ((media_attr = ippFindAttribute(val->collection, "media-info", IPP_TAG_TEXT)) != NULL) mdb.info = media_attr->values[0].string.text; if ((media_attr = ippFindAttribute(val->collection, "media-key", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD)) mdb.key = media_attr->values[0].string.text; if ((media_attr = ippFindAttribute(val->collection, "media-size-name", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD)) mdb.size_name = media_attr->values[0].string.text; if ((media_attr = ippFindAttribute(val->collection, "media-source", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD)) mdb.source = media_attr->values[0].string.text; if ((media_attr = ippFindAttribute(val->collection, "media-type", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD)) mdb.type = media_attr->values[0].string.text; if ((media_attr = ippFindAttribute(val->collection, "media-bottom-margin", IPP_TAG_INTEGER)) != NULL) mdb.bottom = media_attr->values[0].integer; if ((media_attr = ippFindAttribute(val->collection, "media-left-margin", IPP_TAG_INTEGER)) != NULL) mdb.left = media_attr->values[0].integer; if ((media_attr = ippFindAttribute(val->collection, "media-right-margin", IPP_TAG_INTEGER)) != NULL) mdb.right = media_attr->values[0].integer; if ((media_attr = ippFindAttribute(val->collection, "media-top-margin", IPP_TAG_INTEGER)) != NULL) mdb.top = media_attr->values[0].integer; if (!mdb.key) { if (!mdb.size_name && (pwg = pwgMediaForSize(mdb.width, mdb.length)) != NULL) mdb.size_name = (char *)pwg->pwg; if (!mdb.size_name) { /* * Use a CUPS-specific identifier if we don't have a size name... */ if (flags & CUPS_MEDIA_FLAGS_READY) snprintf(media_key, sizeof(media_key), "cups-media-ready-%d", i + 1); else snprintf(media_key, sizeof(media_key), "cups-media-%d", i + 1); } else if (mdb.source) { /* * Generate key using size name, source, and type (if set)... */ if (mdb.type) snprintf(media_key, sizeof(media_key), "%s_%s_%s", mdb.size_name, mdb.source, mdb.type); else snprintf(media_key, sizeof(media_key), "%s_%s", mdb.size_name, mdb.source); } else if (mdb.type) { /* * Generate key using size name and type... */ snprintf(media_key, sizeof(media_key), "%s_%s", mdb.size_name, mdb.type); } else { /* * Key is just the size name... */ strlcpy(media_key, mdb.size_name, sizeof(media_key)); } /* * Append "_borderless" for borderless media... */ if (!mdb.bottom && !mdb.left && !mdb.right && !mdb.top) strlcat(media_key, "_borderless", sizeof(media_key)); mdb.key = media_key; } DEBUG_printf(("1cups_create_media_db: Adding media: key=\"%s\", width=%d, length=%d, source=\"%s\", type=\"%s\".", mdb.key, mdb.width, mdb.length, mdb.source, mdb.type)); cupsArrayAdd(db, &mdb); } if (custom) { if ((media_attr = ippFindAttribute(custom->collection, "media-bottom-margin", IPP_TAG_INTEGER)) != NULL) { dinfo->min_size.top = dinfo->max_size.top = media_attr->values[0].integer; } if ((media_attr = ippFindAttribute(custom->collection, "media-left-margin", IPP_TAG_INTEGER)) != NULL) { dinfo->min_size.left = dinfo->max_size.left = media_attr->values[0].integer; } if ((media_attr = ippFindAttribute(custom->collection, "media-right-margin", IPP_TAG_INTEGER)) != NULL) { dinfo->min_size.right = dinfo->max_size.right = media_attr->values[0].integer; } if ((media_attr = ippFindAttribute(custom->collection, "media-top-margin", IPP_TAG_INTEGER)) != NULL) { dinfo->min_size.top = dinfo->max_size.top = media_attr->values[0].integer; } } } else if (media_attr && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD)) { memset(&mdb, 0, sizeof(mdb)); mdb.left = mdb.right = 635; /* Default 1/4" side margins */ mdb.top = mdb.bottom = 1270; /* Default 1/2" top/bottom margins */ for (i = media_attr->num_values, val = media_attr->values; i > 0; i --, val ++) { if ((pwg = pwgMediaForPWG(val->string.text)) == NULL) if ((pwg = pwgMediaForLegacy(val->string.text)) == NULL) { DEBUG_printf(("3cups_create_media_db: Ignoring unknown size '%s'.", val->string.text)); continue; } mdb.width = pwg->width; mdb.length = pwg->length; if (flags != CUPS_MEDIA_FLAGS_READY && !strncmp(val->string.text, "custom_min_", 11)) { mdb.size_name = NULL; dinfo->min_size = mdb; } else if (flags != CUPS_MEDIA_FLAGS_READY && !strncmp(val->string.text, "custom_max_", 11)) { mdb.size_name = NULL; dinfo->max_size = mdb; } else { mdb.size_name = val->string.text; cupsArrayAdd(db, &mdb); } } } } /* * 'cups_free_media_cb()' - Free a media entry. */ static void cups_free_media_db( _cups_media_db_t *mdb) /* I - Media entry to free */ { if (mdb->color) _cupsStrFree(mdb->color); if (mdb->key) _cupsStrFree(mdb->key); if (mdb->info) _cupsStrFree(mdb->info); if (mdb->size_name) _cupsStrFree(mdb->size_name); if (mdb->source) _cupsStrFree(mdb->source); if (mdb->type) _cupsStrFree(mdb->type); free(mdb); } /* * 'cups_get_media_db()' - Lookup the media entry for a given size. */ static int /* O - 1 on match, 0 on failure */ cups_get_media_db(http_t *http, /* I - Connection to destination */ cups_dinfo_t *dinfo, /* I - Destination information */ pwg_media_t *pwg, /* I - PWG media info */ unsigned flags, /* I - Media matching flags */ cups_size_t *size) /* O - Media size/margin/name info */ { cups_array_t *db; /* Which media database to query */ _cups_media_db_t *mdb, /* Current media database entry */ *best = NULL, /* Best matching entry */ key; /* Search key */ /* * Create the media database as needed... */ if (flags & CUPS_MEDIA_FLAGS_READY) { cups_update_ready(http, dinfo); db = dinfo->ready_db; } else { if (!dinfo->media_db) cups_create_media_db(dinfo, CUPS_MEDIA_FLAGS_DEFAULT); db = dinfo->media_db; } /* * Find a match... */ memset(&key, 0, sizeof(key)); key.width = pwg->width; key.length = pwg->length; if ((mdb = cupsArrayFind(db, &key)) != NULL) { /* * Found an exact match, let's figure out the best margins for the flags * supplied... */ best = mdb; if (flags & CUPS_MEDIA_FLAGS_BORDERLESS) { /* * Look for the smallest margins... */ if (best->left != 0 || best->right != 0 || best->top != 0 || best->bottom != 0) { for (mdb = (_cups_media_db_t *)cupsArrayNext(db); mdb && !cups_compare_media_db(mdb, &key); mdb = (_cups_media_db_t *)cupsArrayNext(db)) { if (mdb->left <= best->left && mdb->right <= best->right && mdb->top <= best->top && mdb->bottom <= best->bottom) { best = mdb; if (mdb->left == 0 && mdb->right == 0 && mdb->bottom == 0 && mdb->top == 0) break; } } } /* * If we need an exact match, return no-match if the size is not * borderless. */ if ((flags & CUPS_MEDIA_FLAGS_EXACT) && (best->left || best->right || best->top || best->bottom)) return (0); } else if (flags & CUPS_MEDIA_FLAGS_DUPLEX) { /* * Look for the largest margins... */ for (mdb = (_cups_media_db_t *)cupsArrayNext(db); mdb && !cups_compare_media_db(mdb, &key); mdb = (_cups_media_db_t *)cupsArrayNext(db)) { if (mdb->left >= best->left && mdb->right >= best->right && mdb->top >= best->top && mdb->bottom >= best->bottom && (mdb->bottom != best->bottom || mdb->left != best->left || mdb->right != best->right || mdb->top != best->top)) best = mdb; } } else { /* * Look for the smallest non-zero margins... */ for (mdb = (_cups_media_db_t *)cupsArrayNext(db); mdb && !cups_compare_media_db(mdb, &key); mdb = (_cups_media_db_t *)cupsArrayNext(db)) { if (((mdb->left > 0 && mdb->left <= best->left) || best->left == 0) && ((mdb->right > 0 && mdb->right <= best->right) || best->right == 0) && ((mdb->top > 0 && mdb->top <= best->top) || best->top == 0) && ((mdb->bottom > 0 && mdb->bottom <= best->bottom) || best->bottom == 0) && (mdb->bottom != best->bottom || mdb->left != best->left || mdb->right != best->right || mdb->top != best->top)) best = mdb; } } } else if (flags & CUPS_MEDIA_FLAGS_EXACT) { /* * See if we can do this as a custom size... */ if (pwg->width < dinfo->min_size.width || pwg->width > dinfo->max_size.width || pwg->length < dinfo->min_size.length || pwg->length > dinfo->max_size.length) return (0); /* Out of range */ if ((flags & CUPS_MEDIA_FLAGS_BORDERLESS) && (dinfo->min_size.left > 0 || dinfo->min_size.right > 0 || dinfo->min_size.top > 0 || dinfo->min_size.bottom > 0)) return (0); /* Not borderless */ key.size_name = (char *)pwg->pwg; key.bottom = dinfo->min_size.bottom; key.left = dinfo->min_size.left; key.right = dinfo->min_size.right; key.top = dinfo->min_size.top; best = &key; } else if (pwg->width >= dinfo->min_size.width && pwg->width <= dinfo->max_size.width && pwg->length >= dinfo->min_size.length && pwg->length <= dinfo->max_size.length) { /* * Map to custom size... */ key.size_name = (char *)pwg->pwg; key.bottom = dinfo->min_size.bottom; key.left = dinfo->min_size.left; key.right = dinfo->min_size.right; key.top = dinfo->min_size.top; best = &key; } else { /* * Find a close size... */ for (mdb = (_cups_media_db_t *)cupsArrayFirst(db); mdb; mdb = (_cups_media_db_t *)cupsArrayNext(db)) if (cups_is_close_media_db(mdb, &key)) break; if (!mdb) return (0); best = mdb; if (flags & CUPS_MEDIA_FLAGS_BORDERLESS) { /* * Look for the smallest margins... */ if (best->left != 0 || best->right != 0 || best->top != 0 || best->bottom != 0) { for (mdb = (_cups_media_db_t *)cupsArrayNext(db); mdb && cups_is_close_media_db(mdb, &key); mdb = (_cups_media_db_t *)cupsArrayNext(db)) { if (mdb->left <= best->left && mdb->right <= best->right && mdb->top <= best->top && mdb->bottom <= best->bottom && (mdb->bottom != best->bottom || mdb->left != best->left || mdb->right != best->right || mdb->top != best->top)) { best = mdb; if (mdb->left == 0 && mdb->right == 0 && mdb->bottom == 0 && mdb->top == 0) break; } } } } else if (flags & CUPS_MEDIA_FLAGS_DUPLEX) { /* * Look for the largest margins... */ for (mdb = (_cups_media_db_t *)cupsArrayNext(db); mdb && cups_is_close_media_db(mdb, &key); mdb = (_cups_media_db_t *)cupsArrayNext(db)) { if (mdb->left >= best->left && mdb->right >= best->right && mdb->top >= best->top && mdb->bottom >= best->bottom && (mdb->bottom != best->bottom || mdb->left != best->left || mdb->right != best->right || mdb->top != best->top)) best = mdb; } } else { /* * Look for the smallest non-zero margins... */ for (mdb = (_cups_media_db_t *)cupsArrayNext(db); mdb && cups_is_close_media_db(mdb, &key); mdb = (_cups_media_db_t *)cupsArrayNext(db)) { if (((mdb->left > 0 && mdb->left <= best->left) || best->left == 0) && ((mdb->right > 0 && mdb->right <= best->right) || best->right == 0) && ((mdb->top > 0 && mdb->top <= best->top) || best->top == 0) && ((mdb->bottom > 0 && mdb->bottom <= best->bottom) || best->bottom == 0) && (mdb->bottom != best->bottom || mdb->left != best->left || mdb->right != best->right || mdb->top != best->top)) best = mdb; } } } if (best) { /* * Return the matching size... */ if (best->key) strlcpy(size->media, best->key, sizeof(size->media)); else if (best->size_name) strlcpy(size->media, best->size_name, sizeof(size->media)); else strlcpy(size->media, pwg->pwg, sizeof(size->media)); size->width = best->width; size->length = best->length; size->bottom = best->bottom; size->left = best->left; size->right = best->right; size->top = best->top; return (1); } return (0); } /* * 'cups_is_close_media_db()' - Compare two media entries to see if they are * close to the same size. * * Currently we use 5 points (from PostScript) as the matching range... */ static int /* O - 1 if the sizes are close */ cups_is_close_media_db( _cups_media_db_t *a, /* I - First media entries */ _cups_media_db_t *b) /* I - Second media entries */ { int dwidth, /* Difference in width */ dlength; /* Difference in length */ dwidth = a->width - b->width; dlength = a->length - b->length; return (dwidth >= -176 && dwidth <= 176 && dlength >= -176 && dlength <= 176); } /* * 'cups_test_constraints()' - Test constraints. */ static cups_array_t * /* O - Active constraints */ cups_test_constraints( cups_dinfo_t *dinfo, /* I - Destination information */ const char *new_option, /* I - Newly selected option */ const char *new_value, /* I - Newly selected value */ int num_options, /* I - Number of options */ cups_option_t *options, /* I - Options */ int *num_conflicts, /* O - Number of conflicting options */ cups_option_t **conflicts) /* O - Conflicting options */ { int i, /* Looping var */ count, /* Number of values */ match; /* Value matches? */ int num_matching; /* Number of matching options */ cups_option_t *matching; /* Matching options */ _cups_dconstres_t *c; /* Current constraint */ cups_array_t *active = NULL; /* Active constraints */ ipp_t *col; /* Collection value */ ipp_attribute_t *attr; /* Current attribute */ _ipp_value_t *attrval; /* Current attribute value */ const char *value; /* Current value */ char temp[1024]; /* Temporary string */ int int_value; /* Integer value */ int xres_value, /* Horizontal resolution */ yres_value; /* Vertical resolution */ ipp_res_t units_value; /* Resolution units */ for (c = (_cups_dconstres_t *)cupsArrayFirst(dinfo->constraints); c; c = (_cups_dconstres_t *)cupsArrayNext(dinfo->constraints)) { num_matching = 0; matching = NULL; for (attr = ippFirstAttribute(c->collection); attr; attr = ippNextAttribute(c->collection)) { /* * Get the value for the current attribute in the constraint... */ if (new_option && new_value && !strcmp(attr->name, new_option)) value = new_value; else if ((value = cupsGetOption(attr->name, num_options, options)) == NULL) value = cupsGetOption(attr->name, dinfo->num_defaults, dinfo->defaults); if (!value) { /* * Not set so this constraint does not apply... */ break; } match = 0; switch (attr->value_tag) { case IPP_TAG_INTEGER : case IPP_TAG_ENUM : int_value = atoi(value); for (i = attr->num_values, attrval = attr->values; i > 0; i --, attrval ++) { if (attrval->integer == int_value) { match = 1; break; } } break; case IPP_TAG_BOOLEAN : int_value = !strcmp(value, "true"); for (i = attr->num_values, attrval = attr->values; i > 0; i --, attrval ++) { if (attrval->boolean == int_value) { match = 1; break; } } break; case IPP_TAG_RANGE : int_value = atoi(value); for (i = attr->num_values, attrval = attr->values; i > 0; i --, attrval ++) { if (int_value >= attrval->range.lower && int_value <= attrval->range.upper) { match = 1; break; } } break; case IPP_TAG_RESOLUTION : if (sscanf(value, "%dx%d%15s", &xres_value, &yres_value, temp) != 3) { if (sscanf(value, "%d%15s", &xres_value, temp) != 2) break; yres_value = xres_value; } if (!strcmp(temp, "dpi")) units_value = IPP_RES_PER_INCH; else if (!strcmp(temp, "dpc") || !strcmp(temp, "dpcm")) units_value = IPP_RES_PER_CM; else break; for (i = attr->num_values, attrval = attr->values; i > 0; i --, attrval ++) { if (attrval->resolution.xres == xres_value && attrval->resolution.yres == yres_value && attrval->resolution.units == units_value) { match = 1; break; } } break; case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : case IPP_TAG_CHARSET : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_MIMETYPE : case IPP_TAG_LANGUAGE : case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : for (i = attr->num_values, attrval = attr->values; i > 0; i --, attrval ++) { if (!strcmp(attrval->string.text, value)) { match = 1; break; } } break; case IPP_TAG_BEGIN_COLLECTION : col = ippNew(); _cupsEncodeOption(col, IPP_TAG_ZERO, NULL, ippGetName(attr), value); for (i = 0, count = ippGetCount(attr); i < count; i ++) { if (cups_collection_contains(col, ippGetCollection(attr, i))) { match = 1; break; } } ippDelete(col); break; default : break; } if (!match) break; num_matching = cupsAddOption(attr->name, value, num_matching, &matching); } if (!attr) { if (!active) active = cupsArrayNew(NULL, NULL); cupsArrayAdd(active, c); if (num_conflicts && conflicts) { cups_option_t *moption; /* Matching option */ for (i = num_matching, moption = matching; i > 0; i --, moption ++) *num_conflicts = cupsAddOption(moption->name, moption->value, *num_conflicts, conflicts); } } cupsFreeOptions(num_matching, matching); } return (active); } /* * 'cups_update_ready()' - Update xxx-ready attributes for the printer. */ static void cups_update_ready(http_t *http, /* I - Connection to destination */ cups_dinfo_t *dinfo) /* I - Destination information */ { ipp_t *request; /* Get-Printer-Attributes request */ static const char * const pattrs[] = /* Printer attributes we want */ { "finishings-col-ready", "finishings-ready", "job-finishings-col-ready", "job-finishings-ready", "media-col-ready", "media-ready" }; /* * Don't update more than once every 30 seconds... */ if ((time(NULL) - dinfo->ready_time) < _CUPS_MEDIA_READY_TTL) return; /* * Free any previous results... */ if (dinfo->cached_flags & CUPS_MEDIA_FLAGS_READY) { cupsArrayDelete(dinfo->cached_db); dinfo->cached_db = NULL; dinfo->cached_flags = CUPS_MEDIA_FLAGS_DEFAULT; } ippDelete(dinfo->ready_attrs); dinfo->ready_attrs = NULL; cupsArrayDelete(dinfo->ready_db); dinfo->ready_db = NULL; /* * Query the xxx-ready values... */ request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); ippSetVersion(request, dinfo->version / 10, dinfo->version % 10); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, dinfo->uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddStrings(request, IPP_TAG_OPERATION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs); dinfo->ready_attrs = cupsDoRequest(http, request, dinfo->resource); /* * Update the ready media database... */ cups_create_media_db(dinfo, CUPS_MEDIA_FLAGS_READY); /* * Update last lookup time and return... */ dinfo->ready_time = time(NULL); } ippsample/cups/libcups2.def0000644000175000017500000001644113240604116014722 0ustar tilltillLIBRARY libcups2 VERSION 2.12 EXPORTS _cupsArrayAddStrings _cupsArrayNewStrings _cupsBufferGet _cupsBufferRelease _cupsCharmapFlush _cupsCondBroadcast _cupsCondInit _cupsCondWait _cupsConnect _cupsCreateDest _cupsEncodeOption _cupsEncodingName _cupsGet1284Values _cupsGetDestResource _cupsGetDests _cupsGetPassword _cupsGlobalLock _cupsGlobalUnlock _cupsGlobals _cupsLangPrintError _cupsLangPrintf _cupsLangPuts _cupsLangString _cupsMessageFree _cupsMessageLoad _cupsMessageLookup _cupsMessageNew _cupsMessageSave _cupsMutexInit _cupsMutexLock _cupsMutexUnlock _cupsNextDelay _cupsRWInit _cupsRWLockRead _cupsRWLockWrite _cupsRWUnlock _cupsRasterAddError _cupsRasterClearError _cupsSetDefaults _cupsSetError _cupsSetHTTPError _cupsSetLocale _cupsStrAlloc _cupsStrDate _cupsStrFlush _cupsStrFormatd _cupsStrFree _cupsStrRetain _cupsStrScand _cupsStrStatistics _cupsThreadCancel _cupsThreadCreate _cupsThreadDetach _cupsThreadWait _cupsUserDefault _cups_safe_vsnprintf _cups_strcasecmp _cups_strcpy _cups_strcpy _cups_strlcat _cups_strlcpy _cups_strncasecmp _httpAddrSetPort _httpCreateCredentials _httpDecodeURI _httpDisconnect _httpEncodeURI _httpFreeCredentials _httpResolveURI _httpStatus _httpTLSInitialize _httpTLSPending _httpTLSRead _httpTLSSetOptions _httpTLSStart _httpTLSStop _httpTLSWrite _httpUpdate _httpWait _ippCheckOptions _ippFileParse _ippFileReadToken _ippFindOption _ippVarsDeinit _ippVarsExpand _ippVarsGet _ippVarsInit _ippVarsPasswordCB _ippVarsSet _pwgMediaNearSize _pwgMediaTable cupsAddDest cupsAddDestMediaOptions cupsAddIntegerOption cupsAddOption cupsArrayAdd cupsArrayClear cupsArrayCount cupsArrayCurrent cupsArrayDelete cupsArrayDup cupsArrayFind cupsArrayFirst cupsArrayGetIndex cupsArrayGetInsert cupsArrayIndex cupsArrayInsert cupsArrayLast cupsArrayNew cupsArrayNew2 cupsArrayNew3 cupsArrayNext cupsArrayPrev cupsArrayRemove cupsArrayRestore cupsArraySave cupsArrayUserData cupsCancelDestJob cupsCancelJob cupsCancelJob2 cupsCharsetToUTF8 cupsCheckDestSupported cupsCloseDestJob cupsConnectDest cupsCopyDest cupsCopyDestConflicts cupsCopyDestInfo cupsCreateDestJob cupsCreateJob cupsDirClose cupsDirOpen cupsDirRead cupsDirRewind cupsDoAuthentication cupsDoFileRequest cupsDoIORequest cupsDoRequest cupsEncodeOptions cupsEncodeOptions2 cupsEncryption cupsEnumDests cupsFileClose cupsFileCompression cupsFileEOF cupsFileFind cupsFileFlush cupsFileGetChar cupsFileGetConf cupsFileGetLine cupsFileGets cupsFileLock cupsFileNumber cupsFileOpen cupsFileOpenFd cupsFilePeekChar cupsFilePrintf cupsFilePutChar cupsFilePutConf cupsFilePuts cupsFileRead cupsFileRewind cupsFileSeek cupsFileStderr cupsFileStdin cupsFileStdout cupsFileTell cupsFileUnlock cupsFileWrite cupsFindDestDefault cupsFindDestReady cupsFindDestSupported cupsFinishDestDocument cupsFinishDocument cupsFreeDestInfo cupsFreeDests cupsFreeJobs cupsFreeOptions cupsGetClasses cupsGetDefault cupsGetDefault2 cupsGetDest cupsGetDestMediaByIndex cupsGetDestMediaByName cupsGetDestMediaBySize cupsGetDestMediaCount cupsGetDestMediaDefault cupsGetDestWithURI cupsGetDests cupsGetDests2 cupsGetFd cupsGetFile cupsGetIntegerOption cupsGetJobs cupsGetJobs2 cupsGetNamedDest cupsGetOption cupsGetPassword cupsGetPassword2 cupsGetPrinters cupsGetResponse cupsHashData cupsHashString cupsLangDefault cupsLangEncoding cupsLangFlush cupsLangFree cupsLangGet cupsLastError cupsLastErrorString cupsLocalizeDestMedia cupsLocalizeDestOption cupsLocalizeDestValue cupsMakeServerCredentials cupsNotifySubject cupsNotifyText cupsParseOptions cupsPrintFile cupsPrintFile2 cupsPrintFiles cupsPrintFiles2 cupsPutFd cupsPutFile cupsRasterClose cupsRasterErrorString cupsRasterInitPWGHeader cupsRasterOpen cupsRasterOpenIO cupsRasterReadHeader cupsRasterReadHeader2 cupsRasterReadPixels cupsRasterWriteHeader cupsRasterWriteHeader2 cupsRasterWritePixels cupsReadResponseData cupsRemoveDest cupsRemoveOption cupsSendRequest cupsServer cupsSetClientCertCB cupsSetCredentials cupsSetDefaultDest cupsSetDests cupsSetDests2 cupsSetEncryption cupsSetPasswordCB cupsSetPasswordCB2 cupsSetServer cupsSetServerCertCB cupsSetServerCredentials cupsSetUser cupsSetUserAgent cupsStartDestDocument cupsStartDocument cupsTempFd cupsTempFile cupsTempFile2 cupsUTF32ToUTF8 cupsUTF8ToCharset cupsUTF8ToUTF32 cupsUser cupsUserAgent cupsWriteRequestData httpAcceptConnection httpAddCredential httpAddrAny httpAddrClose httpAddrConnect httpAddrConnect2 httpAddrCopyList httpAddrEqual httpAddrFamily httpAddrFreeList httpAddrGetList httpAddrLength httpAddrListen httpAddrLocalhost httpAddrLookup httpAddrPort httpAddrString httpAssembleURI httpAssembleURIf httpAssembleUUID httpBlocking httpCheck httpClearCookie httpClearFields httpClose httpCompareCredentials httpConnect httpConnect2 httpConnectEncrypt httpCopyCredentials httpCredentialsAreValidForName httpCredentialsGetExpiration httpCredentialsGetTrust httpCredentialsString httpDecode64 httpDecode64_2 httpDelete httpEncode64 httpEncode64_2 httpEncryption httpError httpFieldValue httpFlush httpFlushWrite httpFreeCredentials httpGet httpGetActivity httpGetAddress httpGetAuthString httpGetBlocking httpGetContentEncoding httpGetCookie httpGetDateString httpGetDateString2 httpGetDateTime httpGetEncryption httpGetExpect httpGetFd httpGetField httpGetHostByName httpGetHostname httpGetKeepAlive httpGetLength httpGetLength2 httpGetPending httpGetReady httpGetRemaining httpGetState httpGetStatus httpGetSubField httpGetSubField2 httpGetVersion httpGets httpHead httpInitialize httpIsChunked httpIsEncrypted httpLoadCredentials httpMD5 httpMD5Final httpMD5String httpOptions httpPeek httpPost httpPrintf httpPut httpRead httpRead2 httpReadRequest httpReconnect httpReconnect2 httpResolveHostname httpSaveCredentials httpSeparate httpSeparate2 httpSeparateURI httpSetAuthString httpSetCookie httpSetCredentials httpSetDefaultField httpSetExpect httpSetField httpSetKeepAlive httpSetLength httpSetTimeout httpShutdown httpStateString httpStatus httpTrace httpURIStatusString httpUpdate httpWait httpWrite httpWrite2 httpWriteResponse ippAddBoolean ippAddBooleans ippAddCollection ippAddCollections ippAddDate ippAddInteger ippAddIntegers ippAddOctetString ippAddOutOfBand ippAddRange ippAddRanges ippAddResolution ippAddResolutions ippAddSeparator ippAddString ippAddStringf ippAddStringfv ippAddStrings ippAttributeString ippContainsInteger ippContainsString ippCopyAttribute ippCopyAttributes ippCreateRequestedArray ippDateToTime ippDelete ippDeleteAttribute ippDeleteValues ippEnumString ippEnumValue ippErrorString ippErrorValue ippFindAttribute ippFindNextAttribute ippFirstAttribute ippGetBoolean ippGetCollection ippGetCount ippGetDate ippGetGroupTag ippGetInteger ippGetName ippGetOctetString ippGetOperation ippGetRange ippGetRequestId ippGetResolution ippGetState ippGetStatusCode ippGetString ippGetValueTag ippGetVersion ippLength ippNew ippNewRequest ippNewResponse ippNextAttribute ippOpString ippOpValue ippPort ippRead ippReadFile ippReadIO ippSetBoolean ippSetCollection ippSetDate ippSetGroupTag ippSetInteger ippSetName ippSetOctetString ippSetOperation ippSetPort ippSetRange ippSetRequestId ippSetResolution ippSetState ippSetStatusCode ippSetString ippSetStringf ippSetStringfv ippSetValueTag ippSetVersion ippStateString ippTagString ippTagValue ippTimeToDate ippValidateAttribute ippValidateAttributes ippWrite ippWriteFile ippWriteIO pwgFormatSizeName pwgInitSize pwgMediaForLegacy pwgMediaForPPD pwgMediaForPWG pwgMediaForSize ippsample/cups/transcode.c0000644000175000017500000003611013240604116014640 0ustar tilltill/* * Transcoding support for CUPS. * * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #include #include #ifdef HAVE_ICONV_H # include #endif /* HAVE_ICONV_H */ /* * Local globals... */ #ifdef HAVE_ICONV_H static _cups_mutex_t map_mutex = _CUPS_MUTEX_INITIALIZER; /* Mutex to control access to maps */ static iconv_t map_from_utf8 = (iconv_t)-1; /* Convert from UTF-8 to charset */ static iconv_t map_to_utf8 = (iconv_t)-1; /* Convert from charset to UTF-8 */ static cups_encoding_t map_encoding = CUPS_AUTO_ENCODING; /* Which charset is cached */ #endif /* HAVE_ICONV_H */ /* * '_cupsCharmapFlush()' - Flush all character set maps out of cache. */ void _cupsCharmapFlush(void) { #ifdef HAVE_ICONV_H if (map_from_utf8 != (iconv_t)-1) { iconv_close(map_from_utf8); map_from_utf8 = (iconv_t)-1; } if (map_to_utf8 != (iconv_t)-1) { iconv_close(map_to_utf8); map_to_utf8 = (iconv_t)-1; } map_encoding = CUPS_AUTO_ENCODING; #endif /* HAVE_ICONV_H */ } /* * 'cupsCharsetToUTF8()' - Convert legacy character set to UTF-8. */ int /* O - Count or -1 on error */ cupsCharsetToUTF8( cups_utf8_t *dest, /* O - Target string */ const char *src, /* I - Source string */ const int maxout, /* I - Max output */ const cups_encoding_t encoding) /* I - Encoding */ { cups_utf8_t *destptr; /* Pointer into UTF-8 buffer */ #ifdef HAVE_ICONV_H size_t srclen, /* Length of source string */ outBytesLeft; /* Bytes remaining in output buffer */ #endif /* HAVE_ICONV_H */ /* * Check for valid arguments... */ DEBUG_printf(("2cupsCharsetToUTF8(dest=%p, src=\"%s\", maxout=%d, encoding=%d)", (void *)dest, src, maxout, encoding)); if (!dest || !src || maxout < 1) { if (dest) *dest = '\0'; DEBUG_puts("3cupsCharsetToUTF8: Bad arguments, returning -1"); return (-1); } /* * Handle identity conversions... */ if (encoding == CUPS_UTF8 || encoding <= CUPS_US_ASCII || encoding >= CUPS_ENCODING_VBCS_END) { strlcpy((char *)dest, src, (size_t)maxout); return ((int)strlen((char *)dest)); } /* * Handle ISO-8859-1 to UTF-8 directly... */ destptr = dest; if (encoding == CUPS_ISO8859_1) { int ch; /* Character from string */ cups_utf8_t *destend; /* End of UTF-8 buffer */ destend = dest + maxout - 2; while (*src && destptr < destend) { ch = *src++ & 255; if (ch & 128) { *destptr++ = (cups_utf8_t)(0xc0 | (ch >> 6)); *destptr++ = (cups_utf8_t)(0x80 | (ch & 0x3f)); } else *destptr++ = (cups_utf8_t)ch; } *destptr = '\0'; return ((int)(destptr - dest)); } /* * Convert input legacy charset to UTF-8... */ #ifdef HAVE_ICONV_H _cupsMutexLock(&map_mutex); if (map_encoding != encoding) { char toset[1024]; /* Destination character set */ _cupsCharmapFlush(); snprintf(toset, sizeof(toset), "%s//IGNORE", _cupsEncodingName(encoding)); map_encoding = encoding; map_from_utf8 = iconv_open(_cupsEncodingName(encoding), "UTF-8"); map_to_utf8 = iconv_open("UTF-8", toset); } if (map_to_utf8 != (iconv_t)-1) { char *altdestptr = (char *)dest; /* Silence bogus GCC type-punned */ srclen = strlen(src); outBytesLeft = (size_t)maxout - 1; iconv(map_to_utf8, (char **)&src, &srclen, &altdestptr, &outBytesLeft); *altdestptr = '\0'; _cupsMutexUnlock(&map_mutex); return ((int)(altdestptr - (char *)dest)); } _cupsMutexUnlock(&map_mutex); #endif /* HAVE_ICONV_H */ /* * No iconv() support, so error out... */ *destptr = '\0'; return (-1); } /* * 'cupsUTF8ToCharset()' - Convert UTF-8 to legacy character set. */ int /* O - Count or -1 on error */ cupsUTF8ToCharset( char *dest, /* O - Target string */ const cups_utf8_t *src, /* I - Source string */ const int maxout, /* I - Max output */ const cups_encoding_t encoding) /* I - Encoding */ { char *destptr; /* Pointer into destination */ #ifdef HAVE_ICONV_H size_t srclen, /* Length of source string */ outBytesLeft; /* Bytes remaining in output buffer */ #endif /* HAVE_ICONV_H */ /* * Check for valid arguments... */ if (!dest || !src || maxout < 1) { if (dest) *dest = '\0'; return (-1); } /* * Handle identity conversions... */ if (encoding == CUPS_UTF8 || encoding >= CUPS_ENCODING_VBCS_END) { strlcpy(dest, (char *)src, (size_t)maxout); return ((int)strlen(dest)); } /* * Handle UTF-8 to ISO-8859-1 directly... */ destptr = dest; if (encoding == CUPS_ISO8859_1 || encoding <= CUPS_US_ASCII) { int ch, /* Character from string */ maxch; /* Maximum character for charset */ char *destend; /* End of ISO-8859-1 buffer */ maxch = encoding == CUPS_ISO8859_1 ? 256 : 128; destend = dest + maxout - 1; while (*src && destptr < destend) { ch = *src++; if ((ch & 0xe0) == 0xc0) { ch = ((ch & 0x1f) << 6) | (*src++ & 0x3f); if (ch < maxch) *destptr++ = (char)ch; else *destptr++ = '?'; } else if ((ch & 0xf0) == 0xe0 || (ch & 0xf8) == 0xf0) *destptr++ = '?'; else if (!(ch & 0x80)) *destptr++ = (char)ch; } *destptr = '\0'; return ((int)(destptr - dest)); } #ifdef HAVE_ICONV_H /* * Convert input UTF-8 to legacy charset... */ _cupsMutexLock(&map_mutex); if (map_encoding != encoding) { char toset[1024]; /* Destination character set */ _cupsCharmapFlush(); snprintf(toset, sizeof(toset), "%s//IGNORE", _cupsEncodingName(encoding)); map_encoding = encoding; map_from_utf8 = iconv_open(_cupsEncodingName(encoding), "UTF-8"); map_to_utf8 = iconv_open("UTF-8", toset); } if (map_from_utf8 != (iconv_t)-1) { char *altsrc = (char *)src; /* Silence bogus GCC type-punned */ srclen = strlen((char *)src); outBytesLeft = (size_t)maxout - 1; iconv(map_from_utf8, &altsrc, &srclen, &destptr, &outBytesLeft); *destptr = '\0'; _cupsMutexUnlock(&map_mutex); return ((int)(destptr - dest)); } _cupsMutexUnlock(&map_mutex); #endif /* HAVE_ICONV_H */ /* * No iconv() support, so error out... */ *destptr = '\0'; return (-1); } /* * 'cupsUTF8ToUTF32()' - Convert UTF-8 to UTF-32. * * 32-bit UTF-32 (actually 21-bit) maps to UTF-8 as follows... * * UTF-32 char UTF-8 char(s) * -------------------------------------------------- * 0 to 127 = 0xxxxxxx (US-ASCII) * 128 to 2047 = 110xxxxx 10yyyyyy * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz * > 65535 = 11110xxx 10yyyyyy 10zzzzzz 10xxxxxx * * UTF-32 prohibits chars beyond Plane 16 (> 0x10ffff) in UCS-4, * which would convert to five- or six-octet UTF-8 sequences... */ int /* O - Count or -1 on error */ cupsUTF8ToUTF32( cups_utf32_t *dest, /* O - Target string */ const cups_utf8_t *src, /* I - Source string */ const int maxout) /* I - Max output */ { int i; /* Looping variable */ cups_utf8_t ch; /* Character value */ cups_utf8_t next; /* Next character value */ cups_utf32_t ch32; /* UTF-32 character value */ /* * Check for valid arguments and clear output... */ DEBUG_printf(("2cupsUTF8ToUTF32(dest=%p, src=\"%s\", maxout=%d)", (void *)dest, src, maxout)); if (dest) *dest = 0; if (!dest || !src || maxout < 1 || maxout > CUPS_MAX_USTRING) { DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad arguments)"); return (-1); } /* * Convert input UTF-8 to output UTF-32... */ for (i = maxout - 1; *src && i > 0; i --) { ch = *src++; /* * Convert UTF-8 character(s) to UTF-32 character... */ if (!(ch & 0x80)) { /* * One-octet UTF-8 <= 127 (US-ASCII)... */ *dest++ = ch; DEBUG_printf(("4cupsUTF8ToUTF32: %02x => %08X", src[-1], ch)); continue; } else if ((ch & 0xe0) == 0xc0) { /* * Two-octet UTF-8 <= 2047 (Latin-x)... */ next = *src++; if ((next & 0xc0) != 0x80) { DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)"); return (-1); } ch32 = (cups_utf32_t)((ch & 0x1f) << 6) | (cups_utf32_t)(next & 0x3f); /* * Check for non-shortest form (invalid UTF-8)... */ if (ch32 < 0x80) { DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)"); return (-1); } *dest++ = ch32; DEBUG_printf(("4cupsUTF8ToUTF32: %02x %02x => %08X", src[-2], src[-1], (unsigned)ch32)); } else if ((ch & 0xf0) == 0xe0) { /* * Three-octet UTF-8 <= 65535 (Plane 0 - BMP)... */ next = *src++; if ((next & 0xc0) != 0x80) { DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)"); return (-1); } ch32 = (cups_utf32_t)((ch & 0x0f) << 6) | (cups_utf32_t)(next & 0x3f); next = *src++; if ((next & 0xc0) != 0x80) { DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)"); return (-1); } ch32 = (ch32 << 6) | (cups_utf32_t)(next & 0x3f); /* * Check for non-shortest form (invalid UTF-8)... */ if (ch32 < 0x800) { DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)"); return (-1); } *dest++ = ch32; DEBUG_printf(("4cupsUTF8ToUTF32: %02x %02x %02x => %08X", src[-3], src[-2], src[-1], (unsigned)ch32)); } else if ((ch & 0xf8) == 0xf0) { /* * Four-octet UTF-8... */ next = *src++; if ((next & 0xc0) != 0x80) { DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)"); return (-1); } ch32 = (cups_utf32_t)((ch & 0x07) << 6) | (cups_utf32_t)(next & 0x3f); next = *src++; if ((next & 0xc0) != 0x80) { DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)"); return (-1); } ch32 = (ch32 << 6) | (cups_utf32_t)(next & 0x3f); next = *src++; if ((next & 0xc0) != 0x80) { DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)"); return (-1); } ch32 = (ch32 << 6) | (cups_utf32_t)(next & 0x3f); /* * Check for non-shortest form (invalid UTF-8)... */ if (ch32 < 0x10000) { DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)"); return (-1); } *dest++ = ch32; DEBUG_printf(("4cupsUTF8ToUTF32: %02x %02x %02x %02x => %08X", src[-4], src[-3], src[-2], src[-1], (unsigned)ch32)); } else { /* * More than 4-octet (invalid UTF-8 sequence)... */ DEBUG_puts("3cupsUTF8ToUTF32: Returning -1 (bad UTF-8 sequence)"); return (-1); } /* * Check for UTF-16 surrogate (illegal UTF-8)... */ if (ch32 >= 0xd800 && ch32 <= 0xdfff) return (-1); } *dest = 0; DEBUG_printf(("3cupsUTF8ToUTF32: Returning %d characters", maxout - 1 - i)); return (maxout - 1 - i); } /* * 'cupsUTF32ToUTF8()' - Convert UTF-32 to UTF-8. * * 32-bit UTF-32 (actually 21-bit) maps to UTF-8 as follows... * * UTF-32 char UTF-8 char(s) * -------------------------------------------------- * 0 to 127 = 0xxxxxxx (US-ASCII) * 128 to 2047 = 110xxxxx 10yyyyyy * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz * > 65535 = 11110xxx 10yyyyyy 10zzzzzz 10xxxxxx * * UTF-32 prohibits chars beyond Plane 16 (> 0x10ffff) in UCS-4, * which would convert to five- or six-octet UTF-8 sequences... */ int /* O - Count or -1 on error */ cupsUTF32ToUTF8( cups_utf8_t *dest, /* O - Target string */ const cups_utf32_t *src, /* I - Source string */ const int maxout) /* I - Max output */ { cups_utf8_t *start; /* Start of destination string */ int i; /* Looping variable */ int swap; /* Byte-swap input to output */ cups_utf32_t ch; /* Character value */ /* * Check for valid arguments and clear output... */ DEBUG_printf(("2cupsUTF32ToUTF8(dest=%p, src=%p, maxout=%d)", (void *)dest, (void *)src, maxout)); if (dest) *dest = '\0'; if (!dest || !src || maxout < 1) { DEBUG_puts("3cupsUTF32ToUTF8: Returning -1 (bad args)"); return (-1); } /* * Check for leading BOM in UTF-32 and inverted BOM... */ start = dest; swap = *src == 0xfffe0000; DEBUG_printf(("4cupsUTF32ToUTF8: swap=%d", swap)); if (*src == 0xfffe0000 || *src == 0xfeff) src ++; /* * Convert input UTF-32 to output UTF-8... */ for (i = maxout - 1; *src && i > 0;) { ch = *src++; /* * Byte swap input UTF-32, if necessary... * (only byte-swapping 24 of 32 bits) */ if (swap) ch = ((ch >> 24) | ((ch >> 8) & 0xff00) | ((ch << 8) & 0xff0000)); /* * Check for beyond Plane 16 (invalid UTF-32)... */ if (ch > 0x10ffff) { DEBUG_puts("3cupsUTF32ToUTF8: Returning -1 (character out of range)"); return (-1); } /* * Convert UTF-32 character to UTF-8 character(s)... */ if (ch < 0x80) { /* * One-octet UTF-8 <= 127 (US-ASCII)... */ *dest++ = (cups_utf8_t)ch; i --; DEBUG_printf(("4cupsUTF32ToUTF8: %08x => %02x", (unsigned)ch, dest[-1])); } else if (ch < 0x800) { /* * Two-octet UTF-8 <= 2047 (Latin-x)... */ if (i < 2) { DEBUG_puts("3cupsUTF32ToUTF8: Returning -1 (too long 2)"); return (-1); } *dest++ = (cups_utf8_t)(0xc0 | ((ch >> 6) & 0x1f)); *dest++ = (cups_utf8_t)(0x80 | (ch & 0x3f)); i -= 2; DEBUG_printf(("4cupsUTF32ToUTF8: %08x => %02x %02x", (unsigned)ch, dest[-2], dest[-1])); } else if (ch < 0x10000) { /* * Three-octet UTF-8 <= 65535 (Plane 0 - BMP)... */ if (i < 3) { DEBUG_puts("3cupsUTF32ToUTF8: Returning -1 (too long 3)"); return (-1); } *dest++ = (cups_utf8_t)(0xe0 | ((ch >> 12) & 0x0f)); *dest++ = (cups_utf8_t)(0x80 | ((ch >> 6) & 0x3f)); *dest++ = (cups_utf8_t)(0x80 | (ch & 0x3f)); i -= 3; DEBUG_printf(("4cupsUTF32ToUTF8: %08x => %02x %02x %02x", (unsigned)ch, dest[-3], dest[-2], dest[-1])); } else { /* * Four-octet UTF-8... */ if (i < 4) { DEBUG_puts("3cupsUTF32ToUTF8: Returning -1 (too long 4)"); return (-1); } *dest++ = (cups_utf8_t)(0xf0 | ((ch >> 18) & 0x07)); *dest++ = (cups_utf8_t)(0x80 | ((ch >> 12) & 0x3f)); *dest++ = (cups_utf8_t)(0x80 | ((ch >> 6) & 0x3f)); *dest++ = (cups_utf8_t)(0x80 | (ch & 0x3f)); i -= 4; DEBUG_printf(("4cupsUTF32ToUTF8: %08x => %02x %02x %02x %02x", (unsigned)ch, dest[-4], dest[-3], dest[-2], dest[-1])); } } *dest = '\0'; DEBUG_printf(("3cupsUTF32ToUTF8: Returning %d", (int)(dest - start))); return ((int)(dest - start)); } ippsample/cups/http-support.c0000644000175000017500000017351613240604116015363 0ustar tilltill/* * HTTP support routines for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #ifdef HAVE_DNSSD # include # ifdef WIN32 # include # elif defined(HAVE_POLL) # include # else # include # endif /* WIN32 */ #elif defined(HAVE_AVAHI) # include # include # include #endif /* HAVE_DNSSD */ /* * Local types... */ typedef struct _http_uribuf_s /* URI buffer */ { #ifdef HAVE_AVAHI AvahiSimplePoll *poll; /* Poll state */ #endif /* HAVE_AVAHI */ char *buffer; /* Pointer to buffer */ size_t bufsize; /* Size of buffer */ int options; /* Options passed to _httpResolveURI */ const char *resource; /* Resource from URI */ const char *uuid; /* UUID from URI */ } _http_uribuf_t; /* * Local globals... */ static const char * const http_days[7] =/* Days of the week */ { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static const char * const http_months[12] = { /* Months of the year */ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static const char * const http_states[] = { /* HTTP state strings */ "HTTP_STATE_ERROR", "HTTP_STATE_WAITING", "HTTP_STATE_OPTIONS", "HTTP_STATE_GET", "HTTP_STATE_GET_SEND", "HTTP_STATE_HEAD", "HTTP_STATE_POST", "HTTP_STATE_POST_RECV", "HTTP_STATE_POST_SEND", "HTTP_STATE_PUT", "HTTP_STATE_PUT_RECV", "HTTP_STATE_DELETE", "HTTP_STATE_TRACE", "HTTP_STATE_CONNECT", "HTTP_STATE_STATUS", "HTTP_STATE_UNKNOWN_METHOD", "HTTP_STATE_UNKNOWN_VERSION" }; /* * Local functions... */ static const char *http_copy_decode(char *dst, const char *src, int dstsize, const char *term, int decode); static char *http_copy_encode(char *dst, const char *src, char *dstend, const char *reserved, const char *term, int encode); #ifdef HAVE_DNSSD static void DNSSD_API http_resolve_cb(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullName, const char *hostTarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context); #endif /* HAVE_DNSSD */ #ifdef HAVE_AVAHI static void http_client_cb(AvahiClient *client, AvahiClientState state, void *simple_poll); static int http_poll_cb(struct pollfd *pollfds, unsigned int num_pollfds, int timeout, void *context); static void http_resolve_cb(AvahiServiceResolver *resolver, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *context); #endif /* HAVE_AVAHI */ /* * 'httpAssembleURI()' - Assemble a uniform resource identifier from its * components. * * This function escapes reserved characters in the URI depending on the * value of the "encoding" argument. You should use this function in * place of traditional string functions whenever you need to create a * URI string. * * @since CUPS 1.2/macOS 10.5@ */ http_uri_status_t /* O - URI status */ httpAssembleURI( http_uri_coding_t encoding, /* I - Encoding flags */ char *uri, /* I - URI buffer */ int urilen, /* I - Size of URI buffer */ const char *scheme, /* I - Scheme name */ const char *username, /* I - Username */ const char *host, /* I - Hostname or address */ int port, /* I - Port number */ const char *resource) /* I - Resource */ { char *ptr, /* Pointer into URI buffer */ *end; /* End of URI buffer */ /* * Range check input... */ if (!uri || urilen < 1 || !scheme || port < 0) { if (uri) *uri = '\0'; return (HTTP_URI_STATUS_BAD_ARGUMENTS); } /* * Assemble the URI starting with the scheme... */ end = uri + urilen - 1; ptr = http_copy_encode(uri, scheme, end, NULL, NULL, 0); if (!ptr) goto assemble_overflow; if (!strcmp(scheme, "geo") || !strcmp(scheme, "mailto") || !strcmp(scheme, "tel")) { /* * geo:, mailto:, and tel: only have :, no //... */ if (ptr < end) *ptr++ = ':'; else goto assemble_overflow; } else { /* * Schemes other than geo:, mailto:, and tel: typically have //... */ if ((ptr + 2) < end) { *ptr++ = ':'; *ptr++ = '/'; *ptr++ = '/'; } else goto assemble_overflow; } /* * Next the username and hostname, if any... */ if (host) { const char *hostptr; /* Pointer into hostname */ int have_ipv6; /* Do we have an IPv6 address? */ if (username && *username) { /* * Add username@ first... */ ptr = http_copy_encode(ptr, username, end, "/?#[]@", NULL, encoding & HTTP_URI_CODING_USERNAME); if (!ptr) goto assemble_overflow; if (ptr < end) *ptr++ = '@'; else goto assemble_overflow; } /* * Then add the hostname. Since IPv6 is a particular pain to deal * with, we have several special cases to deal with. If we get * an IPv6 address with brackets around it, assume it is already in * URI format. Since DNS-SD service names can sometimes look like * raw IPv6 addresses, we specifically look for "._tcp" in the name, * too... */ for (hostptr = host, have_ipv6 = strchr(host, ':') && !strstr(host, "._tcp"); *hostptr && have_ipv6; hostptr ++) if (*hostptr != ':' && !isxdigit(*hostptr & 255)) { have_ipv6 = *hostptr == '%'; break; } if (have_ipv6) { /* * We have a raw IPv6 address... */ if (strchr(host, '%') && !(encoding & HTTP_URI_CODING_RFC6874)) { /* * We have a link-local address, add "[v1." prefix... */ if ((ptr + 4) < end) { *ptr++ = '['; *ptr++ = 'v'; *ptr++ = '1'; *ptr++ = '.'; } else goto assemble_overflow; } else { /* * We have a normal (or RFC 6874 link-local) address, add "[" prefix... */ if (ptr < end) *ptr++ = '['; else goto assemble_overflow; } /* * Copy the rest of the IPv6 address, and terminate with "]". */ while (ptr < end && *host) { if (*host == '%') { /* * Convert/encode zone separator */ if (encoding & HTTP_URI_CODING_RFC6874) { if (ptr >= (end - 2)) goto assemble_overflow; *ptr++ = '%'; *ptr++ = '2'; *ptr++ = '5'; } else *ptr++ = '+'; host ++; } else *ptr++ = *host++; } if (*host) goto assemble_overflow; if (ptr < end) *ptr++ = ']'; else goto assemble_overflow; } else { /* * Otherwise, just copy the host string (the extra chars are not in the * "reg-name" ABNF rule; anything <= SP or >= DEL plus % gets automatically * percent-encoded. */ ptr = http_copy_encode(ptr, host, end, "\"#/:<>?@[\\]^`{|}", NULL, encoding & HTTP_URI_CODING_HOSTNAME); if (!ptr) goto assemble_overflow; } /* * Finish things off with the port number... */ if (port > 0) { snprintf(ptr, (size_t)(end - ptr + 1), ":%d", port); ptr += strlen(ptr); if (ptr >= end) goto assemble_overflow; } } /* * Last but not least, add the resource string... */ if (resource) { char *query; /* Pointer to query string */ /* * Copy the resource string up to the query string if present... */ query = strchr(resource, '?'); ptr = http_copy_encode(ptr, resource, end, NULL, "?", encoding & HTTP_URI_CODING_RESOURCE); if (!ptr) goto assemble_overflow; if (query) { /* * Copy query string without encoding... */ ptr = http_copy_encode(ptr, query, end, NULL, NULL, encoding & HTTP_URI_CODING_QUERY); if (!ptr) goto assemble_overflow; } } else if (ptr < end) *ptr++ = '/'; else goto assemble_overflow; /* * Nul-terminate the URI buffer and return with no errors... */ *ptr = '\0'; return (HTTP_URI_STATUS_OK); /* * Clear the URI string and return an overflow error; I don't usually * like goto's, but in this case it makes sense... */ assemble_overflow: *uri = '\0'; return (HTTP_URI_STATUS_OVERFLOW); } /* * 'httpAssembleURIf()' - Assemble a uniform resource identifier from its * components with a formatted resource. * * This function creates a formatted version of the resource string * argument "resourcef" and escapes reserved characters in the URI * depending on the value of the "encoding" argument. You should use * this function in place of traditional string functions whenever * you need to create a URI string. * * @since CUPS 1.2/macOS 10.5@ */ http_uri_status_t /* O - URI status */ httpAssembleURIf( http_uri_coding_t encoding, /* I - Encoding flags */ char *uri, /* I - URI buffer */ int urilen, /* I - Size of URI buffer */ const char *scheme, /* I - Scheme name */ const char *username, /* I - Username */ const char *host, /* I - Hostname or address */ int port, /* I - Port number */ const char *resourcef, /* I - Printf-style resource */ ...) /* I - Additional arguments as needed */ { va_list ap; /* Pointer to additional arguments */ char resource[1024]; /* Formatted resource string */ int bytes; /* Bytes in formatted string */ /* * Range check input... */ if (!uri || urilen < 1 || !scheme || port < 0 || !resourcef) { if (uri) *uri = '\0'; return (HTTP_URI_STATUS_BAD_ARGUMENTS); } /* * Format the resource string and assemble the URI... */ va_start(ap, resourcef); bytes = vsnprintf(resource, sizeof(resource), resourcef, ap); va_end(ap); if ((size_t)bytes >= sizeof(resource)) { *uri = '\0'; return (HTTP_URI_STATUS_OVERFLOW); } else return (httpAssembleURI(encoding, uri, urilen, scheme, username, host, port, resource)); } /* * 'httpAssembleUUID()' - Assemble a name-based UUID URN conforming to RFC 4122. * * This function creates a unique 128-bit identifying number using the server * name, port number, random data, and optionally an object name and/or object * number. The result is formatted as a UUID URN as defined in RFC 4122. * * The buffer needs to be at least 46 bytes in size. * * @since CUPS 1.7/macOS 10.9@ */ char * /* I - UUID string */ httpAssembleUUID(const char *server, /* I - Server name */ int port, /* I - Port number */ const char *name, /* I - Object name or NULL */ int number, /* I - Object number or 0 */ char *buffer, /* I - String buffer */ size_t bufsize) /* I - Size of buffer */ { char data[1024]; /* Source string for MD5 */ unsigned char md5sum[16]; /* MD5 digest/sum */ /* * Build a version 3 UUID conforming to RFC 4122. * * Start with the MD5 sum of the server, port, object name and * number, and some random data on the end. */ snprintf(data, sizeof(data), "%s:%d:%s:%d:%04x:%04x", server, port, name ? name : server, number, (unsigned)CUPS_RAND() & 0xffff, (unsigned)CUPS_RAND() & 0xffff); cupsHashData("md5", (unsigned char *)data, strlen(data), md5sum, sizeof(md5sum)); /* * Generate the UUID from the MD5... */ snprintf(buffer, bufsize, "urn:uuid:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" "%02x%02x%02x%02x%02x%02x", md5sum[0], md5sum[1], md5sum[2], md5sum[3], md5sum[4], md5sum[5], (md5sum[6] & 15) | 0x30, md5sum[7], (md5sum[8] & 0x3f) | 0x40, md5sum[9], md5sum[10], md5sum[11], md5sum[12], md5sum[13], md5sum[14], md5sum[15]); return (buffer); } /* * 'httpDecode64()' - Base64-decode a string. * * This function is deprecated. Use the httpDecode64_2() function instead * which provides buffer length arguments. * * @deprecated@ @exclude all@ */ char * /* O - Decoded string */ httpDecode64(char *out, /* I - String to write to */ const char *in) /* I - String to read from */ { int outlen; /* Output buffer length */ /* * Use the old maximum buffer size for binary compatibility... */ outlen = 512; return (httpDecode64_2(out, &outlen, in)); } /* * 'httpDecode64_2()' - Base64-decode a string. * * The caller must initialize "outlen" to the maximum size of the decoded * string before calling @code httpDecode64_2@. On return "outlen" contains the * decoded length of the string. * * @since CUPS 1.1.21/macOS 10.4@ */ char * /* O - Decoded string */ httpDecode64_2(char *out, /* I - String to write to */ int *outlen, /* IO - Size of output string */ const char *in) /* I - String to read from */ { int pos; /* Bit position */ unsigned base64; /* Value of this character */ char *outptr, /* Output pointer */ *outend; /* End of output buffer */ /* * Range check input... */ if (!out || !outlen || *outlen < 1 || !in) return (NULL); if (!*in) { *out = '\0'; *outlen = 0; return (out); } /* * Convert from base-64 to bytes... */ for (outptr = out, outend = out + *outlen - 1, pos = 0; *in != '\0'; in ++) { /* * Decode this character into a number from 0 to 63... */ if (*in >= 'A' && *in <= 'Z') base64 = (unsigned)(*in - 'A'); else if (*in >= 'a' && *in <= 'z') base64 = (unsigned)(*in - 'a' + 26); else if (*in >= '0' && *in <= '9') base64 = (unsigned)(*in - '0' + 52); else if (*in == '+') base64 = 62; else if (*in == '/') base64 = 63; else if (*in == '=') break; else continue; /* * Store the result in the appropriate chars... */ switch (pos) { case 0 : if (outptr < outend) *outptr = (char)(base64 << 2); pos ++; break; case 1 : if (outptr < outend) *outptr++ |= (char)((base64 >> 4) & 3); if (outptr < outend) *outptr = (char)((base64 << 4) & 255); pos ++; break; case 2 : if (outptr < outend) *outptr++ |= (char)((base64 >> 2) & 15); if (outptr < outend) *outptr = (char)((base64 << 6) & 255); pos ++; break; case 3 : if (outptr < outend) *outptr++ |= (char)base64; pos = 0; break; } } *outptr = '\0'; /* * Return the decoded string and size... */ *outlen = (int)(outptr - out); return (out); } /* * 'httpEncode64()' - Base64-encode a string. * * This function is deprecated. Use the httpEncode64_2() function instead * which provides buffer length arguments. * * @deprecated@ @exclude all@ */ char * /* O - Encoded string */ httpEncode64(char *out, /* I - String to write to */ const char *in) /* I - String to read from */ { return (httpEncode64_2(out, 512, in, (int)strlen(in))); } /* * 'httpEncode64_2()' - Base64-encode a string. * * @since CUPS 1.1.21/macOS 10.4@ */ char * /* O - Encoded string */ httpEncode64_2(char *out, /* I - String to write to */ int outlen, /* I - Maximum size of output string */ const char *in, /* I - String to read from */ int inlen) /* I - Size of input string */ { char *outptr, /* Output pointer */ *outend; /* End of output buffer */ static const char base64[] = /* Base64 characters... */ { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789" "+/" }; /* * Range check input... */ if (!out || outlen < 1 || !in) return (NULL); /* * Convert bytes to base-64... */ for (outptr = out, outend = out + outlen - 1; inlen > 0; in ++, inlen --) { /* * Encode the up to 3 characters as 4 Base64 numbers... */ if (outptr < outend) *outptr ++ = base64[(in[0] & 255) >> 2]; if (outptr < outend) { if (inlen > 1) *outptr ++ = base64[(((in[0] & 255) << 4) | ((in[1] & 255) >> 4)) & 63]; else *outptr ++ = base64[((in[0] & 255) << 4) & 63]; } in ++; inlen --; if (inlen <= 0) { if (outptr < outend) *outptr ++ = '='; if (outptr < outend) *outptr ++ = '='; break; } if (outptr < outend) { if (inlen > 1) *outptr ++ = base64[(((in[0] & 255) << 2) | ((in[1] & 255) >> 6)) & 63]; else *outptr ++ = base64[((in[0] & 255) << 2) & 63]; } in ++; inlen --; if (inlen <= 0) { if (outptr < outend) *outptr ++ = '='; break; } if (outptr < outend) *outptr ++ = base64[in[0] & 63]; } *outptr = '\0'; /* * Return the encoded string... */ return (out); } /* * 'httpGetDateString()' - Get a formatted date/time string from a time value. * * @deprecated@ @exclude all@ */ const char * /* O - Date/time string */ httpGetDateString(time_t t) /* I - Time in seconds */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ return (httpGetDateString2(t, cg->http_date, sizeof(cg->http_date))); } /* * 'httpGetDateString2()' - Get a formatted date/time string from a time value. * * @since CUPS 1.2/macOS 10.5@ */ const char * /* O - Date/time string */ httpGetDateString2(time_t t, /* I - Time in seconds */ char *s, /* I - String buffer */ int slen) /* I - Size of string buffer */ { struct tm *tdate; /* UNIX date/time data */ tdate = gmtime(&t); if (tdate) snprintf(s, (size_t)slen, "%s, %02d %s %d %02d:%02d:%02d GMT", http_days[tdate->tm_wday], tdate->tm_mday, http_months[tdate->tm_mon], tdate->tm_year + 1900, tdate->tm_hour, tdate->tm_min, tdate->tm_sec); else s[0] = '\0'; return (s); } /* * 'httpGetDateTime()' - Get a time value from a formatted date/time string. */ time_t /* O - Time in seconds */ httpGetDateTime(const char *s) /* I - Date/time string */ { int i; /* Looping var */ char mon[16]; /* Abbreviated month name */ int day, year; /* Day of month and year */ int hour, min, sec; /* Time */ int days; /* Number of days since 1970 */ static const int normal_days[] = /* Days to a month, normal years */ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; static const int leap_days[] = /* Days to a month, leap years */ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }; DEBUG_printf(("2httpGetDateTime(s=\"%s\")", s)); /* * Extract the date and time from the formatted string... */ if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6) return (0); DEBUG_printf(("4httpGetDateTime: day=%d, mon=\"%s\", year=%d, hour=%d, " "min=%d, sec=%d", day, mon, year, hour, min, sec)); /* * Convert the month name to a number from 0 to 11. */ for (i = 0; i < 12; i ++) if (!_cups_strcasecmp(mon, http_months[i])) break; if (i >= 12) return (0); DEBUG_printf(("4httpGetDateTime: i=%d", i)); /* * Now convert the date and time to a UNIX time value in seconds since * 1970. We can't use mktime() since the timezone may not be UTC but * the date/time string *is* UTC. */ if ((year & 3) == 0 && ((year % 100) != 0 || (year % 400) == 0)) days = leap_days[i] + day - 1; else days = normal_days[i] + day - 1; DEBUG_printf(("4httpGetDateTime: days=%d", days)); days += (year - 1970) * 365 + /* 365 days per year (normally) */ ((year - 1) / 4 - 492) - /* + leap days */ ((year - 1) / 100 - 19) + /* - 100 year days */ ((year - 1) / 400 - 4); /* + 400 year days */ DEBUG_printf(("4httpGetDateTime: days=%d\n", days)); return (days * 86400 + hour * 3600 + min * 60 + sec); } /* * 'httpSeparate()' - Separate a Universal Resource Identifier into its * components. * * This function is deprecated; use the httpSeparateURI() function instead. * * @deprecated@ @exclude all@ */ void httpSeparate(const char *uri, /* I - Universal Resource Identifier */ char *scheme, /* O - Scheme [32] (http, https, etc.) */ char *username, /* O - Username [1024] */ char *host, /* O - Hostname [1024] */ int *port, /* O - Port number to use */ char *resource) /* O - Resource/filename [1024] */ { httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, 32, username, HTTP_MAX_URI, host, HTTP_MAX_URI, port, resource, HTTP_MAX_URI); } /* * 'httpSeparate2()' - Separate a Universal Resource Identifier into its * components. * * This function is deprecated; use the httpSeparateURI() function instead. * * @since CUPS 1.1.21/macOS 10.4@ * @deprecated@ @exclude all@ */ void httpSeparate2(const char *uri, /* I - Universal Resource Identifier */ char *scheme, /* O - Scheme (http, https, etc.) */ int schemelen, /* I - Size of scheme buffer */ char *username, /* O - Username */ int usernamelen, /* I - Size of username buffer */ char *host, /* O - Hostname */ int hostlen, /* I - Size of hostname buffer */ int *port, /* O - Port number to use */ char *resource, /* O - Resource/filename */ int resourcelen) /* I - Size of resource buffer */ { httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, schemelen, username, usernamelen, host, hostlen, port, resource, resourcelen); } /* * 'httpSeparateURI()' - Separate a Universal Resource Identifier into its * components. * * @since CUPS 1.2/macOS 10.5@ */ http_uri_status_t /* O - Result of separation */ httpSeparateURI( http_uri_coding_t decoding, /* I - Decoding flags */ const char *uri, /* I - Universal Resource Identifier */ char *scheme, /* O - Scheme (http, https, etc.) */ int schemelen, /* I - Size of scheme buffer */ char *username, /* O - Username */ int usernamelen, /* I - Size of username buffer */ char *host, /* O - Hostname */ int hostlen, /* I - Size of hostname buffer */ int *port, /* O - Port number to use */ char *resource, /* O - Resource/filename */ int resourcelen) /* I - Size of resource buffer */ { char *ptr, /* Pointer into string... */ *end; /* End of string */ const char *sep; /* Separator character */ http_uri_status_t status; /* Result of separation */ /* * Initialize everything to blank... */ if (scheme && schemelen > 0) *scheme = '\0'; if (username && usernamelen > 0) *username = '\0'; if (host && hostlen > 0) *host = '\0'; if (port) *port = 0; if (resource && resourcelen > 0) *resource = '\0'; /* * Range check input... */ if (!uri || !port || !scheme || schemelen <= 0 || !username || usernamelen <= 0 || !host || hostlen <= 0 || !resource || resourcelen <= 0) return (HTTP_URI_STATUS_BAD_ARGUMENTS); if (!*uri) return (HTTP_URI_STATUS_BAD_URI); /* * Grab the scheme portion of the URI... */ status = HTTP_URI_STATUS_OK; if (!strncmp(uri, "//", 2)) { /* * Workaround for HP IPP client bug... */ strlcpy(scheme, "ipp", (size_t)schemelen); status = HTTP_URI_STATUS_MISSING_SCHEME; } else if (*uri == '/') { /* * Filename... */ strlcpy(scheme, "file", (size_t)schemelen); status = HTTP_URI_STATUS_MISSING_SCHEME; } else { /* * Standard URI with scheme... */ for (ptr = scheme, end = scheme + schemelen - 1; *uri && *uri != ':' && ptr < end;) if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789-+.", *uri) != NULL) *ptr++ = *uri++; else break; *ptr = '\0'; if (*uri != ':') { *scheme = '\0'; return (HTTP_URI_STATUS_BAD_SCHEME); } uri ++; } /* * Set the default port number... */ if (!strcmp(scheme, "http")) *port = 80; else if (!strcmp(scheme, "https")) *port = 443; else if (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) *port = 631; else if (!_cups_strcasecmp(scheme, "lpd")) *port = 515; else if (!strcmp(scheme, "socket")) /* Not yet registered with IANA... */ *port = 9100; else if (strcmp(scheme, "file") && strcmp(scheme, "mailto") && strcmp(scheme, "tel")) status = HTTP_URI_STATUS_UNKNOWN_SCHEME; /* * Now see if we have a hostname... */ if (!strncmp(uri, "//", 2)) { /* * Yes, extract it... */ uri += 2; /* * Grab the username, if any... */ if ((sep = strpbrk(uri, "@/")) != NULL && *sep == '@') { /* * Get a username:password combo... */ uri = http_copy_decode(username, uri, usernamelen, "@", decoding & HTTP_URI_CODING_USERNAME); if (!uri) { *username = '\0'; return (HTTP_URI_STATUS_BAD_USERNAME); } uri ++; } /* * Then the hostname/IP address... */ if (*uri == '[') { /* * Grab IPv6 address... */ uri ++; if (*uri == 'v') { /* * Skip IPvFuture ("vXXXX.") prefix... */ uri ++; while (isxdigit(*uri & 255)) uri ++; if (*uri != '.') { *host = '\0'; return (HTTP_URI_STATUS_BAD_HOSTNAME); } uri ++; } uri = http_copy_decode(host, uri, hostlen, "]", decoding & HTTP_URI_CODING_HOSTNAME); if (!uri) { *host = '\0'; return (HTTP_URI_STATUS_BAD_HOSTNAME); } /* * Validate value... */ if (*uri != ']') { *host = '\0'; return (HTTP_URI_STATUS_BAD_HOSTNAME); } uri ++; for (ptr = host; *ptr; ptr ++) if (*ptr == '+') { /* * Convert zone separator to % and stop here... */ *ptr = '%'; break; } else if (*ptr == '%') { /* * Stop at zone separator (RFC 6874) */ break; } else if (*ptr != ':' && *ptr != '.' && !isxdigit(*ptr & 255)) { *host = '\0'; return (HTTP_URI_STATUS_BAD_HOSTNAME); } } else { /* * Validate the hostname or IPv4 address first... */ for (ptr = (char *)uri; *ptr; ptr ++) if (strchr(":?/", *ptr)) break; else if (!strchr("abcdefghijklmnopqrstuvwxyz" /* unreserved */ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* unreserved */ "0123456789" /* unreserved */ "-._~" /* unreserved */ "%" /* pct-encoded */ "!$&'()*+,;=" /* sub-delims */ "\\", *ptr)) /* SMB domain */ { *host = '\0'; return (HTTP_URI_STATUS_BAD_HOSTNAME); } /* * Then copy the hostname or IPv4 address to the buffer... */ uri = http_copy_decode(host, uri, hostlen, ":?/", decoding & HTTP_URI_CODING_HOSTNAME); if (!uri) { *host = '\0'; return (HTTP_URI_STATUS_BAD_HOSTNAME); } } /* * Validate hostname for file scheme - only empty and localhost are * acceptable. */ if (!strcmp(scheme, "file") && strcmp(host, "localhost") && host[0]) { *host = '\0'; return (HTTP_URI_STATUS_BAD_HOSTNAME); } /* * See if we have a port number... */ if (*uri == ':') { /* * Yes, collect the port number... */ if (!isdigit(uri[1] & 255)) { *port = 0; return (HTTP_URI_STATUS_BAD_PORT); } *port = (int)strtol(uri + 1, (char **)&uri, 10); if (*port <= 0 || *port > 65535) { *port = 0; return (HTTP_URI_STATUS_BAD_PORT); } if (*uri != '/' && *uri) { *port = 0; return (HTTP_URI_STATUS_BAD_PORT); } } } /* * The remaining portion is the resource string... */ if (*uri == '?' || !*uri) { /* * Hostname but no path... */ status = HTTP_URI_STATUS_MISSING_RESOURCE; *resource = '/'; /* * Copy any query string... */ if (*uri == '?') uri = http_copy_decode(resource + 1, uri, resourcelen - 1, NULL, decoding & HTTP_URI_CODING_QUERY); else resource[1] = '\0'; } else { uri = http_copy_decode(resource, uri, resourcelen, "?", decoding & HTTP_URI_CODING_RESOURCE); if (uri && *uri == '?') { /* * Concatenate any query string... */ char *resptr = resource + strlen(resource); uri = http_copy_decode(resptr, uri, resourcelen - (int)(resptr - resource), NULL, decoding & HTTP_URI_CODING_QUERY); } } if (!uri) { *resource = '\0'; return (HTTP_URI_STATUS_BAD_RESOURCE); } /* * Return the URI separation status... */ return (status); } /* * 'httpStateString()' - Return the string describing a HTTP state value. * * @since CUPS 2.0/OS 10.10@ */ const char * /* O - State string */ httpStateString(http_state_t state) /* I - HTTP state value */ { if (state < HTTP_STATE_ERROR || state > HTTP_STATE_UNKNOWN_VERSION) return ("HTTP_STATE_???"); else return (http_states[state - HTTP_STATE_ERROR]); } /* * '_httpStatus()' - Return the localized string describing a HTTP status code. * * The returned string is localized using the passed message catalog. */ const char * /* O - Localized status string */ _httpStatus(cups_lang_t *lang, /* I - Language */ http_status_t status) /* I - HTTP status code */ { const char *s; /* Status string */ switch (status) { case HTTP_STATUS_ERROR : s = strerror(errno); break; case HTTP_STATUS_CONTINUE : s = _("Continue"); break; case HTTP_STATUS_SWITCHING_PROTOCOLS : s = _("Switching Protocols"); break; case HTTP_STATUS_OK : s = _("OK"); break; case HTTP_STATUS_CREATED : s = _("Created"); break; case HTTP_STATUS_ACCEPTED : s = _("Accepted"); break; case HTTP_STATUS_NO_CONTENT : s = _("No Content"); break; case HTTP_STATUS_MOVED_PERMANENTLY : s = _("Moved Permanently"); break; case HTTP_STATUS_FOUND : s = _("Found"); break; case HTTP_STATUS_SEE_OTHER : s = _("See Other"); break; case HTTP_STATUS_NOT_MODIFIED : s = _("Not Modified"); break; case HTTP_STATUS_BAD_REQUEST : s = _("Bad Request"); break; case HTTP_STATUS_UNAUTHORIZED : case HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED : s = _("Unauthorized"); break; case HTTP_STATUS_FORBIDDEN : s = _("Forbidden"); break; case HTTP_STATUS_NOT_FOUND : s = _("Not Found"); break; case HTTP_STATUS_REQUEST_TOO_LARGE : s = _("Request Entity Too Large"); break; case HTTP_STATUS_URI_TOO_LONG : s = _("URI Too Long"); break; case HTTP_STATUS_UPGRADE_REQUIRED : s = _("Upgrade Required"); break; case HTTP_STATUS_NOT_IMPLEMENTED : s = _("Not Implemented"); break; case HTTP_STATUS_NOT_SUPPORTED : s = _("Not Supported"); break; case HTTP_STATUS_EXPECTATION_FAILED : s = _("Expectation Failed"); break; case HTTP_STATUS_SERVICE_UNAVAILABLE : s = _("Service Unavailable"); break; case HTTP_STATUS_SERVER_ERROR : s = _("Internal Server Error"); break; case HTTP_STATUS_CUPS_PKI_ERROR : s = _("SSL/TLS Negotiation Error"); break; case HTTP_STATUS_CUPS_WEBIF_DISABLED : s = _("Web Interface is Disabled"); break; default : s = _("Unknown"); break; } return (_cupsLangString(lang, s)); } /* * 'httpStatus()' - Return a short string describing a HTTP status code. * * The returned string is localized to the current POSIX locale and is based * on the status strings defined in RFC 7231. */ const char * /* O - Localized status string */ httpStatus(http_status_t status) /* I - HTTP status code */ { _cups_globals_t *cg = _cupsGlobals(); /* Global data */ if (!cg->lang_default) cg->lang_default = cupsLangDefault(); return (_httpStatus(cg->lang_default, status)); } /* * 'httpURIStatusString()' - Return a string describing a URI status code. * * @since CUPS 2.0/OS 10.10@ */ const char * /* O - Localized status string */ httpURIStatusString( http_uri_status_t status) /* I - URI status code */ { const char *s; /* Status string */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ if (!cg->lang_default) cg->lang_default = cupsLangDefault(); switch (status) { case HTTP_URI_STATUS_OVERFLOW : s = _("URI too large"); break; case HTTP_URI_STATUS_BAD_ARGUMENTS : s = _("Bad arguments to function"); break; case HTTP_URI_STATUS_BAD_RESOURCE : s = _("Bad resource in URI"); break; case HTTP_URI_STATUS_BAD_PORT : s = _("Bad port number in URI"); break; case HTTP_URI_STATUS_BAD_HOSTNAME : s = _("Bad hostname/address in URI"); break; case HTTP_URI_STATUS_BAD_USERNAME : s = _("Bad username in URI"); break; case HTTP_URI_STATUS_BAD_SCHEME : s = _("Bad scheme in URI"); break; case HTTP_URI_STATUS_BAD_URI : s = _("Bad/empty URI"); break; case HTTP_URI_STATUS_OK : s = _("OK"); break; case HTTP_URI_STATUS_MISSING_SCHEME : s = _("Missing scheme in URI"); break; case HTTP_URI_STATUS_UNKNOWN_SCHEME : s = _("Unknown scheme in URI"); break; case HTTP_URI_STATUS_MISSING_RESOURCE : s = _("Missing resource in URI"); break; default: s = _("Unknown"); break; } return (_cupsLangString(cg->lang_default, s)); } #ifndef HAVE_HSTRERROR /* * '_cups_hstrerror()' - hstrerror() emulation function for Solaris and others. */ const char * /* O - Error string */ _cups_hstrerror(int error) /* I - Error number */ { static const char * const errors[] = /* Error strings */ { "OK", "Host not found.", "Try again.", "Unrecoverable lookup error.", "No data associated with name." }; if (error < 0 || error > 4) return ("Unknown hostname lookup error."); else return (errors[error]); } #endif /* !HAVE_HSTRERROR */ /* * '_httpDecodeURI()' - Percent-decode a HTTP request URI. */ char * /* O - Decoded URI or NULL on error */ _httpDecodeURI(char *dst, /* I - Destination buffer */ const char *src, /* I - Source URI */ size_t dstsize) /* I - Size of destination buffer */ { if (http_copy_decode(dst, src, (int)dstsize, NULL, 1)) return (dst); else return (NULL); } /* * '_httpEncodeURI()' - Percent-encode a HTTP request URI. */ char * /* O - Encoded URI */ _httpEncodeURI(char *dst, /* I - Destination buffer */ const char *src, /* I - Source URI */ size_t dstsize) /* I - Size of destination buffer */ { http_copy_encode(dst, src, dst + dstsize - 1, NULL, NULL, 1); return (dst); } /* * '_httpResolveURI()' - Resolve a DNS-SD URI. */ const char * /* O - Resolved URI */ _httpResolveURI( const char *uri, /* I - DNS-SD URI */ char *resolved_uri, /* I - Buffer for resolved URI */ size_t resolved_size, /* I - Size of URI buffer */ int options, /* I - Resolve options */ int (*cb)(void *context), /* I - Continue callback function */ void *context) /* I - Context pointer for callback */ { char scheme[32], /* URI components... */ userpass[256], hostname[1024], resource[1024]; int port; #ifdef DEBUG http_uri_status_t status; /* URI decode status */ #endif /* DEBUG */ DEBUG_printf(("_httpResolveURI(uri=\"%s\", resolved_uri=%p, resolved_size=" CUPS_LLFMT ", options=0x%x, cb=%p, context=%p)", uri, (void *)resolved_uri, CUPS_LLCAST resolved_size, options, (void *)cb, context)); /* * Get the device URI... */ #ifdef DEBUG if ((status = httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource))) < HTTP_URI_STATUS_OK) #else if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) #endif /* DEBUG */ { if (options & _HTTP_RESOLVE_STDERR) _cupsLangPrintFilter(stderr, "ERROR", _("Bad device-uri \"%s\"."), uri); DEBUG_printf(("2_httpResolveURI: httpSeparateURI returned %d!", status)); DEBUG_puts("2_httpResolveURI: Returning NULL"); return (NULL); } /* * Resolve it as needed... */ if (strstr(hostname, "._tcp")) { #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) char *regtype, /* Pointer to type in hostname */ *domain, /* Pointer to domain in hostname */ *uuid, /* Pointer to UUID in URI */ *uuidend; /* Pointer to end of UUID in URI */ _http_uribuf_t uribuf; /* URI buffer */ int offline = 0; /* offline-report state set? */ # ifdef HAVE_DNSSD # ifdef WIN32 # pragma comment(lib, "dnssd.lib") # endif /* WIN32 */ DNSServiceRef ref, /* DNS-SD master service reference */ domainref = NULL,/* DNS-SD service reference for domain */ ippref = NULL, /* DNS-SD service reference for network IPP */ ippsref = NULL, /* DNS-SD service reference for network IPPS */ localref; /* DNS-SD service reference for .local */ int extrasent = 0; /* Send the domain/IPP/IPPS resolves? */ # ifdef HAVE_POLL struct pollfd polldata; /* Polling data */ # else /* select() */ fd_set input_set; /* Input set for select() */ struct timeval stimeout; /* Timeout value for select() */ # endif /* HAVE_POLL */ # elif defined(HAVE_AVAHI) AvahiClient *client; /* Client information */ int error; /* Status */ # endif /* HAVE_DNSSD */ if (options & _HTTP_RESOLVE_STDERR) fprintf(stderr, "DEBUG: Resolving \"%s\"...\n", hostname); /* * Separate the hostname into service name, registration type, and domain... */ for (regtype = strstr(hostname, "._tcp") - 2; regtype > hostname; regtype --) if (regtype[0] == '.' && regtype[1] == '_') { /* * Found ._servicetype in front of ._tcp... */ *regtype++ = '\0'; break; } if (regtype <= hostname) { DEBUG_puts("2_httpResolveURI: Bad hostname, returning NULL"); return (NULL); } for (domain = strchr(regtype, '.'); domain; domain = strchr(domain + 1, '.')) if (domain[1] != '_') break; if (domain) *domain++ = '\0'; if ((uuid = strstr(resource, "?uuid=")) != NULL) { *uuid = '\0'; uuid += 6; if ((uuidend = strchr(uuid, '&')) != NULL) *uuidend = '\0'; } resolved_uri[0] = '\0'; uribuf.buffer = resolved_uri; uribuf.bufsize = resolved_size; uribuf.options = options; uribuf.resource = resource; uribuf.uuid = uuid; DEBUG_printf(("2_httpResolveURI: Resolving hostname=\"%s\", regtype=\"%s\", " "domain=\"%s\"\n", hostname, regtype, domain)); if (options & _HTTP_RESOLVE_STDERR) { fputs("STATE: +connecting-to-device\n", stderr); fprintf(stderr, "DEBUG: Resolving \"%s\", regtype=\"%s\", " "domain=\"local.\"...\n", hostname, regtype); } uri = NULL; # ifdef HAVE_DNSSD if (DNSServiceCreateConnection(&ref) == kDNSServiceErr_NoError) { uint32_t myinterface = kDNSServiceInterfaceIndexAny; /* Lookup on any interface */ if (!strcmp(scheme, "ippusb")) myinterface = kDNSServiceInterfaceIndexLocalOnly; localref = ref; if (DNSServiceResolve(&localref, kDNSServiceFlagsShareConnection, myinterface, hostname, regtype, "local.", http_resolve_cb, &uribuf) == kDNSServiceErr_NoError) { int fds; /* Number of ready descriptors */ time_t timeout, /* Poll timeout */ start_time = time(NULL),/* Start time */ end_time = start_time + 90; /* End time */ while (time(NULL) < end_time) { if (options & _HTTP_RESOLVE_STDERR) _cupsLangPrintFilter(stderr, "INFO", _("Looking for printer.")); if (cb && !(*cb)(context)) { DEBUG_puts("2_httpResolveURI: callback returned 0 (stop)"); break; } /* * Wakeup every 2 seconds to emit a "looking for printer" message... */ if ((timeout = end_time - time(NULL)) > 2) timeout = 2; # ifdef HAVE_POLL polldata.fd = DNSServiceRefSockFD(ref); polldata.events = POLLIN; fds = poll(&polldata, 1, (int)(1000 * timeout)); # else /* select() */ FD_ZERO(&input_set); FD_SET(DNSServiceRefSockFD(ref), &input_set); # ifdef WIN32 stimeout.tv_sec = (long)timeout; # else stimeout.tv_sec = timeout; # endif /* WIN32 */ stimeout.tv_usec = 0; fds = select(DNSServiceRefSockFD(ref)+1, &input_set, NULL, NULL, &stimeout); # endif /* HAVE_POLL */ if (fds < 0) { if (errno != EINTR && errno != EAGAIN) { DEBUG_printf(("2_httpResolveURI: poll error: %s", strerror(errno))); break; } } else if (fds == 0) { /* * Wait 2 seconds for a response to the local resolve; if nothing * comes in, do an additional domain resolution... */ if (extrasent == 0 && domain && _cups_strcasecmp(domain, "local.")) { if (options & _HTTP_RESOLVE_STDERR) fprintf(stderr, "DEBUG: Resolving \"%s\", regtype=\"%s\", " "domain=\"%s\"...\n", hostname, regtype, domain ? domain : ""); domainref = ref; if (DNSServiceResolve(&domainref, kDNSServiceFlagsShareConnection, myinterface, hostname, regtype, domain, http_resolve_cb, &uribuf) == kDNSServiceErr_NoError) extrasent = 1; } else if (extrasent == 0 && !strcmp(scheme, "ippusb")) { if (options & _HTTP_RESOLVE_STDERR) fprintf(stderr, "DEBUG: Resolving \"%s\", regtype=\"_ipps._tcp\", domain=\"local.\"...\n", hostname); ippsref = ref; if (DNSServiceResolve(&ippsref, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexAny, hostname, "_ipps._tcp", domain, http_resolve_cb, &uribuf) == kDNSServiceErr_NoError) extrasent = 1; } else if (extrasent == 1 && !strcmp(scheme, "ippusb")) { if (options & _HTTP_RESOLVE_STDERR) fprintf(stderr, "DEBUG: Resolving \"%s\", regtype=\"_ipp._tcp\", domain=\"local.\"...\n", hostname); ippref = ref; if (DNSServiceResolve(&ippref, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexAny, hostname, "_ipp._tcp", domain, http_resolve_cb, &uribuf) == kDNSServiceErr_NoError) extrasent = 2; } /* * If it hasn't resolved within 5 seconds set the offline-report * printer-state-reason... */ if ((options & _HTTP_RESOLVE_STDERR) && offline == 0 && time(NULL) > (start_time + 5)) { fputs("STATE: +offline-report\n", stderr); offline = 1; } } else { if (DNSServiceProcessResult(ref) == kDNSServiceErr_NoError && resolved_uri[0]) { uri = resolved_uri; break; } } } if (extrasent) { if (domainref) DNSServiceRefDeallocate(domainref); if (ippref) DNSServiceRefDeallocate(ippref); if (ippsref) DNSServiceRefDeallocate(ippsref); } DNSServiceRefDeallocate(localref); } DNSServiceRefDeallocate(ref); } # else /* HAVE_AVAHI */ if ((uribuf.poll = avahi_simple_poll_new()) != NULL) { avahi_simple_poll_set_func(uribuf.poll, http_poll_cb, NULL); if ((client = avahi_client_new(avahi_simple_poll_get(uribuf.poll), 0, http_client_cb, &uribuf, &error)) != NULL) { if (avahi_service_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, hostname, regtype, "local.", AVAHI_PROTO_UNSPEC, 0, http_resolve_cb, &uribuf) != NULL) { time_t start_time = time(NULL), /* Start time */ end_time = start_time + 90; /* End time */ int pstatus; /* Poll status */ pstatus = avahi_simple_poll_iterate(uribuf.poll, 2000); if (pstatus == 0 && !resolved_uri[0] && domain && _cups_strcasecmp(domain, "local.")) { /* * Resolve for .local hasn't returned anything, try the listed * domain... */ avahi_service_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, hostname, regtype, domain, AVAHI_PROTO_UNSPEC, 0, http_resolve_cb, &uribuf); } while (!pstatus && !resolved_uri[0] && time(NULL) < end_time) { if ((pstatus = avahi_simple_poll_iterate(uribuf.poll, 2000)) != 0) break; /* * If it hasn't resolved within 5 seconds set the offline-report * printer-state-reason... */ if ((options & _HTTP_RESOLVE_STDERR) && offline == 0 && time(NULL) > (start_time + 5)) { fputs("STATE: +offline-report\n", stderr); offline = 1; } } /* * Collect the result (if we got one). */ if (resolved_uri[0]) uri = resolved_uri; } avahi_client_free(client); } avahi_simple_poll_free(uribuf.poll); } # endif /* HAVE_DNSSD */ if (options & _HTTP_RESOLVE_STDERR) { if (uri) { fprintf(stderr, "DEBUG: Resolved as \"%s\"...\n", uri); fputs("STATE: -connecting-to-device,offline-report\n", stderr); } else { fputs("DEBUG: Unable to resolve URI\n", stderr); fputs("STATE: -connecting-to-device\n", stderr); } } #else /* HAVE_DNSSD || HAVE_AVAHI */ /* * No DNS-SD support... */ uri = NULL; #endif /* HAVE_DNSSD || HAVE_AVAHI */ if ((options & _HTTP_RESOLVE_STDERR) && !uri) _cupsLangPrintFilter(stderr, "INFO", _("Unable to find printer.")); } else { /* * Nothing more to do... */ strlcpy(resolved_uri, uri, resolved_size); uri = resolved_uri; } DEBUG_printf(("2_httpResolveURI: Returning \"%s\"", uri)); return (uri); } #ifdef HAVE_AVAHI /* * 'http_client_cb()' - Client callback for resolving URI. */ static void http_client_cb( AvahiClient *client, /* I - Client information */ AvahiClientState state, /* I - Current state */ void *context) /* I - Pointer to URI buffer */ { DEBUG_printf(("7http_client_cb(client=%p, state=%d, context=%p)", client, state, context)); /* * If the connection drops, quit. */ if (state == AVAHI_CLIENT_FAILURE) { _http_uribuf_t *uribuf = (_http_uribuf_t *)context; /* URI buffer */ avahi_simple_poll_quit(uribuf->poll); } } #endif /* HAVE_AVAHI */ /* * 'http_copy_decode()' - Copy and decode a URI. */ static const char * /* O - New source pointer or NULL on error */ http_copy_decode(char *dst, /* O - Destination buffer */ const char *src, /* I - Source pointer */ int dstsize, /* I - Destination size */ const char *term, /* I - Terminating characters */ int decode) /* I - Decode %-encoded values */ { char *ptr, /* Pointer into buffer */ *end; /* End of buffer */ int quoted; /* Quoted character */ /* * Copy the src to the destination until we hit a terminating character * or the end of the string. */ for (ptr = dst, end = dst + dstsize - 1; *src && (!term || !strchr(term, *src)); src ++) if (ptr < end) { if (*src == '%' && decode) { if (isxdigit(src[1] & 255) && isxdigit(src[2] & 255)) { /* * Grab a hex-encoded character... */ src ++; if (isalpha(*src)) quoted = (tolower(*src) - 'a' + 10) << 4; else quoted = (*src - '0') << 4; src ++; if (isalpha(*src)) quoted |= tolower(*src) - 'a' + 10; else quoted |= *src - '0'; *ptr++ = (char)quoted; } else { /* * Bad hex-encoded character... */ *ptr = '\0'; return (NULL); } } else if ((*src & 255) <= 0x20 || (*src & 255) >= 0x7f) { *ptr = '\0'; return (NULL); } else *ptr++ = *src; } *ptr = '\0'; return (src); } /* * 'http_copy_encode()' - Copy and encode a URI. */ static char * /* O - End of current URI */ http_copy_encode(char *dst, /* O - Destination buffer */ const char *src, /* I - Source pointer */ char *dstend, /* I - End of destination buffer */ const char *reserved, /* I - Extra reserved characters */ const char *term, /* I - Terminating characters */ int encode) /* I - %-encode reserved chars? */ { static const char hex[] = "0123456789ABCDEF"; while (*src && dst < dstend) { if (term && *src == *term) return (dst); if (encode && (*src == '%' || *src <= ' ' || *src & 128 || (reserved && strchr(reserved, *src)))) { /* * Hex encode reserved characters... */ if ((dst + 2) >= dstend) break; *dst++ = '%'; *dst++ = hex[(*src >> 4) & 15]; *dst++ = hex[*src & 15]; src ++; } else *dst++ = *src++; } *dst = '\0'; if (*src) return (NULL); else return (dst); } #ifdef HAVE_DNSSD /* * 'http_resolve_cb()' - Build a device URI for the given service name. */ static void DNSSD_API http_resolve_cb( DNSServiceRef sdRef, /* I - Service reference */ DNSServiceFlags flags, /* I - Results flags */ uint32_t interfaceIndex, /* I - Interface number */ DNSServiceErrorType errorCode, /* I - Error, if any */ const char *fullName, /* I - Full service name */ const char *hostTarget, /* I - Hostname */ uint16_t port, /* I - Port number */ uint16_t txtLen, /* I - Length of TXT record */ const unsigned char *txtRecord, /* I - TXT record data */ void *context) /* I - Pointer to URI buffer */ { _http_uribuf_t *uribuf = (_http_uribuf_t *)context; /* URI buffer */ const char *scheme, /* URI scheme */ *hostptr, /* Pointer into hostTarget */ *reskey, /* "rp" or "rfo" */ *resdefault; /* Default path */ char resource[257], /* Remote path */ fqdn[256]; /* FQDN of the .local name */ const void *value; /* Value from TXT record */ uint8_t valueLen; /* Length of value */ DEBUG_printf(("4http_resolve_cb(sdRef=%p, flags=%x, interfaceIndex=%u, errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, txtLen=%u, txtRecord=%p, context=%p)", (void *)sdRef, flags, interfaceIndex, errorCode, fullName, hostTarget, port, txtLen, (void *)txtRecord, context)); /* * If we have a UUID, compare it... */ if (uribuf->uuid && (value = TXTRecordGetValuePtr(txtLen, txtRecord, "UUID", &valueLen)) != NULL) { char uuid[256]; /* UUID value */ memcpy(uuid, value, valueLen); uuid[valueLen] = '\0'; if (_cups_strcasecmp(uuid, uribuf->uuid)) { if (uribuf->options & _HTTP_RESOLVE_STDERR) fprintf(stderr, "DEBUG: Found UUID %s, looking for %s.", uuid, uribuf->uuid); DEBUG_printf(("5http_resolve_cb: Found UUID %s, looking for %s.", uuid, uribuf->uuid)); return; } } /* * Figure out the scheme from the full name... */ if (strstr(fullName, "._ipps") || strstr(fullName, "._ipp-tls")) scheme = "ipps"; else if (strstr(fullName, "._ipp") || strstr(fullName, "._fax-ipp")) scheme = "ipp"; else if (strstr(fullName, "._http.")) scheme = "http"; else if (strstr(fullName, "._https.")) scheme = "https"; else if (strstr(fullName, "._printer.")) scheme = "lpd"; else if (strstr(fullName, "._pdl-datastream.")) scheme = "socket"; else scheme = "riousbprint"; /* * Extract the "remote printer" key from the TXT record... */ if ((uribuf->options & _HTTP_RESOLVE_FAXOUT) && (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) && !TXTRecordGetValuePtr(txtLen, txtRecord, "printer-type", &valueLen)) { reskey = "rfo"; resdefault = "/ipp/faxout"; } else { reskey = "rp"; resdefault = "/"; } if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, reskey, &valueLen)) != NULL) { if (((char *)value)[0] == '/') { /* * Value (incorrectly) has a leading slash already... */ memcpy(resource, value, valueLen); resource[valueLen] = '\0'; } else { /* * Convert to resource by concatenating with a leading "/"... */ resource[0] = '/'; memcpy(resource + 1, value, valueLen); resource[valueLen + 1] = '\0'; } } else { /* * Use the default value... */ strlcpy(resource, resdefault, sizeof(resource)); } /* * Lookup the FQDN if needed... */ if ((uribuf->options & _HTTP_RESOLVE_FQDN) && (hostptr = hostTarget + strlen(hostTarget) - 7) > hostTarget && !_cups_strcasecmp(hostptr, ".local.")) { /* * OK, we got a .local name but the caller needs a real domain. Start by * getting the IP address of the .local name and then do reverse-lookups... */ http_addrlist_t *addrlist, /* List of addresses */ *addr; /* Current address */ DEBUG_printf(("5http_resolve_cb: Looking up \"%s\".", hostTarget)); snprintf(fqdn, sizeof(fqdn), "%d", ntohs(port)); if ((addrlist = httpAddrGetList(hostTarget, AF_UNSPEC, fqdn)) != NULL) { for (addr = addrlist; addr; addr = addr->next) { int error = getnameinfo(&(addr->addr.addr), (socklen_t)httpAddrLength(&(addr->addr)), fqdn, sizeof(fqdn), NULL, 0, NI_NAMEREQD); if (!error) { DEBUG_printf(("5http_resolve_cb: Found \"%s\".", fqdn)); if ((hostptr = fqdn + strlen(fqdn) - 6) <= fqdn || _cups_strcasecmp(hostptr, ".local")) { hostTarget = fqdn; break; } } #ifdef DEBUG else DEBUG_printf(("5http_resolve_cb: \"%s\" did not resolve: %d", httpAddrString(&(addr->addr), fqdn, sizeof(fqdn)), error)); #endif /* DEBUG */ } httpAddrFreeList(addrlist); } } /* * Assemble the final device URI... */ if ((!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) && !strcmp(uribuf->resource, "/cups")) httpAssembleURIf(HTTP_URI_CODING_ALL, uribuf->buffer, (int)uribuf->bufsize, scheme, NULL, hostTarget, ntohs(port), "%s?snmp=false", resource); else httpAssembleURI(HTTP_URI_CODING_ALL, uribuf->buffer, (int)uribuf->bufsize, scheme, NULL, hostTarget, ntohs(port), resource); DEBUG_printf(("5http_resolve_cb: Resolved URI is \"%s\"...", uribuf->buffer)); } #elif defined(HAVE_AVAHI) /* * 'http_poll_cb()' - Wait for input on the specified file descriptors. * * Note: This function is needed because avahi_simple_poll_iterate is broken * and always uses a timeout of 0 (!) milliseconds. * (Avahi Ticket #364) * * @private@ */ static int /* O - Number of file descriptors matching */ http_poll_cb( struct pollfd *pollfds, /* I - File descriptors */ unsigned int num_pollfds, /* I - Number of file descriptors */ int timeout, /* I - Timeout in milliseconds (used) */ void *context) /* I - User data (unused) */ { (void)timeout; (void)context; return (poll(pollfds, num_pollfds, 2000)); } /* * 'http_resolve_cb()' - Build a device URI for the given service name. */ static void http_resolve_cb( AvahiServiceResolver *resolver, /* I - Resolver (unused) */ AvahiIfIndex interface, /* I - Interface index (unused) */ AvahiProtocol protocol, /* I - Network protocol (unused) */ AvahiResolverEvent event, /* I - Event (found, etc.) */ const char *name, /* I - Service name */ const char *type, /* I - Registration type */ const char *domain, /* I - Domain (unused) */ const char *hostTarget, /* I - Hostname */ const AvahiAddress *address, /* I - Address (unused) */ uint16_t port, /* I - Port number */ AvahiStringList *txt, /* I - TXT record */ AvahiLookupResultFlags flags, /* I - Lookup flags (unused) */ void *context) /* I - Pointer to URI buffer */ { _http_uribuf_t *uribuf = (_http_uribuf_t *)context; /* URI buffer */ const char *scheme, /* URI scheme */ *hostptr, /* Pointer into hostTarget */ *reskey, /* "rp" or "rfo" */ *resdefault; /* Default path */ char resource[257], /* Remote path */ fqdn[256]; /* FQDN of the .local name */ AvahiStringList *pair; /* Current TXT record key/value pair */ char *value; /* Value for "rp" key */ size_t valueLen = 0; /* Length of "rp" key */ DEBUG_printf(("4http_resolve_cb(resolver=%p, " "interface=%d, protocol=%d, event=%d, name=\"%s\", " "type=\"%s\", domain=\"%s\", hostTarget=\"%s\", address=%p, " "port=%d, txt=%p, flags=%d, context=%p)", resolver, interface, protocol, event, name, type, domain, hostTarget, address, port, txt, flags, context)); if (event != AVAHI_RESOLVER_FOUND) { avahi_service_resolver_free(resolver); avahi_simple_poll_quit(uribuf->poll); return; } /* * If we have a UUID, compare it... */ if (uribuf->uuid && (pair = avahi_string_list_find(txt, "UUID")) != NULL) { char uuid[256]; /* UUID value */ avahi_string_list_get_pair(pair, NULL, &value, &valueLen); memcpy(uuid, value, valueLen); uuid[valueLen] = '\0'; if (_cups_strcasecmp(uuid, uribuf->uuid)) { if (uribuf->options & _HTTP_RESOLVE_STDERR) fprintf(stderr, "DEBUG: Found UUID %s, looking for %s.", uuid, uribuf->uuid); DEBUG_printf(("5http_resolve_cb: Found UUID %s, looking for %s.", uuid, uribuf->uuid)); return; } } /* * Figure out the scheme from the full name... */ if (strstr(type, "_ipp.")) scheme = "ipp"; else if (strstr(type, "_printer.")) scheme = "lpd"; else if (strstr(type, "_pdl-datastream.")) scheme = "socket"; else scheme = "riousbprint"; if (!strncmp(type, "_ipps.", 6) || !strncmp(type, "_ipp-tls.", 9)) scheme = "ipps"; else if (!strncmp(type, "_ipp.", 5) || !strncmp(type, "_fax-ipp.", 9)) scheme = "ipp"; else if (!strncmp(type, "_http.", 6)) scheme = "http"; else if (!strncmp(type, "_https.", 7)) scheme = "https"; else if (!strncmp(type, "_printer.", 9)) scheme = "lpd"; else if (!strncmp(type, "_pdl-datastream.", 16)) scheme = "socket"; else { avahi_service_resolver_free(resolver); avahi_simple_poll_quit(uribuf->poll); return; } /* * Extract the remote resource key from the TXT record... */ if ((uribuf->options & _HTTP_RESOLVE_FAXOUT) && (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) && !avahi_string_list_find(txt, "printer-type")) { reskey = "rfo"; resdefault = "/ipp/faxout"; } else { reskey = "rp"; resdefault = "/"; } if ((pair = avahi_string_list_find(txt, reskey)) != NULL) { avahi_string_list_get_pair(pair, NULL, &value, &valueLen); if (value[0] == '/') { /* * Value (incorrectly) has a leading slash already... */ memcpy(resource, value, valueLen); resource[valueLen] = '\0'; } else { /* * Convert to resource by concatenating with a leading "/"... */ resource[0] = '/'; memcpy(resource + 1, value, valueLen); resource[valueLen + 1] = '\0'; } } else { /* * Use the default value... */ strlcpy(resource, resdefault, sizeof(resource)); } /* * Lookup the FQDN if needed... */ if ((uribuf->options & _HTTP_RESOLVE_FQDN) && (hostptr = hostTarget + strlen(hostTarget) - 6) > hostTarget && !_cups_strcasecmp(hostptr, ".local")) { /* * OK, we got a .local name but the caller needs a real domain. Start by * getting the IP address of the .local name and then do reverse-lookups... */ http_addrlist_t *addrlist, /* List of addresses */ *addr; /* Current address */ DEBUG_printf(("5http_resolve_cb: Looking up \"%s\".", hostTarget)); snprintf(fqdn, sizeof(fqdn), "%d", ntohs(port)); if ((addrlist = httpAddrGetList(hostTarget, AF_UNSPEC, fqdn)) != NULL) { for (addr = addrlist; addr; addr = addr->next) { int error = getnameinfo(&(addr->addr.addr), (socklen_t)httpAddrLength(&(addr->addr)), fqdn, sizeof(fqdn), NULL, 0, NI_NAMEREQD); if (!error) { DEBUG_printf(("5http_resolve_cb: Found \"%s\".", fqdn)); if ((hostptr = fqdn + strlen(fqdn) - 6) <= fqdn || _cups_strcasecmp(hostptr, ".local")) { hostTarget = fqdn; break; } } #ifdef DEBUG else DEBUG_printf(("5http_resolve_cb: \"%s\" did not resolve: %d", httpAddrString(&(addr->addr), fqdn, sizeof(fqdn)), error)); #endif /* DEBUG */ } httpAddrFreeList(addrlist); } } /* * Assemble the final device URI using the resolved hostname... */ httpAssembleURI(HTTP_URI_CODING_ALL, uribuf->buffer, (int)uribuf->bufsize, scheme, NULL, hostTarget, port, resource); DEBUG_printf(("5http_resolve_cb: Resolved URI is \"%s\".", uribuf->buffer)); avahi_simple_poll_quit(uribuf->poll); } #endif /* HAVE_DNSSD */ ippsample/cups/util.c0000644000175000017500000006703413240604116013644 0ustar tilltill/* * Printing utilities for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #include #include #if defined(WIN32) || defined(__EMX__) # include #else # include #endif /* WIN32 || __EMX__ */ /* * Enumeration data and callback... */ typedef struct _cups_createdata_s { const char *name; /* Destination name */ cups_dest_t *dest; /* Matching destination */ } _cups_createdata_t; static int cups_create_cb(_cups_createdata_t *data, unsigned flags, cups_dest_t *dest); /* * 'cupsCancelJob()' - Cancel a print job on the default server. * * Pass @code CUPS_JOBID_ALL@ to cancel all jobs or @code CUPS_JOBID_CURRENT@ * to cancel the current job on the named destination. * * Use the @link cupsLastError@ and @link cupsLastErrorString@ functions to get * the cause of any failure. * * @exclude all@ */ int /* O - 1 on success, 0 on failure */ cupsCancelJob(const char *name, /* I - Name of printer or class */ int job_id) /* I - Job ID, @code CUPS_JOBID_CURRENT@ for the current job, or @code CUPS_JOBID_ALL@ for all jobs */ { return (cupsCancelJob2(CUPS_HTTP_DEFAULT, name, job_id, 0) < IPP_STATUS_REDIRECTION_OTHER_SITE); } /* * 'cupsCancelJob2()' - Cancel or purge a print job. * * Canceled jobs remain in the job history while purged jobs are removed * from the job history. * * Pass @code CUPS_JOBID_ALL@ to cancel all jobs or @code CUPS_JOBID_CURRENT@ * to cancel the current job on the named destination. * * Use the @link cupsLastError@ and @link cupsLastErrorString@ functions to get * the cause of any failure. * * @since CUPS 1.4/macOS 10.6@ @exclude all@ */ ipp_status_t /* O - IPP status */ cupsCancelJob2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *name, /* I - Name of printer or class */ int job_id, /* I - Job ID, @code CUPS_JOBID_CURRENT@ for the current job, or @code CUPS_JOBID_ALL@ for all jobs */ int purge) /* I - 1 to purge, 0 to cancel */ { char uri[HTTP_MAX_URI]; /* Job/printer URI */ ipp_t *request; /* IPP request */ /* * Range check input... */ if (job_id < -1 || (!name && job_id == 0)) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (0); } /* * Connect to the default server as needed... */ if (!http) if ((http = _cupsConnect()) == NULL) return (IPP_STATUS_ERROR_SERVICE_UNAVAILABLE); /* * Build an IPP_CANCEL_JOB or IPP_PURGE_JOBS request, which requires the following * attributes: * * attributes-charset * attributes-natural-language * job-uri or printer-uri + job-id * requesting-user-name * [purge-job] or [purge-jobs] */ request = ippNewRequest(job_id < 0 ? IPP_OP_PURGE_JOBS : IPP_OP_CANCEL_JOB); if (name) { httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", ippPort(), "/printers/%s", name); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id); } else if (job_id > 0) { snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", job_id); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri); } ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); if (purge && job_id >= 0) ippAddBoolean(request, IPP_TAG_OPERATION, "purge-job", 1); else if (!purge && job_id < 0) ippAddBoolean(request, IPP_TAG_OPERATION, "purge-jobs", 0); /* * Do the request... */ ippDelete(cupsDoRequest(http, request, "/jobs/")); return (cupsLastError()); } /* * 'cupsCreateJob()' - Create an empty job for streaming. * * Use this function when you want to stream print data using the * @link cupsStartDocument@, @link cupsWriteRequestData@, and * @link cupsFinishDocument@ functions. If you have one or more files to * print, use the @link cupsPrintFile2@ or @link cupsPrintFiles2@ function * instead. * * @since CUPS 1.4/macOS 10.6@ @exclude all@ */ int /* O - Job ID or 0 on error */ cupsCreateJob( http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *name, /* I - Destination name */ const char *title, /* I - Title of job */ int num_options, /* I - Number of options */ cups_option_t *options) /* I - Options */ { int job_id = 0; /* job-id value */ ipp_status_t status; /* Create-Job status */ _cups_createdata_t data; /* Enumeration data */ cups_dinfo_t *info; /* Destination information */ DEBUG_printf(("cupsCreateJob(http=%p, name=\"%s\", title=\"%s\", num_options=%d, options=%p)", (void *)http, name, title, num_options, (void *)options)); /* * Range check input... */ if (!name) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (0); } /* * Lookup the destination... */ data.name = name; data.dest = NULL; cupsEnumDests(0, 1000, NULL, 0, 0, (cups_dest_cb_t)cups_create_cb, &data); if (!data.dest) { DEBUG_puts("1cupsCreateJob: Destination not found."); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0); return (0); } /* * Query dest information and create the job... */ DEBUG_puts("1cupsCreateJob: Querying destination info."); if ((info = cupsCopyDestInfo(http, data.dest)) == NULL) { DEBUG_puts("1cupsCreateJob: Query failed."); cupsFreeDests(1, data.dest); return (0); } status = cupsCreateDestJob(http, data.dest, info, &job_id, title, num_options, options); DEBUG_printf(("1cupsCreateJob: cupsCreateDestJob returned %04x (%s)", status, ippErrorString(status))); cupsFreeDestInfo(info); cupsFreeDests(1, data.dest); /* * Return the job... */ if (status >= IPP_STATUS_REDIRECTION_OTHER_SITE) return (0); else return (job_id); } /* * 'cupsFinishDocument()' - Finish sending a document. * * The document must have been started using @link cupsStartDocument@. * * @since CUPS 1.4/macOS 10.6@ @exclude all@ */ ipp_status_t /* O - Status of document submission */ cupsFinishDocument(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *name) /* I - Destination name */ { char resource[1024]; /* Printer resource */ snprintf(resource, sizeof(resource), "/printers/%s", name); ippDelete(cupsGetResponse(http, resource)); return (cupsLastError()); } /* * 'cupsFreeJobs()' - Free memory used by job data. */ void cupsFreeJobs(int num_jobs, /* I - Number of jobs */ cups_job_t *jobs) /* I - Jobs */ { int i; /* Looping var */ cups_job_t *job; /* Current job */ if (num_jobs <= 0 || !jobs) return; for (i = num_jobs, job = jobs; i > 0; i --, job ++) { _cupsStrFree(job->dest); _cupsStrFree(job->user); _cupsStrFree(job->format); _cupsStrFree(job->title); } free(jobs); } /* * 'cupsGetClasses()' - Get a list of printer classes from the default server. * * This function is deprecated and no longer returns a list of printer * classes - use @link cupsGetDests@ instead. * * @deprecated@ @exclude all@ */ int /* O - Number of classes */ cupsGetClasses(char ***classes) /* O - Classes */ { if (classes) *classes = NULL; return (0); } /* * 'cupsGetDefault()' - Get the default printer or class for the default server. * * This function returns the default printer or class as defined by * the LPDEST or PRINTER environment variables. If these environment * variables are not set, the server default destination is returned. * Applications should use the @link cupsGetDests@ and @link cupsGetDest@ * functions to get the user-defined default printer, as this function does * not support the lpoptions-defined default printer. * * @exclude all@ */ const char * /* O - Default printer or @code NULL@ */ cupsGetDefault(void) { /* * Return the default printer... */ return (cupsGetDefault2(CUPS_HTTP_DEFAULT)); } /* * 'cupsGetDefault2()' - Get the default printer or class for the specified server. * * This function returns the default printer or class as defined by * the LPDEST or PRINTER environment variables. If these environment * variables are not set, the server default destination is returned. * Applications should use the @link cupsGetDests@ and @link cupsGetDest@ * functions to get the user-defined default printer, as this function does * not support the lpoptions-defined default printer. * * @since CUPS 1.1.21/macOS 10.4@ @exclude all@ */ const char * /* O - Default printer or @code NULL@ */ cupsGetDefault2(http_t *http) /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ { ipp_t *request, /* IPP Request */ *response; /* IPP Response */ ipp_attribute_t *attr; /* Current attribute */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ /* * See if we have a user default printer set... */ if (_cupsUserDefault(cg->def_printer, sizeof(cg->def_printer))) return (cg->def_printer); /* * Connect to the server as needed... */ if (!http) if ((http = _cupsConnect()) == NULL) return (NULL); /* * Build a CUPS_GET_DEFAULT request, which requires the following * attributes: * * attributes-charset * attributes-natural-language */ request = ippNewRequest(IPP_OP_CUPS_GET_DEFAULT); /* * Do the request and get back a response... */ if ((response = cupsDoRequest(http, request, "/")) != NULL) { if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL) { strlcpy(cg->def_printer, attr->values[0].string.text, sizeof(cg->def_printer)); ippDelete(response); return (cg->def_printer); } ippDelete(response); } return (NULL); } /* * 'cupsGetJobs()' - Get the jobs from the default server. * * A "whichjobs" value of @code CUPS_WHICHJOBS_ALL@ returns all jobs regardless * of state, while @code CUPS_WHICHJOBS_ACTIVE@ returns jobs that are * pending, processing, or held and @code CUPS_WHICHJOBS_COMPLETED@ returns * jobs that are stopped, canceled, aborted, or completed. * * @exclude all@ */ int /* O - Number of jobs */ cupsGetJobs(cups_job_t **jobs, /* O - Job data */ const char *name, /* I - @code NULL@ = all destinations, otherwise show jobs for named destination */ int myjobs, /* I - 0 = all users, 1 = mine */ int whichjobs) /* I - @code CUPS_WHICHJOBS_ALL@, @code CUPS_WHICHJOBS_ACTIVE@, or @code CUPS_WHICHJOBS_COMPLETED@ */ { /* * Return the jobs... */ return (cupsGetJobs2(CUPS_HTTP_DEFAULT, jobs, name, myjobs, whichjobs)); } /* * 'cupsGetJobs2()' - Get the jobs from the specified server. * * A "whichjobs" value of @code CUPS_WHICHJOBS_ALL@ returns all jobs regardless * of state, while @code CUPS_WHICHJOBS_ACTIVE@ returns jobs that are * pending, processing, or held and @code CUPS_WHICHJOBS_COMPLETED@ returns * jobs that are stopped, canceled, aborted, or completed. * * @since CUPS 1.1.21/macOS 10.4@ */ int /* O - Number of jobs */ cupsGetJobs2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ cups_job_t **jobs, /* O - Job data */ const char *name, /* I - @code NULL@ = all destinations, otherwise show jobs for named destination */ int myjobs, /* I - 0 = all users, 1 = mine */ int whichjobs) /* I - @code CUPS_WHICHJOBS_ALL@, @code CUPS_WHICHJOBS_ACTIVE@, or @code CUPS_WHICHJOBS_COMPLETED@ */ { int n; /* Number of jobs */ ipp_t *request, /* IPP Request */ *response; /* IPP Response */ ipp_attribute_t *attr; /* Current attribute */ cups_job_t *temp; /* Temporary pointer */ int id, /* job-id */ priority, /* job-priority */ size; /* job-k-octets */ ipp_jstate_t state; /* job-state */ time_t completed_time, /* time-at-completed */ creation_time, /* time-at-creation */ processing_time; /* time-at-processing */ const char *dest, /* job-printer-uri */ *format, /* document-format */ *title, /* job-name */ *user; /* job-originating-user-name */ char uri[HTTP_MAX_URI]; /* URI for jobs */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ static const char * const attrs[] = /* Requested attributes */ { "document-format", "job-id", "job-k-octets", "job-name", "job-originating-user-name", "job-printer-uri", "job-priority", "job-state", "time-at-completed", "time-at-creation", "time-at-processing" }; /* * Range check input... */ if (!jobs) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (-1); } /* * Get the right URI... */ if (name) { if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", 0, "/printers/%s", name) < HTTP_URI_STATUS_OK) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create printer-uri"), 1); return (-1); } } else strlcpy(uri, "ipp://localhost/", sizeof(uri)); if (!http) if ((http = _cupsConnect()) == NULL) return (-1); /* * Build an IPP_GET_JOBS request, which requires the following * attributes: * * attributes-charset * attributes-natural-language * printer-uri * requesting-user-name * which-jobs * my-jobs * requested-attributes */ request = ippNewRequest(IPP_OP_GET_JOBS); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); if (myjobs) ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1); if (whichjobs == CUPS_WHICHJOBS_COMPLETED) ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs", NULL, "completed"); else if (whichjobs == CUPS_WHICHJOBS_ALL) ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs", NULL, "all"); ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", sizeof(attrs) / sizeof(attrs[0]), NULL, attrs); /* * Do the request and get back a response... */ n = 0; *jobs = NULL; if ((response = cupsDoRequest(http, request, "/")) != NULL) { for (attr = response->attrs; attr; attr = attr->next) { /* * Skip leading attributes until we hit a job... */ while (attr && attr->group_tag != IPP_TAG_JOB) attr = attr->next; if (!attr) break; /* * Pull the needed attributes from this job... */ id = 0; size = 0; priority = 50; state = IPP_JSTATE_PENDING; user = "unknown"; dest = NULL; format = "application/octet-stream"; title = "untitled"; creation_time = 0; completed_time = 0; processing_time = 0; while (attr && attr->group_tag == IPP_TAG_JOB) { if (!strcmp(attr->name, "job-id") && attr->value_tag == IPP_TAG_INTEGER) id = attr->values[0].integer; else if (!strcmp(attr->name, "job-state") && attr->value_tag == IPP_TAG_ENUM) state = (ipp_jstate_t)attr->values[0].integer; else if (!strcmp(attr->name, "job-priority") && attr->value_tag == IPP_TAG_INTEGER) priority = attr->values[0].integer; else if (!strcmp(attr->name, "job-k-octets") && attr->value_tag == IPP_TAG_INTEGER) size = attr->values[0].integer; else if (!strcmp(attr->name, "time-at-completed") && attr->value_tag == IPP_TAG_INTEGER) completed_time = attr->values[0].integer; else if (!strcmp(attr->name, "time-at-creation") && attr->value_tag == IPP_TAG_INTEGER) creation_time = attr->values[0].integer; else if (!strcmp(attr->name, "time-at-processing") && attr->value_tag == IPP_TAG_INTEGER) processing_time = attr->values[0].integer; else if (!strcmp(attr->name, "job-printer-uri") && attr->value_tag == IPP_TAG_URI) { if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL) dest ++; } else if (!strcmp(attr->name, "job-originating-user-name") && attr->value_tag == IPP_TAG_NAME) user = attr->values[0].string.text; else if (!strcmp(attr->name, "document-format") && attr->value_tag == IPP_TAG_MIMETYPE) format = attr->values[0].string.text; else if (!strcmp(attr->name, "job-name") && (attr->value_tag == IPP_TAG_TEXT || attr->value_tag == IPP_TAG_NAME)) title = attr->values[0].string.text; attr = attr->next; } /* * See if we have everything needed... */ if (!dest || !id) { if (!attr) break; else continue; } /* * Allocate memory for the job... */ if (n == 0) temp = malloc(sizeof(cups_job_t)); else temp = realloc(*jobs, sizeof(cups_job_t) * (size_t)(n + 1)); if (!temp) { /* * Ran out of memory! */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0); cupsFreeJobs(n, *jobs); *jobs = NULL; ippDelete(response); return (-1); } *jobs = temp; temp += n; n ++; /* * Copy the data over... */ temp->dest = _cupsStrAlloc(dest); temp->user = _cupsStrAlloc(user); temp->format = _cupsStrAlloc(format); temp->title = _cupsStrAlloc(title); temp->id = id; temp->priority = priority; temp->state = state; temp->size = size; temp->completed_time = completed_time; temp->creation_time = creation_time; temp->processing_time = processing_time; if (!attr) break; } ippDelete(response); } if (n == 0 && cg->last_error >= IPP_STATUS_ERROR_BAD_REQUEST) return (-1); else return (n); } /* * 'cupsGetPrinters()' - Get a list of printers from the default server. * * This function is deprecated and no longer returns a list of printers - use * @link cupsGetDests@ instead. * * @deprecated@ @exclude all@ */ int /* O - Number of printers */ cupsGetPrinters(char ***printers) /* O - Printers */ { if (printers) *printers = NULL; return (0); } /* * 'cupsPrintFile()' - Print a file to a printer or class on the default server. * * @exclude all@ */ int /* O - Job ID or 0 on error */ cupsPrintFile(const char *name, /* I - Destination name */ const char *filename, /* I - File to print */ const char *title, /* I - Title of job */ int num_options,/* I - Number of options */ cups_option_t *options) /* I - Options */ { DEBUG_printf(("cupsPrintFile(name=\"%s\", filename=\"%s\", title=\"%s\", num_options=%d, options=%p)", name, filename, title, num_options, (void *)options)); return (cupsPrintFiles2(CUPS_HTTP_DEFAULT, name, 1, &filename, title, num_options, options)); } /* * 'cupsPrintFile2()' - Print a file to a printer or class on the specified * server. * * @since CUPS 1.1.21/macOS 10.4@ @exclude all@ */ int /* O - Job ID or 0 on error */ cupsPrintFile2( http_t *http, /* I - Connection to server */ const char *name, /* I - Destination name */ const char *filename, /* I - File to print */ const char *title, /* I - Title of job */ int num_options, /* I - Number of options */ cups_option_t *options) /* I - Options */ { DEBUG_printf(("cupsPrintFile2(http=%p, name=\"%s\", filename=\"%s\", title=\"%s\", num_options=%d, options=%p)", (void *)http, name, filename, title, num_options, (void *)options)); return (cupsPrintFiles2(http, name, 1, &filename, title, num_options, options)); } /* * 'cupsPrintFiles()' - Print one or more files to a printer or class on the * default server. * * @exclude all@ */ int /* O - Job ID or 0 on error */ cupsPrintFiles( const char *name, /* I - Destination name */ int num_files, /* I - Number of files */ const char **files, /* I - File(s) to print */ const char *title, /* I - Title of job */ int num_options, /* I - Number of options */ cups_option_t *options) /* I - Options */ { DEBUG_printf(("cupsPrintFiles(name=\"%s\", num_files=%d, files=%p, title=\"%s\", num_options=%d, options=%p)", name, num_files, (void *)files, title, num_options, (void *)options)); /* * Print the file(s)... */ return (cupsPrintFiles2(CUPS_HTTP_DEFAULT, name, num_files, files, title, num_options, options)); } /* * 'cupsPrintFiles2()' - Print one or more files to a printer or class on the * specified server. * * @since CUPS 1.1.21/macOS 10.4@ @exclude all@ */ int /* O - Job ID or 0 on error */ cupsPrintFiles2( http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *name, /* I - Destination name */ int num_files, /* I - Number of files */ const char **files, /* I - File(s) to print */ const char *title, /* I - Title of job */ int num_options, /* I - Number of options */ cups_option_t *options) /* I - Options */ { int i; /* Looping var */ int job_id; /* New job ID */ const char *docname; /* Basename of current filename */ const char *format; /* Document format */ cups_file_t *fp; /* Current file */ char buffer[8192]; /* Copy buffer */ ssize_t bytes; /* Bytes in buffer */ http_status_t status; /* Status of write */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ ipp_status_t cancel_status; /* Status code to preserve */ char *cancel_message; /* Error message to preserve */ DEBUG_printf(("cupsPrintFiles2(http=%p, name=\"%s\", num_files=%d, files=%p, title=\"%s\", num_options=%d, options=%p)", (void *)http, name, num_files, (void *)files, title, num_options, (void *)options)); /* * Range check input... */ if (!name || num_files < 1 || !files) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (0); } /* * Create the print job... */ if ((job_id = cupsCreateJob(http, name, title, num_options, options)) == 0) return (0); /* * Send each of the files... */ if (cupsGetOption("raw", num_options, options)) format = CUPS_FORMAT_RAW; else if ((format = cupsGetOption("document-format", num_options, options)) == NULL) format = CUPS_FORMAT_AUTO; for (i = 0; i < num_files; i ++) { /* * Start the next file... */ if ((docname = strrchr(files[i], '/')) != NULL) docname ++; else docname = files[i]; if ((fp = cupsFileOpen(files[i], "rb")) == NULL) { /* * Unable to open print file, cancel the job and return... */ _cupsSetError(IPP_STATUS_ERROR_DOCUMENT_ACCESS, NULL, 0); goto cancel_job; } status = cupsStartDocument(http, name, job_id, docname, format, i == (num_files - 1)); while (status == HTTP_STATUS_CONTINUE && (bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0) status = cupsWriteRequestData(http, buffer, (size_t)bytes); cupsFileClose(fp); if (status != HTTP_STATUS_CONTINUE || cupsFinishDocument(http, name) != IPP_STATUS_OK) { /* * Unable to queue, cancel the job and return... */ goto cancel_job; } } return (job_id); /* * If we get here, something happened while sending the print job so we need * to cancel the job without setting the last error (since we need to preserve * the current error... */ cancel_job: cancel_status = cg->last_error; cancel_message = cg->last_status_message ? _cupsStrRetain(cg->last_status_message) : NULL; cupsCancelJob2(http, name, job_id, 0); cg->last_error = cancel_status; cg->last_status_message = cancel_message; return (0); } /* * 'cupsStartDocument()' - Add a document to a job created with cupsCreateJob(). * * Use @link cupsWriteRequestData@ to write data for the document and * @link cupsFinishDocument@ to finish the document and get the submission status. * * The MIME type constants @code CUPS_FORMAT_AUTO@, @code CUPS_FORMAT_PDF@, * @code CUPS_FORMAT_POSTSCRIPT@, @code CUPS_FORMAT_RAW@, and * @code CUPS_FORMAT_TEXT@ are provided for the "format" argument, although * any supported MIME type string can be supplied. * * @since CUPS 1.4/macOS 10.6@ @exclude all@ */ http_status_t /* O - HTTP status of request */ cupsStartDocument( http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *name, /* I - Destination name */ int job_id, /* I - Job ID from @link cupsCreateJob@ */ const char *docname, /* I - Name of document */ const char *format, /* I - MIME type or @code CUPS_FORMAT_foo@ */ int last_document) /* I - 1 for last document in job, 0 otherwise */ { char resource[1024], /* Resource for destinatio */ printer_uri[1024]; /* Printer URI */ ipp_t *request; /* Send-Document request */ http_status_t status; /* HTTP status */ /* * Create a Send-Document request... */ if ((request = ippNewRequest(IPP_OP_SEND_DOCUMENT)) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0); return (HTTP_STATUS_ERROR); } httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), "ipp", NULL, "localhost", ippPort(), "/printers/%s", name); snprintf(resource, sizeof(resource), "/printers/%s", name); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer_uri); ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); if (docname) ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name", NULL, docname); if (format) ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, format); ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", (char)last_document); /* * Send and delete the request, then return the status... */ status = cupsSendRequest(http, request, resource, CUPS_LENGTH_VARIABLE); ippDelete(request); return (status); } /* * 'cups_create_cb()' - Find the destination for printing. */ static int /* O - 0 on match */ cups_create_cb( _cups_createdata_t *data, /* I - Data from cupsCreateJob call */ unsigned flags, /* I - Enumeration flags */ cups_dest_t *dest) /* I - Destination */ { DEBUG_printf(("2cups_create_cb(data=%p(%s), flags=%08x, dest=%p(%s))", (void *)data, data->name, flags, (void *)dest, dest->name)); (void)flags; if (dest->instance || strcasecmp(data->name, dest->name)) return (1); cupsCopyDest(dest, 0, &data->dest); return (0); } ippsample/cups/versioning.h0000644000175000017500000001655313240604116015057 0ustar tilltill/* * API versioning definitions for CUPS. * * Copyright 2007-2017 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_VERSIONING_H_ # define _CUPS_VERSIONING_H_ /* * This header defines several constants - _CUPS_DEPRECATED, * _CUPS_DEPRECATED_MSG, _CUPS_INTERNAL_MSG, _CUPS_API_major_minor, and * _CUPS_API_major_minor_patch - which add compiler-specific attributes that * flag functions that are deprecated, added in particular releases, or internal * to CUPS. * * On macOS, the _CUPS_API_* constants are defined based on the values of * the MAC_OS_X_VERSION_MIN_ALLOWED and MAC_OS_X_VERSION_MAX_ALLOWED constants * provided by the compiler. */ # if defined(__APPLE__) && !defined(_CUPS_SOURCE) && !TARGET_OS_IOS # include # ifndef AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER # define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER __attribute__((unavailable)) # endif /* !AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER */ # ifndef AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER # define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER __attribute__((unavailable)) # endif /* !AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER */ # ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER # define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER __attribute__((unavailable)) # endif /* !AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER */ # ifndef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER # define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER __attribute__((unavailable)) # endif /* !AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER */ # ifndef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER # define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER __attribute__((unavailable)) # endif /* !AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER */ # ifndef AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER # define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER __attribute__((unavailable)) # endif /* !AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER */ # ifndef AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER # define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER __attribute__((unavailable)) # endif /* !AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER */ # ifndef AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER # define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER __attribute__((unavailable)) # endif /* !AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER */ # ifndef AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER # define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER __attribute__((unavailable)) # endif /* !AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER */ # ifndef AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER # define AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER __attribute__((unavailable)) # endif /* !AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER */ # define _CUPS_API_1_1_19 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER # define _CUPS_API_1_1_20 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER # define _CUPS_API_1_1_21 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER # define _CUPS_API_1_2 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER # define _CUPS_API_1_3 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER # define _CUPS_API_1_4 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER # define _CUPS_API_1_5 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER # define _CUPS_API_1_6 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER # define _CUPS_API_1_7 AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER # define _CUPS_API_2_0 AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER # define _CUPS_API_2_2 AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER # define _CUPS_API_2_2_4 AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER # define _CUPS_API_2_3 # else # define _CUPS_API_1_1_19 # define _CUPS_API_1_1_20 # define _CUPS_API_1_1_21 # define _CUPS_API_1_2 # define _CUPS_API_1_3 # define _CUPS_API_1_4 # define _CUPS_API_1_5 # define _CUPS_API_1_6 # define _CUPS_API_1_7 # define _CUPS_API_2_0 # define _CUPS_API_2_2 # define _CUPS_API_2_2_4 # define _CUPS_API_2_3 # endif /* __APPLE__ && !_CUPS_SOURCE */ /* * With GCC and Clang we can mark old APIs as "deprecated" or "unavailable" with * messages so you get warnings/errors are compile-time... */ # ifdef __has_extension /* Clang */ # define _CUPS_HAS_DEPRECATED # if __has_extension(attribute_deprecated_with_message) # define _CUPS_HAS_DEPRECATED_WITH_MESSAGE # endif # if __has_extension(attribute_unavailable_with_message) # define _CUPS_HAS_UNAVAILABLE_WITH_MESSAGE # endif # elif defined(__GNUC__) /* GCC and compatible */ # if __GNUC__ >= 3 /* GCC 3.0 or higher */ # define _CUPS_HAS_DEPRECATED # endif /* __GNUC__ >= 3 */ # if __GNUC__ >= 5 /* GCC 5.x */ # define _CUPS_HAS_DEPRECATED_WITH_MESSAGE # elif __GNUC__ == 4 && __GNUC_MINOR__ >= 5 /* GCC 4.5 or higher */ # define _CUPS_HAS_DEPRECATED_WITH_MESSAGE # endif /* __GNUC__ >= 5 */ # endif /* __has_extension */ # if !defined(_CUPS_HAS_DEPRECATED) || (defined(_CUPS_SOURCE) && !defined(_CUPS_NO_DEPRECATED)) /* * Don't mark functions deprecated if the compiler doesn't support it * or we are building CUPS source that doesn't care. */ # define _CUPS_DEPRECATED # define _CUPS_DEPRECATED_MSG(m) # define _CUPS_DEPRECATED_1_6_MSG(m) # define _CUPS_DEPRECATED_1_7_MSG(m) # define _CUPS_INTERNAL_MSG(m) # elif defined(_CUPS_HAS_UNAVAILABLE_WITH_MESSAGE) && defined(_CUPS_NO_DEPRECATED) /* * Compiler supports the unavailable attribute, so use it when the code * wants to exclude the use of deprecated API. */ # define _CUPS_DEPRECATED __attribute__ ((unavailable)) # define _CUPS_DEPRECATED_MSG(m) __attribute__ ((unavailable(m))) # define _CUPS_DEPRECATED_1_6_MSG(m) __attribute__ ((unavailable(m))) # define _CUPS_DEPRECATED_1_7_MSG(m) __attribute__ ((unavailable(m))) # define _CUPS_INTERNAL_MSG(m) __attribute__ ((unavailable(m))) # else /* * Compiler supports the deprecated attribute, so use it. */ # define _CUPS_DEPRECATED __attribute__ ((deprecated)) # ifdef _CUPS_HAS_DEPRECATED_WITH_MESSAGE # define _CUPS_DEPRECATED_MSG(m) __attribute__ ((deprecated(m))) # else # define _CUPS_DEPRECATED_MSG(m) __attribute__ ((deprecated)) # endif /* _CUPS_HAS_DEPRECATED_WITH_MESSAGE */ # if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8 # define _CUPS_DEPRECATED_1_6_MSG(m) _CUPS_DEPRECATED_MSG(m) # else # define _CUPS_DEPRECATED_1_6_MSG(m) # endif /* MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_8 */ # if defined(MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9 # define _CUPS_DEPRECATED_1_7_MSG(m) _CUPS_DEPRECATED_MSG(m) # else # define _CUPS_DEPRECATED_1_7_MSG(m) # endif /* MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_9 */ # ifdef _CUPS_SOURCE # define _CUPS_INTERNAL_MSG(m) # elif defined(_CUPS_HAS_UNAVAILABLE_WITH_MESSAGE) # define _CUPS_INTERNAL_MSG(m) __attribute__ ((unavailable(m))) # elif defined(_CUPS_HAS_DEPRECATED_WITH_MESSAGE) # define _CUPS_INTERNAL_MSG(m) __attribute__ ((deprecated(m))) # else # define _CUPS_INTERNAL_MSG(m) __attribute__ ((deprecated)) # endif /* _CUPS_SOURCE */ # endif /* !_CUPS_HAS_DEPRECATED || (_CUPS_SOURCE && !_CUPS_NO_DEPRECATED) */ # ifndef __GNUC__ # define __attribute__(x) # endif /* !__GNUC__ */ #endif /* !_CUPS_VERSIONING_H_ */ ippsample/cups/testdest.c0000644000175000017500000005134213240604116014521 0ustar tilltill/* * CUPS destination API test program for CUPS. * * Copyright © 2012-2018 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include #include #include "cups.h" /* * Local functions... */ static int enum_cb(void *user_data, unsigned flags, cups_dest_t *dest); static void localize(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option, const char *value); static void print_file(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *filename, int num_options, cups_option_t *options); static void show_conflicts(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, int num_options, cups_option_t *options); static void show_default(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option); static void show_media(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, unsigned flags, const char *name); static void show_supported(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option, const char *value); static void usage(const char *arg) __attribute__((noreturn)); /* * 'main()' - Main entry. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ http_t *http; /* Connection to destination */ cups_dest_t *dest = NULL; /* Destination */ cups_dinfo_t *dinfo; /* Destination info */ unsigned dflags = CUPS_DEST_FLAGS_NONE; /* Destination flags */ if (argc < 2) return (0); if (!strcmp(argv[1], "--get")) { cups_dest_t *dests; /* Destinations */ int num_dests = cupsGetDests2(CUPS_HTTP_DEFAULT, &dests); /* Number of destinations */ for (i = 0; i < num_dests; i ++) enum_cb(NULL, 0, dests + i); cupsFreeDests(num_dests, dests); return (0); } else if (!strcmp(argv[1], "--enum")) { cups_ptype_t type = 0, /* Printer type filter */ mask = 0; /* Printer type mask */ for (i = 2; i < argc; i ++) { if (!strcmp(argv[i], "grayscale")) { type |= CUPS_PRINTER_BW; mask |= CUPS_PRINTER_BW; } else if (!strcmp(argv[i], "color")) { type |= CUPS_PRINTER_COLOR; mask |= CUPS_PRINTER_COLOR; } else if (!strcmp(argv[i], "duplex")) { type |= CUPS_PRINTER_DUPLEX; mask |= CUPS_PRINTER_DUPLEX; } else if (!strcmp(argv[i], "staple")) { type |= CUPS_PRINTER_STAPLE; mask |= CUPS_PRINTER_STAPLE; } else if (!strcmp(argv[i], "small")) { type |= CUPS_PRINTER_SMALL; mask |= CUPS_PRINTER_SMALL; } else if (!strcmp(argv[i], "medium")) { type |= CUPS_PRINTER_MEDIUM; mask |= CUPS_PRINTER_MEDIUM; } else if (!strcmp(argv[i], "large")) { type |= CUPS_PRINTER_LARGE; mask |= CUPS_PRINTER_LARGE; } else usage(argv[i]); } cupsEnumDests(CUPS_DEST_FLAGS_NONE, 5000, NULL, type, mask, enum_cb, NULL); return (0); } i = 1; if (!strcmp(argv[i], "--device")) { dflags = CUPS_DEST_FLAGS_DEVICE; i ++; } if (!strncmp(argv[i], "ipp://", 6) || !strncmp(argv[i], "ipps://", 7)) dest = cupsGetDestWithURI(NULL, argv[i]); else if (!strcmp(argv[i], "default")) { dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, NULL, NULL); if (dest && dest->instance) printf("default is \"%s/%s\".\n", dest->name, dest->instance); else if (dest) printf("default is \"%s\".\n", dest->name); else puts("no default destination."); } else dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, argv[i], NULL); if (!dest) { printf("testdest: Unable to get destination \"%s\": %s\n", argv[i], cupsLastErrorString()); return (1); } i ++; if ((http = cupsConnectDest(dest, dflags, 30000, NULL, NULL, 0, NULL, NULL)) == NULL) { printf("testdest: Unable to connect to destination \"%s\": %s\n", dest->name, cupsLastErrorString()); return (1); } if ((dinfo = cupsCopyDestInfo(http, dest)) == NULL) { printf("testdest: Unable to get information for destination \"%s\": %s\n", dest->name, cupsLastErrorString()); return (1); } if (i == argc || !strcmp(argv[i], "supported")) { i ++; if ((i + 1) < argc) show_supported(http, dest, dinfo, argv[i], argv[i + 1]); else if (argc > 2) show_supported(http, dest, dinfo, argv[i], NULL); else show_supported(http, dest, dinfo, NULL, NULL); } else if (!strcmp(argv[i], "conflicts") && (i + 1) < argc) { int num_options = 0;/* Number of options */ cups_option_t *options = NULL;/* Options */ for (i ++; i < argc; i ++) num_options = cupsParseOptions(argv[i], num_options, &options); show_conflicts(http, dest, dinfo, num_options, options); } else if (!strcmp(argv[i], "default") && (i + 1) < argc) { show_default(http, dest, dinfo, argv[i + 1]); } else if (!strcmp(argv[i], "localize")) { i ++; if ((i + 1) < argc) localize(http, dest, dinfo, argv[i], argv[i + 1]); else if (argc > 2) localize(http, dest, dinfo, argv[i], NULL); else localize(http, dest, dinfo, NULL, NULL); } else if (!strcmp(argv[i], "media")) { const char *name = NULL; /* Media name, if any */ unsigned flags = CUPS_MEDIA_FLAGS_DEFAULT; /* Media selection flags */ for (i ++; i < argc; i ++) { if (!strcmp(argv[i], "borderless")) flags = CUPS_MEDIA_FLAGS_BORDERLESS; else if (!strcmp(argv[i], "duplex")) flags = CUPS_MEDIA_FLAGS_DUPLEX; else if (!strcmp(argv[i], "exact")) flags = CUPS_MEDIA_FLAGS_EXACT; else if (!strcmp(argv[i], "ready")) flags = CUPS_MEDIA_FLAGS_READY; else if (name) usage(argv[i]); else name = argv[i]; } show_media(http, dest, dinfo, flags, name); } else if (!strcmp(argv[i], "print") && (i + 1) < argc) { int num_options = 0;/* Number of options */ cups_option_t *options = NULL;/* Options */ const char *filename = argv[i + 1]; for (i += 2; i < argc; i ++) num_options = cupsParseOptions(argv[i], num_options, &options); print_file(http, dest, dinfo, filename, num_options, options); } else usage(argv[i]); return (0); } /* * 'enum_cb()' - Print the results from the enumeration of destinations. */ static int /* O - 1 to continue */ enum_cb(void *user_data, /* I - User data (unused) */ unsigned flags, /* I - Flags */ cups_dest_t *dest) /* I - Destination */ { int i; /* Looping var */ (void)user_data; (void)flags; if (dest->instance) printf("%s%s/%s%s:\n", (flags & CUPS_DEST_FLAGS_REMOVED) ? "REMOVE " : "", dest->name, dest->instance, dest->is_default ? " (Default)" : ""); else printf("%s%s%s:\n", (flags & CUPS_DEST_FLAGS_REMOVED) ? "REMOVE " : "", dest->name, dest->is_default ? " (Default)" : ""); for (i = 0; i < dest->num_options; i ++) printf(" %s=\"%s\"\n", dest->options[i].name, dest->options[i].value); puts(""); return (1); } /* * 'localize()' - Localize an option and value. */ static void localize(http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ const char *option, /* I - Option */ const char *value) /* I - Value, if any */ { ipp_attribute_t *attr; /* Attribute */ int i, /* Looping var */ count; /* Number of values */ if (!option) { attr = cupsFindDestSupported(http, dest, dinfo, "job-creation-attributes"); if (attr) { count = ippGetCount(attr); for (i = 0; i < count; i ++) localize(http, dest, dinfo, ippGetString(attr, i, NULL), NULL); } else { static const char * const options[] = { /* List of standard options */ CUPS_COPIES, CUPS_FINISHINGS, CUPS_MEDIA, CUPS_NUMBER_UP, CUPS_ORIENTATION, CUPS_PRINT_COLOR_MODE, CUPS_PRINT_QUALITY, CUPS_SIDES }; puts("No job-creation-attributes-supported attribute, probing instead."); for (i = 0; i < (int)(sizeof(options) / sizeof(options[0])); i ++) if (cupsCheckDestSupported(http, dest, dinfo, options[i], NULL)) localize(http, dest, dinfo, options[i], NULL); } } else if (!value) { printf("%s (%s)\n", option, cupsLocalizeDestOption(http, dest, dinfo, option)); if ((attr = cupsFindDestSupported(http, dest, dinfo, option)) != NULL) { count = ippGetCount(attr); switch (ippGetValueTag(attr)) { case IPP_TAG_INTEGER : for (i = 0; i < count; i ++) printf(" %d\n", ippGetInteger(attr, i)); break; case IPP_TAG_ENUM : for (i = 0; i < count; i ++) printf(" %s\n", ippEnumString(option, ippGetInteger(attr, i))); break; case IPP_TAG_RANGE : for (i = 0; i < count; i ++) { int upper, lower = ippGetRange(attr, i, &upper); printf(" %d-%d\n", lower, upper); } break; case IPP_TAG_RESOLUTION : for (i = 0; i < count; i ++) { int xres, yres; ipp_res_t units; xres = ippGetResolution(attr, i, &yres, &units); if (xres == yres) printf(" %d%s\n", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); else printf(" %dx%d%s\n", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); } break; case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : for (i = 0; i < count; i ++) printf(" %s (%s)\n", ippGetString(attr, i, NULL), cupsLocalizeDestValue(http, dest, dinfo, option, ippGetString(attr, i, NULL))); break; case IPP_TAG_STRING : for (i = 0; i < count; i ++) { int j, len; unsigned char *data = ippGetOctetString(attr, i, &len); fputs(" ", stdout); for (j = 0; j < len; j ++) { if (data[j] < ' ' || data[j] >= 0x7f) printf("<%02X>", data[j]); else putchar(data[j]); } putchar('\n'); } break; case IPP_TAG_BOOLEAN : break; default : printf(" %s\n", ippTagString(ippGetValueTag(attr))); break; } } } else puts(cupsLocalizeDestValue(http, dest, dinfo, option, value)); } /* * 'print_file()' - Print a file. */ static void print_file(http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ const char *filename, /* I - File to print */ int num_options, /* I - Number of options */ cups_option_t *options) /* I - Options */ { cups_file_t *fp; /* File to print */ int job_id; /* Job ID */ ipp_status_t status; /* Submission status */ const char *title; /* Title of job */ char buffer[32768]; /* File buffer */ ssize_t bytes; /* Bytes read/to write */ if ((fp = cupsFileOpen(filename, "r")) == NULL) { printf("Unable to open \"%s\": %s\n", filename, strerror(errno)); return; } if ((title = strrchr(filename, '/')) != NULL) title ++; else title = filename; if ((status = cupsCreateDestJob(http, dest, dinfo, &job_id, title, num_options, options)) > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED) { printf("Unable to create job: %s\n", cupsLastErrorString()); cupsFileClose(fp); return; } printf("Created job ID: %d\n", job_id); if (cupsStartDestDocument(http, dest, dinfo, job_id, title, CUPS_FORMAT_AUTO, 0, NULL, 1) != HTTP_STATUS_CONTINUE) { printf("Unable to send document: %s\n", cupsLastErrorString()); cupsFileClose(fp); return; } while ((bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0) { if (cupsWriteRequestData(http, buffer, (size_t)bytes) != HTTP_STATUS_CONTINUE) { printf("Unable to write document data: %s\n", cupsLastErrorString()); break; } } cupsFileClose(fp); if ((status = cupsFinishDestDocument(http, dest, dinfo)) > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED) { printf("Unable to send document: %s\n", cupsLastErrorString()); return; } puts("Job queued."); } /* * 'show_conflicts()' - Show conflicts for selected options. */ static void show_conflicts( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ int num_options, /* I - Number of options */ cups_option_t *options) /* I - Options */ { (void)http; (void)dest; (void)dinfo; (void)num_options; (void)options; } /* * 'show_default()' - Show default value for option. */ static void show_default(http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ const char *option) /* I - Option */ { if (!strcmp(option, "media")) { /* * Show default media option... */ cups_size_t size; /* Media size information */ if (cupsGetDestMediaDefault(http, dest, dinfo, CUPS_MEDIA_FLAGS_DEFAULT, &size)) printf("%s (%.2fx%.2fmm, margins=[%.2f %.2f %.2f %.2f])\n", size.media, size.width * 0.01, size.length * 0.01, size.left * 0.01, size.bottom * 0.01, size.right * 0.01, size.top * 0.01); else puts("FAILED"); } else { /* * Show default other option... */ ipp_attribute_t *defattr; /* Default attribute */ if ((defattr = cupsFindDestDefault(http, dest, dinfo, option)) != NULL) { char value[1024]; /* Value of default attribute */ ippAttributeString(defattr, value, sizeof(value)); puts(value); } else puts("FAILED"); } } /* * 'show_media()' - Show available media. */ static void show_media(http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ unsigned flags, /* I - Media flags */ const char *name) /* I - Size name */ { int i, /* Looping var */ count; /* Number of sizes */ cups_size_t size; /* Media size info */ if (name) { double dw, dl; /* Width and length from name */ char units[32]; /* Units */ int width, /* Width in 100ths of millimeters */ length; /* Length in 100ths of millimeters */ if (sscanf(name, "%lfx%lf%31s", &dw, &dl, units) == 3) { if (!strcmp(units, "in")) { width = (int)(dw * 2540.0); length = (int)(dl * 2540.0); } else if (!strcmp(units, "mm")) { width = (int)(dw * 100.0); length = (int)(dl * 100.0); } else { puts(" bad units in size"); return; } if (cupsGetDestMediaBySize(http, dest, dinfo, width, length, flags, &size)) { printf(" %s (%s) %dx%d B%d L%d R%d T%d\n", size.media, cupsLocalizeDestMedia(http, dest, dinfo, flags, &size), size.width, size.length, size.bottom, size.left, size.right, size.top); } else { puts(" not supported"); } } else if (cupsGetDestMediaByName(http, dest, dinfo, name, flags, &size)) { printf(" %s (%s) %dx%d B%d L%d R%d T%d\n", size.media, cupsLocalizeDestMedia(http, dest, dinfo, flags, &size), size.width, size.length, size.bottom, size.left, size.right, size.top); } else { puts(" not supported"); } } else { count = cupsGetDestMediaCount(http, dest, dinfo, flags); printf("%d size%s:\n", count, count == 1 ? "" : "s"); for (i = 0; i < count; i ++) { if (cupsGetDestMediaByIndex(http, dest, dinfo, i, flags, &size)) printf(" %s (%s) %dx%d B%d L%d R%d T%d\n", size.media, cupsLocalizeDestMedia(http, dest, dinfo, flags, &size), size.width, size.length, size.bottom, size.left, size.right, size.top); else puts(" error"); } } } /* * 'show_supported()' - Show supported options, values, etc. */ static void show_supported(http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ const char *option, /* I - Option, if any */ const char *value) /* I - Value, if any */ { ipp_attribute_t *attr; /* Attribute */ int i, /* Looping var */ count; /* Number of values */ if (!option) { attr = cupsFindDestSupported(http, dest, dinfo, "job-creation-attributes"); if (attr) { count = ippGetCount(attr); for (i = 0; i < count; i ++) show_supported(http, dest, dinfo, ippGetString(attr, i, NULL), NULL); } else { static const char * const options[] = { /* List of standard options */ CUPS_COPIES, CUPS_FINISHINGS, CUPS_MEDIA, CUPS_NUMBER_UP, CUPS_ORIENTATION, CUPS_PRINT_COLOR_MODE, CUPS_PRINT_QUALITY, CUPS_SIDES }; puts("No job-creation-attributes-supported attribute, probing instead."); for (i = 0; i < (int)(sizeof(options) / sizeof(options[0])); i ++) if (cupsCheckDestSupported(http, dest, dinfo, options[i], NULL)) show_supported(http, dest, dinfo, options[i], NULL); } } else if (!value) { printf("%s (%s - %s)\n", option, cupsLocalizeDestOption(http, dest, dinfo, option), cupsCheckDestSupported(http, dest, dinfo, option, NULL) ? "supported" : "not-supported"); if ((attr = cupsFindDestSupported(http, dest, dinfo, option)) != NULL) { count = ippGetCount(attr); switch (ippGetValueTag(attr)) { case IPP_TAG_INTEGER : for (i = 0; i < count; i ++) printf(" %d\n", ippGetInteger(attr, i)); break; case IPP_TAG_ENUM : for (i = 0; i < count; i ++) { int val = ippGetInteger(attr, i); char valstr[256]; snprintf(valstr, sizeof(valstr), "%d", val); printf(" %s (%s)\n", ippEnumString(option, ippGetInteger(attr, i)), cupsLocalizeDestValue(http, dest, dinfo, option, valstr)); } break; case IPP_TAG_RANGE : for (i = 0; i < count; i ++) { int upper, lower = ippGetRange(attr, i, &upper); printf(" %d-%d\n", lower, upper); } break; case IPP_TAG_RESOLUTION : for (i = 0; i < count; i ++) { int xres, yres; ipp_res_t units; xres = ippGetResolution(attr, i, &yres, &units); if (xres == yres) printf(" %d%s\n", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); else printf(" %dx%d%s\n", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); } break; case IPP_TAG_KEYWORD : for (i = 0; i < count; i ++) printf(" %s (%s)\n", ippGetString(attr, i, NULL), cupsLocalizeDestValue(http, dest, dinfo, option, ippGetString(attr, i, NULL))); break; case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : for (i = 0; i < count; i ++) printf(" %s\n", ippGetString(attr, i, NULL)); break; case IPP_TAG_STRING : for (i = 0; i < count; i ++) { int j, len; unsigned char *data = ippGetOctetString(attr, i, &len); fputs(" ", stdout); for (j = 0; j < len; j ++) { if (data[j] < ' ' || data[j] >= 0x7f) printf("<%02X>", data[j]); else putchar(data[j]); } putchar('\n'); } break; case IPP_TAG_BOOLEAN : break; default : printf(" %s\n", ippTagString(ippGetValueTag(attr))); break; } } } else if (cupsCheckDestSupported(http, dest, dinfo, option, value)) puts("YES"); else puts("NO"); } /* * 'usage()' - Show program usage. */ static void usage(const char *arg) /* I - Argument for usage message */ { if (arg) printf("testdest: Unknown option \"%s\".\n", arg); puts("Usage:"); puts(" ./testdest [--device] name [operation ...]"); puts(" ./testdest [--device] ipp://... [operation ...]"); puts(" ./testdest [--device] ipps://... [operation ...]"); puts(" ./testdest --get"); puts(" ./testdest --enum [grayscale] [color] [duplex] [staple] [small]\n" " [medium] [large]"); puts(""); puts("Operations:"); puts(" conflicts options"); puts(" default option"); puts(" localize option [value]"); puts(" media [borderless] [duplex] [exact] [ready] [name or size]"); puts(" print filename [options]"); puts(" supported [option [value]]"); exit(arg != NULL); } ippsample/cups/dir.c0000644000175000017500000001636113240604116013442 0ustar tilltill/* * Directory routines for CUPS. * * This set of APIs abstracts enumeration of directory entries. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2005 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "string-private.h" #include "debug-private.h" #include "dir.h" /* * Windows implementation... */ #ifdef WIN32 # include /* * Types and structures... */ struct _cups_dir_s /**** Directory data structure ****/ { char directory[1024]; /* Directory filename */ HANDLE dir; /* Directory handle */ cups_dentry_t entry; /* Directory entry */ }; /* * '_cups_dir_time()' - Convert a FILETIME value to a UNIX time value. */ time_t /* O - UNIX time */ _cups_dir_time(FILETIME ft) /* I - File time */ { ULONGLONG val; /* File time in 0.1 usecs */ /* * Convert file time (1/10 microseconds since Jan 1, 1601) to UNIX * time (seconds since Jan 1, 1970). There are 11,644,732,800 seconds * between them... */ val = ft.dwLowDateTime + ((ULONGLONG)ft.dwHighDateTime << 32); return ((time_t)(val / 10000000 - 11644732800)); } /* * 'cupsDirClose()' - Close a directory. * * @since CUPS 1.2/macOS 10.5@ */ void cupsDirClose(cups_dir_t *dp) /* I - Directory pointer */ { /* * Range check input... */ if (!dp) return; /* * Close an open directory handle... */ if (dp->dir != INVALID_HANDLE_VALUE) FindClose(dp->dir); /* * Free memory used... */ free(dp); } /* * 'cupsDirOpen()' - Open a directory. * * @since CUPS 1.2/macOS 10.5@ */ cups_dir_t * /* O - Directory pointer or @code NULL@ if the directory could not be opened. */ cupsDirOpen(const char *directory) /* I - Directory name */ { cups_dir_t *dp; /* Directory */ /* * Range check input... */ if (!directory) return (NULL); /* * Allocate memory for the directory structure... */ dp = (cups_dir_t *)calloc(1, sizeof(cups_dir_t)); if (!dp) return (NULL); /* * Copy the directory name for later use... */ dp->dir = INVALID_HANDLE_VALUE; strlcpy(dp->directory, directory, sizeof(dp->directory)); /* * Return the new directory structure... */ return (dp); } /* * 'cupsDirRead()' - Read the next directory entry. * * @since CUPS 1.2/macOS 10.5@ */ cups_dentry_t * /* O - Directory entry or @code NULL@ if there are no more */ cupsDirRead(cups_dir_t *dp) /* I - Directory pointer */ { WIN32_FIND_DATA entry; /* Directory entry data */ /* * Range check input... */ if (!dp) return (NULL); /* * See if we have already started finding files... */ if (dp->dir == INVALID_HANDLE_VALUE) { /* * No, find the first file... */ dp->dir = FindFirstFile(dp->directory, &entry); if (dp->dir == INVALID_HANDLE_VALUE) return (NULL); } else if (!FindNextFile(dp->dir, &entry)) return (NULL); /* * Copy the name over and convert the file information... */ strlcpy(dp->entry.filename, entry.cFileName, sizeof(dp->entry.filename)); if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) dp->entry.fileinfo.st_mode = 0755 | S_IFDIR; else dp->entry.fileinfo.st_mode = 0644; dp->entry.fileinfo.st_atime = _cups_dir_time(entry.ftLastAccessTime); dp->entry.fileinfo.st_ctime = _cups_dir_time(entry.ftCreationTime); dp->entry.fileinfo.st_mtime = _cups_dir_time(entry.ftLastWriteTime); dp->entry.fileinfo.st_size = entry.nFileSizeLow + ((unsigned long long)entry.nFileSizeHigh << 32); /* * Return the entry... */ return (&(dp->entry)); } /* * 'cupsDirRewind()' - Rewind to the start of the directory. * * @since CUPS 1.2/macOS 10.5@ */ void cupsDirRewind(cups_dir_t *dp) /* I - Directory pointer */ { /* * Range check input... */ if (!dp) return; /* * Close an open directory handle... */ if (dp->dir != INVALID_HANDLE_VALUE) { FindClose(dp->dir); dp->dir = INVALID_HANDLE_VALUE; } } #else /* * POSIX implementation... */ # include # include /* * Types and structures... */ struct _cups_dir_s /**** Directory data structure ****/ { char directory[1024]; /* Directory filename */ DIR *dir; /* Directory file */ cups_dentry_t entry; /* Directory entry */ }; /* * 'cupsDirClose()' - Close a directory. * * @since CUPS 1.2/macOS 10.5@ */ void cupsDirClose(cups_dir_t *dp) /* I - Directory pointer */ { DEBUG_printf(("cupsDirClose(dp=%p)", (void *)dp)); /* * Range check input... */ if (!dp) return; /* * Close the directory and free memory... */ closedir(dp->dir); free(dp); } /* * 'cupsDirOpen()' - Open a directory. * * @since CUPS 1.2/macOS 10.5@ */ cups_dir_t * /* O - Directory pointer or @code NULL@ if the directory could not be opened. */ cupsDirOpen(const char *directory) /* I - Directory name */ { cups_dir_t *dp; /* Directory */ DEBUG_printf(("cupsDirOpen(directory=\"%s\")", directory)); /* * Range check input... */ if (!directory) return (NULL); /* * Allocate memory for the directory structure... */ dp = (cups_dir_t *)calloc(1, sizeof(cups_dir_t)); if (!dp) return (NULL); /* * Open the directory... */ dp->dir = opendir(directory); if (!dp->dir) { free(dp); return (NULL); } /* * Copy the directory name for later use... */ strlcpy(dp->directory, directory, sizeof(dp->directory)); /* * Return the new directory structure... */ return (dp); } /* * 'cupsDirRead()' - Read the next directory entry. * * @since CUPS 1.2/macOS 10.5@ */ cups_dentry_t * /* O - Directory entry or @code NULL@ when there are no more */ cupsDirRead(cups_dir_t *dp) /* I - Directory pointer */ { struct dirent *entry; /* Pointer to entry */ char filename[1024]; /* Full filename */ DEBUG_printf(("2cupsDirRead(dp=%p)", (void *)dp)); /* * Range check input... */ if (!dp) return (NULL); /* * Try reading an entry that is not "." or ".."... */ for (;;) { /* * Read the next entry... */ if ((entry = readdir(dp->dir)) == NULL) { DEBUG_puts("3cupsDirRead: readdir() returned a NULL pointer!"); return (NULL); } DEBUG_printf(("4cupsDirRead: readdir() returned \"%s\"...", entry->d_name)); /* * Skip "." and ".."... */ if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) continue; /* * Copy the name over and get the file information... */ strlcpy(dp->entry.filename, entry->d_name, sizeof(dp->entry.filename)); snprintf(filename, sizeof(filename), "%s/%s", dp->directory, entry->d_name); if (stat(filename, &(dp->entry.fileinfo))) { DEBUG_printf(("3cupsDirRead: stat() failed for \"%s\" - %s...", filename, strerror(errno))); continue; } /* * Return the entry... */ return (&(dp->entry)); } } /* * 'cupsDirRewind()' - Rewind to the start of the directory. * * @since CUPS 1.2/macOS 10.5@ */ void cupsDirRewind(cups_dir_t *dp) /* I - Directory pointer */ { DEBUG_printf(("cupsDirRewind(dp=%p)", (void *)dp)); /* * Range check input... */ if (!dp) return; /* * Rewind the directory... */ rewinddir(dp->dir); } #endif /* WIN32 */ ippsample/cups/md5.c0000644000175000017500000002374613240604116013356 0ustar tilltill/* * Private MD5 implementation for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 2005 by Easy Software Products * Copyright (C) 1999 Aladdin Enterprises. All rights reserved. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * L. Peter Deutsch * ghost@aladdin.com */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321. It is derived directly from the text of the RFC and not from the reference implementation. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #include "md5-private.h" #include "string-private.h" #if !defined(__APPLE__) && !defined(HAVE_GNUTLS) # define T1 0xd76aa478 # define T2 0xe8c7b756 # define T3 0x242070db # define T4 0xc1bdceee # define T5 0xf57c0faf # define T6 0x4787c62a # define T7 0xa8304613 # define T8 0xfd469501 # define T9 0x698098d8 # define T10 0x8b44f7af # define T11 0xffff5bb1 # define T12 0x895cd7be # define T13 0x6b901122 # define T14 0xfd987193 # define T15 0xa679438e # define T16 0x49b40821 # define T17 0xf61e2562 # define T18 0xc040b340 # define T19 0x265e5a51 # define T20 0xe9b6c7aa # define T21 0xd62f105d # define T22 0x02441453 # define T23 0xd8a1e681 # define T24 0xe7d3fbc8 # define T25 0x21e1cde6 # define T26 0xc33707d6 # define T27 0xf4d50d87 # define T28 0x455a14ed # define T29 0xa9e3e905 # define T30 0xfcefa3f8 # define T31 0x676f02d9 # define T32 0x8d2a4c8a # define T33 0xfffa3942 # define T34 0x8771f681 # define T35 0x6d9d6122 # define T36 0xfde5380c # define T37 0xa4beea44 # define T38 0x4bdecfa9 # define T39 0xf6bb4b60 # define T40 0xbebfbc70 # define T41 0x289b7ec6 # define T42 0xeaa127fa # define T43 0xd4ef3085 # define T44 0x04881d05 # define T45 0xd9d4d039 # define T46 0xe6db99e5 # define T47 0x1fa27cf8 # define T48 0xc4ac5665 # define T49 0xf4292244 # define T50 0x432aff97 # define T51 0xab9423a7 # define T52 0xfc93a039 # define T53 0x655b59c3 # define T54 0x8f0ccc92 # define T55 0xffeff47d # define T56 0x85845dd1 # define T57 0x6fa87e4f # define T58 0xfe2ce6e0 # define T59 0xa3014314 # define T60 0x4e0811a1 # define T61 0xf7537e82 # define T62 0xbd3af235 # define T63 0x2ad7d2bb # define T64 0xeb86d391 static void _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/) { unsigned int a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; unsigned int t; # ifndef ARCH_IS_BIG_ENDIAN # define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */ # endif # if ARCH_IS_BIG_ENDIAN /* * On big-endian machines, we must arrange the bytes in the right * order. (This also works on machines of unknown byte order.) */ unsigned int X[16]; const unsigned char *xp = data; int i; for (i = 0; i < 16; ++i, xp += 4) X[i] = (unsigned)xp[0] + ((unsigned)xp[1] << 8) + ((unsigned)xp[2] << 16) + ((unsigned)xp[3] << 24); # else /* !ARCH_IS_BIG_ENDIAN */ /* * On little-endian machines, we can process properly aligned data * without copying it. */ unsigned int xbuf[16]; const unsigned int *X; if (!((data - (const unsigned char *)0) & 3)) { /* data are properly aligned */ X = (const unsigned int *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } # endif # define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ # define F(x, y, z) (((x) & (y)) | (~(x) & (z))) # define SET(a, b, c, d, k, s, Ti)\ t = a + F(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); # undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ # define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) # define SET(a, b, c, d, k, s, Ti)\ t = a + G(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); # undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ # define H(x, y, z) ((x) ^ (y) ^ (z)) # define SET(a, b, c, d, k, s, Ti)\ t = a + H(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); # undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ # define I(x, y, z) ((y) ^ ((x) | ~(z))) # define SET(a, b, c, d, k, s, Ti)\ t = a + I(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); # undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } void _cupsMD5Init(_cups_md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = 0xefcdab89; pms->abcd[2] = 0x98badcfe; pms->abcd[3] = 0x10325476; } void _cupsMD5Append(_cups_md5_state_t *pms, const unsigned char *data, int nbytes) { const unsigned char *p = data; int left = nbytes; int offset = (pms->count[0] >> 3) & 63; unsigned int nbits = (unsigned int)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += (unsigned)nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, (size_t)copy); if (offset + copy < 64) return; p += copy; left -= copy; _cups_md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) _cups_md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, (size_t)left); } void _cupsMD5Finish(_cups_md5_state_t *pms, unsigned char digest[16]) { static const unsigned char pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; unsigned char data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (unsigned char)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ _cupsMD5Append(pms, pad, (int)((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ _cupsMD5Append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (unsigned char)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } #endif /* !__APPLE__ && !HAVE_GNUTLS */ ippsample/cups/http.c0000644000175000017500000034160413240604116013644 0ustar tilltill/* * HTTP routines for CUPS. * * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by * Jelmer Vernooij. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ /* * Include necessary headers... */ #include "cups-private.h" #include #include #ifdef WIN32 # include #else # include # include # include #endif /* WIN32 */ #ifdef HAVE_POLL # include #endif /* HAVE_POLL */ /* * Local functions... */ static void http_add_field(http_t *http, http_field_t field, const char *value, int append); #ifdef HAVE_LIBZ static void http_content_coding_finish(http_t *http); static void http_content_coding_start(http_t *http, const char *value); #endif /* HAVE_LIBZ */ static http_t *http_create(const char *host, int port, http_addrlist_t *addrlist, int family, http_encryption_t encryption, int blocking, _http_mode_t mode); #ifdef DEBUG static void http_debug_hex(const char *prefix, const char *buffer, int bytes); #endif /* DEBUG */ static ssize_t http_read(http_t *http, char *buffer, size_t length); static ssize_t http_read_buffered(http_t *http, char *buffer, size_t length); static ssize_t http_read_chunk(http_t *http, char *buffer, size_t length); static int http_send(http_t *http, http_state_t request, const char *uri); static ssize_t http_write(http_t *http, const char *buffer, size_t length); static ssize_t http_write_chunk(http_t *http, const char *buffer, size_t length); static off_t http_set_length(http_t *http); static void http_set_timeout(int fd, double timeout); static void http_set_wait(http_t *http); #ifdef HAVE_SSL static int http_tls_upgrade(http_t *http); #endif /* HAVE_SSL */ /* * Local globals... */ static const char * const http_fields[] = { "Accept-Language", "Accept-Ranges", "Authorization", "Connection", "Content-Encoding", "Content-Language", "Content-Length", "Content-Location", "Content-MD5", "Content-Range", "Content-Type", "Content-Version", "Date", "Host", "If-Modified-Since", "If-Unmodified-since", "Keep-Alive", "Last-Modified", "Link", "Location", "Range", "Referer", "Retry-After", "Transfer-Encoding", "Upgrade", "User-Agent", "WWW-Authenticate", "Accept-Encoding", "Allow", "Server" }; /* * 'httpAcceptConnection()' - Accept a new HTTP client connection from the * specified listening socket. * * @since CUPS 1.7/macOS 10.9@ */ http_t * /* O - HTTP connection or @code NULL@ */ httpAcceptConnection(int fd, /* I - Listen socket file descriptor */ int blocking) /* I - 1 if the connection should be blocking, 0 otherwise */ { http_t *http; /* HTTP connection */ http_addrlist_t addrlist; /* Dummy address list */ socklen_t addrlen; /* Length of address */ int val; /* Socket option value */ /* * Range check input... */ if (fd < 0) return (NULL); /* * Create the client connection... */ memset(&addrlist, 0, sizeof(addrlist)); if ((http = http_create(NULL, 0, &addrlist, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, blocking, _HTTP_MODE_SERVER)) == NULL) return (NULL); /* * Accept the client and get the remote address... */ addrlen = sizeof(http_addr_t); if ((http->fd = accept(fd, (struct sockaddr *)&(http->addrlist->addr), &addrlen)) < 0) { _cupsSetHTTPError(HTTP_STATUS_ERROR); httpClose(http); return (NULL); } http->hostaddr = &(http->addrlist->addr); if (httpAddrLocalhost(http->hostaddr)) strlcpy(http->hostname, "localhost", sizeof(http->hostname)); else httpAddrString(http->hostaddr, http->hostname, sizeof(http->hostname)); #ifdef SO_NOSIGPIPE /* * Disable SIGPIPE for this socket. */ val = 1; setsockopt(http->fd, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val)); #endif /* SO_NOSIGPIPE */ /* * Using TCP_NODELAY improves responsiveness, especially on systems * with a slow loopback interface. Since we write large buffers * when sending print files and requests, there shouldn't be any * performance penalty for this... */ val = 1; setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val)); #ifdef FD_CLOEXEC /* * Close this socket when starting another process... */ fcntl(http->fd, F_SETFD, FD_CLOEXEC); #endif /* FD_CLOEXEC */ return (http); } /* * 'httpAddCredential()' - Allocates and adds a single credential to an array. * * Use @code cupsArrayNew(NULL, NULL)@ to create a credentials array. * * @since CUPS 1.5/macOS 10.7@ */ int /* O - 0 on success, -1 on error */ httpAddCredential( cups_array_t *credentials, /* I - Credentials array */ const void *data, /* I - PEM-encoded X.509 data */ size_t datalen) /* I - Length of data */ { http_credential_t *credential; /* Credential data */ if ((credential = malloc(sizeof(http_credential_t))) != NULL) { credential->datalen = datalen; if ((credential->data = malloc(datalen)) != NULL) { memcpy(credential->data, data, datalen); cupsArrayAdd(credentials, credential); return (0); } free(credential); } return (-1); } /* * 'httpBlocking()' - Set blocking/non-blocking behavior on a connection. */ void httpBlocking(http_t *http, /* I - HTTP connection */ int b) /* I - 1 = blocking, 0 = non-blocking */ { if (http) { http->blocking = b; http_set_wait(http); } } /* * 'httpCheck()' - Check to see if there is a pending response from the server. */ int /* O - 0 = no data, 1 = data available */ httpCheck(http_t *http) /* I - HTTP connection */ { return (httpWait(http, 0)); } /* * 'httpClearCookie()' - Clear the cookie value(s). * * @since CUPS 1.1.19/macOS 10.3@ */ void httpClearCookie(http_t *http) /* I - HTTP connection */ { if (!http) return; if (http->cookie) { free(http->cookie); http->cookie = NULL; } } /* * 'httpClearFields()' - Clear HTTP request fields. */ void httpClearFields(http_t *http) /* I - HTTP connection */ { http_field_t field; /* Curent field */ DEBUG_printf(("httpClearFields(http=%p)", (void *)http)); if (http) { memset(http->_fields, 0, sizeof(http->fields)); for (field = HTTP_FIELD_ACCEPT_LANGUAGE; field < HTTP_FIELD_MAX; field ++) { if (http->fields[field] && http->fields[field] != http->_fields[field]) free(http->fields[field]); http->fields[field] = NULL; } if (http->mode == _HTTP_MODE_CLIENT) { if (http->hostname[0] == '/') httpSetField(http, HTTP_FIELD_HOST, "localhost"); else httpSetField(http, HTTP_FIELD_HOST, http->hostname); } http->expect = (http_status_t)0; } } /* * 'httpClose()' - Close an HTTP connection. */ void httpClose(http_t *http) /* I - HTTP connection */ { #ifdef HAVE_GSSAPI OM_uint32 minor_status; /* Minor status code */ #endif /* HAVE_GSSAPI */ DEBUG_printf(("httpClose(http=%p)", (void *)http)); /* * Range check input... */ if (!http) return; /* * Close any open connection... */ _httpDisconnect(http); /* * Free memory used... */ httpAddrFreeList(http->addrlist); if (http->cookie) free(http->cookie); #ifdef HAVE_GSSAPI if (http->gssctx != GSS_C_NO_CONTEXT) gss_delete_sec_context(&minor_status, &http->gssctx, GSS_C_NO_BUFFER); if (http->gssname != GSS_C_NO_NAME) gss_release_name(&minor_status, &http->gssname); #endif /* HAVE_GSSAPI */ #ifdef HAVE_AUTHORIZATION_H if (http->auth_ref) AuthorizationFree(http->auth_ref, kAuthorizationFlagDefaults); #endif /* HAVE_AUTHORIZATION_H */ httpClearFields(http); if (http->authstring && http->authstring != http->_authstring) free(http->authstring); free(http); } /* * 'httpCompareCredentials()' - Compare two sets of X.509 credentials. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 1 if they match, 0 if they do not */ httpCompareCredentials( cups_array_t *cred1, /* I - First set of X.509 credentials */ cups_array_t *cred2) /* I - Second set of X.509 credentials */ { http_credential_t *temp1, *temp2; /* Temporary credentials */ for (temp1 = (http_credential_t *)cupsArrayFirst(cred1), temp2 = (http_credential_t *)cupsArrayFirst(cred2); temp1 && temp2; temp1 = (http_credential_t *)cupsArrayNext(cred1), temp2 = (http_credential_t *)cupsArrayNext(cred2)) if (temp1->datalen != temp2->datalen) return (0); else if (memcmp(temp1->data, temp2->data, temp1->datalen)) return (0); return (temp1 == temp2); } /* * 'httpConnect()' - Connect to a HTTP server. * * This function is deprecated - use @link httpConnect2@ instead. * * @deprecated@ @exclude all@ */ http_t * /* O - New HTTP connection */ httpConnect(const char *host, /* I - Host to connect to */ int port) /* I - Port number */ { return (httpConnect2(host, port, NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL)); } /* * 'httpConnect2()' - Connect to a HTTP server. * * @since CUPS 1.7/macOS 10.9@ */ http_t * /* O - New HTTP connection */ httpConnect2( const char *host, /* I - Host to connect to */ int port, /* I - Port number */ http_addrlist_t *addrlist, /* I - List of addresses or @code NULL@ to lookup */ int family, /* I - Address family to use or @code AF_UNSPEC@ for any */ http_encryption_t encryption, /* I - Type of encryption to use */ int blocking, /* I - 1 for blocking connection, 0 for non-blocking */ int msec, /* I - Connection timeout in milliseconds, 0 means don't connect */ int *cancel) /* I - Pointer to "cancel" variable */ { http_t *http; /* New HTTP connection */ DEBUG_printf(("httpConnect2(host=\"%s\", port=%d, addrlist=%p, family=%d, encryption=%d, blocking=%d, msec=%d, cancel=%p)", host, port, (void *)addrlist, family, encryption, blocking, msec, (void *)cancel)); /* * Create the HTTP structure... */ if ((http = http_create(host, port, addrlist, family, encryption, blocking, _HTTP_MODE_CLIENT)) == NULL) return (NULL); /* * Optionally connect to the remote system... */ if (msec == 0 || !httpReconnect2(http, msec, cancel)) return (http); /* * Could not connect to any known address - bail out! */ httpClose(http); return (NULL); } /* * 'httpConnectEncrypt()' - Connect to a HTTP server using encryption. * * This function is now deprecated. Please use the @link httpConnect2@ function * instead. * * @deprecated@ @exclude all@ */ http_t * /* O - New HTTP connection */ httpConnectEncrypt( const char *host, /* I - Host to connect to */ int port, /* I - Port number */ http_encryption_t encryption) /* I - Type of encryption to use */ { DEBUG_printf(("httpConnectEncrypt(host=\"%s\", port=%d, encryption=%d)", host, port, encryption)); return (httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)); } /* * 'httpDelete()' - Send a DELETE request to the server. */ int /* O - Status of call (0 = success) */ httpDelete(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI to delete */ { return (http_send(http, HTTP_STATE_DELETE, uri)); } /* * '_httpDisconnect()' - Disconnect a HTTP connection. */ void _httpDisconnect(http_t *http) /* I - HTTP connection */ { #ifdef HAVE_SSL if (http->tls) _httpTLSStop(http); #endif /* HAVE_SSL */ httpAddrClose(NULL, http->fd); http->fd = -1; } /* * 'httpEncryption()' - Set the required encryption on the link. */ int /* O - -1 on error, 0 on success */ httpEncryption(http_t *http, /* I - HTTP connection */ http_encryption_t e) /* I - New encryption preference */ { DEBUG_printf(("httpEncryption(http=%p, e=%d)", (void *)http, e)); #ifdef HAVE_SSL if (!http) return (0); if (http->mode == _HTTP_MODE_CLIENT) { http->encryption = e; if ((http->encryption == HTTP_ENCRYPTION_ALWAYS && !http->tls) || (http->encryption == HTTP_ENCRYPTION_NEVER && http->tls)) return (httpReconnect2(http, 30000, NULL)); else if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls) return (http_tls_upgrade(http)); else return (0); } else { if (e == HTTP_ENCRYPTION_NEVER && http->tls) return (-1); http->encryption = e; if (e != HTTP_ENCRYPTION_IF_REQUESTED && !http->tls) return (_httpTLSStart(http)); else return (0); } #else if (e == HTTP_ENCRYPTION_ALWAYS || e == HTTP_ENCRYPTION_REQUIRED) return (-1); else return (0); #endif /* HAVE_SSL */ } /* * 'httpError()' - Get the last error on a connection. */ int /* O - Error code (errno) value */ httpError(http_t *http) /* I - HTTP connection */ { if (http) return (http->error); else return (EINVAL); } /* * 'httpFieldValue()' - Return the HTTP field enumeration value for a field * name. */ http_field_t /* O - Field index */ httpFieldValue(const char *name) /* I - String name */ { int i; /* Looping var */ for (i = 0; i < HTTP_FIELD_MAX; i ++) if (!_cups_strcasecmp(name, http_fields[i])) return ((http_field_t)i); return (HTTP_FIELD_UNKNOWN); } /* * 'httpFlush()' - Flush data read from a HTTP connection. */ void httpFlush(http_t *http) /* I - HTTP connection */ { char buffer[8192]; /* Junk buffer */ int blocking; /* To block or not to block */ http_state_t oldstate; /* Old state */ DEBUG_printf(("httpFlush(http=%p), state=%s", (void *)http, httpStateString(http->state))); /* * Nothing to do if we are in the "waiting" state... */ if (http->state == HTTP_STATE_WAITING) return; /* * Temporarily set non-blocking mode so we don't get stuck in httpRead()... */ blocking = http->blocking; http->blocking = 0; /* * Read any data we can... */ oldstate = http->state; while (httpRead2(http, buffer, sizeof(buffer)) > 0); /* * Restore blocking and reset the connection if we didn't get all of * the remaining data... */ http->blocking = blocking; if (http->state == oldstate && http->state != HTTP_STATE_WAITING && http->fd >= 0) { /* * Didn't get the data back, so close the current connection. */ #ifdef HAVE_LIBZ if (http->coding) http_content_coding_finish(http); #endif /* HAVE_LIBZ */ DEBUG_puts("1httpFlush: Setting state to HTTP_STATE_WAITING and closing."); http->state = HTTP_STATE_WAITING; #ifdef HAVE_SSL if (http->tls) _httpTLSStop(http); #endif /* HAVE_SSL */ httpAddrClose(NULL, http->fd); http->fd = -1; } } /* * 'httpFlushWrite()' - Flush data written to a HTTP connection. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - Bytes written or -1 on error */ httpFlushWrite(http_t *http) /* I - HTTP connection */ { ssize_t bytes; /* Bytes written */ DEBUG_printf(("httpFlushWrite(http=%p) data_encoding=%d", (void *)http, http ? http->data_encoding : 100)); if (!http || !http->wused) { DEBUG_puts(http ? "1httpFlushWrite: Write buffer is empty." : "1httpFlushWrite: No connection."); return (0); } if (http->data_encoding == HTTP_ENCODING_CHUNKED) bytes = http_write_chunk(http, http->wbuffer, (size_t)http->wused); else bytes = http_write(http, http->wbuffer, (size_t)http->wused); http->wused = 0; DEBUG_printf(("1httpFlushWrite: Returning %d, errno=%d.", (int)bytes, errno)); return ((int)bytes); } /* * 'httpFreeCredentials()' - Free an array of credentials. */ void httpFreeCredentials( cups_array_t *credentials) /* I - Array of credentials */ { http_credential_t *credential; /* Credential */ for (credential = (http_credential_t *)cupsArrayFirst(credentials); credential; credential = (http_credential_t *)cupsArrayNext(credentials)) { cupsArrayRemove(credentials, credential); free((void *)credential->data); free(credential); } cupsArrayDelete(credentials); } /* * 'httpGet()' - Send a GET request to the server. */ int /* O - Status of call (0 = success) */ httpGet(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI to get */ { return (http_send(http, HTTP_STATE_GET, uri)); } /* * 'httpGetActivity()' - Get the most recent activity for a connection. * * The return value is the time in seconds of the last read or write. * * @since CUPS 2.0/OS 10.10@ */ time_t /* O - Time of last read or write */ httpGetActivity(http_t *http) /* I - HTTP connection */ { return (http ? http->activity : 0); } /* * 'httpGetAuthString()' - Get the current authorization string. * * The authorization string is set by @link cupsDoAuthentication@ and * @link httpSetAuthString@. Use @link httpGetAuthString@ to retrieve the * string to use with @link httpSetField@ for the * @code HTTP_FIELD_AUTHORIZATION@ value. * * @since CUPS 1.3/macOS 10.5@ */ char * /* O - Authorization string */ httpGetAuthString(http_t *http) /* I - HTTP connection */ { if (http) return (http->authstring); else return (NULL); } /* * 'httpGetBlocking()' - Get the blocking/non-block state of a connection. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 1 if blocking, 0 if non-blocking */ httpGetBlocking(http_t *http) /* I - HTTP connection */ { return (http ? http->blocking : 0); } /* * 'httpGetContentEncoding()' - Get a common content encoding, if any, between * the client and server. * * This function uses the value of the Accepts-Encoding HTTP header and must be * called after receiving a response from the server or a request from the * client. The value returned can be use in subsequent requests (for clients) * or in the response (for servers) in order to compress the content stream. * * @since CUPS 1.7/macOS 10.9@ */ const char * /* O - Content-Coding value or @code NULL@ for the identity coding. */ httpGetContentEncoding(http_t *http) /* I - HTTP connection */ { #ifdef HAVE_LIBZ if (http && http->fields[HTTP_FIELD_ACCEPT_ENCODING]) { int i; /* Looping var */ char temp[HTTP_MAX_VALUE], /* Copy of Accepts-Encoding value */ *start, /* Start of coding value */ *end; /* End of coding value */ double qvalue; /* "qvalue" for coding */ struct lconv *loc = localeconv(); /* Locale data */ static const char * const codings[] = { /* Supported content codings */ "deflate", "gzip", "x-deflate", "x-gzip" }; strlcpy(temp, http->fields[HTTP_FIELD_ACCEPT_ENCODING], sizeof(temp)); for (start = temp; *start; start = end) { /* * Find the end of the coding name... */ qvalue = 1.0; end = start; while (*end && *end != ';' && *end != ',' && !isspace(*end & 255)) end ++; if (*end == ';') { /* * Grab the qvalue as needed... */ if (!strncmp(end, ";q=", 3)) qvalue = _cupsStrScand(end + 3, NULL, loc); /* * Skip past all attributes... */ *end++ = '\0'; while (*end && *end != ',' && !isspace(*end & 255)) end ++; } else if (*end) *end++ = '\0'; while (*end && isspace(*end & 255)) end ++; /* * Check value if it matches something we support... */ if (qvalue <= 0.0) continue; for (i = 0; i < (int)(sizeof(codings) / sizeof(codings[0])); i ++) if (!strcmp(start, codings[i])) return (codings[i]); } } #endif /* HAVE_LIBZ */ return (NULL); } /* * 'httpGetCookie()' - Get any cookie data from the response. * * @since CUPS 1.1.19/macOS 10.3@ */ const char * /* O - Cookie data or @code NULL@ */ httpGetCookie(http_t *http) /* I - HTTP connection */ { return (http ? http->cookie : NULL); } /* * 'httpGetEncryption()' - Get the current encryption mode of a connection. * * This function returns the encryption mode for the connection. Use the * @link httpIsEncrypted@ function to determine whether a TLS session has * been established. * * @since CUPS 2.0/OS 10.10@ */ http_encryption_t /* O - Current encryption mode */ httpGetEncryption(http_t *http) /* I - HTTP connection */ { return (http ? http->encryption : HTTP_ENCRYPTION_IF_REQUESTED); } /* * 'httpGetExpect()' - Get the value of the Expect header, if any. * * Returns @code HTTP_STATUS_NONE@ if there is no Expect header, otherwise * returns the expected HTTP status code, typically @code HTTP_STATUS_CONTINUE@. * * @since CUPS 1.7/macOS 10.9@ */ http_status_t /* O - Expect: status, if any */ httpGetExpect(http_t *http) /* I - HTTP connection */ { if (!http) return (HTTP_STATUS_ERROR); else return (http->expect); } /* * 'httpGetFd()' - Get the file descriptor associated with a connection. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - File descriptor or -1 if none */ httpGetFd(http_t *http) /* I - HTTP connection */ { return (http ? http->fd : -1); } /* * 'httpGetField()' - Get a field value from a request/response. */ const char * /* O - Field value */ httpGetField(http_t *http, /* I - HTTP connection */ http_field_t field) /* I - Field to get */ { if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX) return (NULL); else if (http->fields[field]) return (http->fields[field]); else return (""); } /* * 'httpGetKeepAlive()' - Get the current Keep-Alive state of the connection. * * @since CUPS 2.0/OS 10.10@ */ http_keepalive_t /* O - Keep-Alive state */ httpGetKeepAlive(http_t *http) /* I - HTTP connection */ { return (http ? http->keep_alive : HTTP_KEEPALIVE_OFF); } /* * 'httpGetLength()' - Get the amount of data remaining from the * content-length or transfer-encoding fields. * * This function is deprecated and will not return lengths larger than * 2^31 - 1; use httpGetLength2() instead. * * @deprecated@ @exclude all@ */ int /* O - Content length */ httpGetLength(http_t *http) /* I - HTTP connection */ { /* * Get the read content length and return the 32-bit value. */ if (http) { httpGetLength2(http); return (http->_data_remaining); } else return (-1); } /* * 'httpGetLength2()' - Get the amount of data remaining from the * content-length or transfer-encoding fields. * * This function returns the complete content length, even for * content larger than 2^31 - 1. * * @since CUPS 1.2/macOS 10.5@ */ off_t /* O - Content length */ httpGetLength2(http_t *http) /* I - HTTP connection */ { off_t remaining; /* Remaining length */ DEBUG_printf(("2httpGetLength2(http=%p), state=%s", (void *)http, httpStateString(http->state))); if (!http) return (-1); if (http->fields[HTTP_FIELD_TRANSFER_ENCODING] && !_cups_strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked")) { DEBUG_puts("4httpGetLength2: chunked request!"); remaining = 0; } else { /* * The following is a hack for HTTP servers that don't send a * Content-Length or Transfer-Encoding field... * * If there is no Content-Length then the connection must close * after the transfer is complete... */ if (!http->fields[HTTP_FIELD_CONTENT_LENGTH] || !http->fields[HTTP_FIELD_CONTENT_LENGTH][0]) { /* * Default content length is 0 for errors and certain types of operations, * and 2^31-1 for other successful requests... */ if (http->status >= HTTP_STATUS_MULTIPLE_CHOICES || http->state == HTTP_STATE_OPTIONS || (http->state == HTTP_STATE_GET && http->mode == _HTTP_MODE_SERVER) || http->state == HTTP_STATE_HEAD || (http->state == HTTP_STATE_PUT && http->mode == _HTTP_MODE_CLIENT) || http->state == HTTP_STATE_DELETE || http->state == HTTP_STATE_TRACE || http->state == HTTP_STATE_CONNECT) remaining = 0; else remaining = 2147483647; } else if ((remaining = strtoll(http->fields[HTTP_FIELD_CONTENT_LENGTH], NULL, 10)) < 0) remaining = -1; DEBUG_printf(("4httpGetLength2: content_length=" CUPS_LLFMT, CUPS_LLCAST remaining)); } return (remaining); } /* * 'httpGetPending()' - Get the number of bytes that are buffered for writing. * * @since CUPS 2.0/OS 10.10@ */ size_t /* O - Number of bytes buffered */ httpGetPending(http_t *http) /* I - HTTP connection */ { return (http ? (size_t)http->wused : 0); } /* * 'httpGetReady()' - Get the number of bytes that can be read without blocking. * * @since CUPS 2.0/OS 10.10@ */ size_t /* O - Number of bytes available */ httpGetReady(http_t *http) /* I - HTTP connection */ { if (!http) return (0); else if (http->used > 0) return ((size_t)http->used); #ifdef HAVE_SSL else if (http->tls) return (_httpTLSPending(http)); #endif /* HAVE_SSL */ return (0); } /* * 'httpGetRemaining()' - Get the number of remaining bytes in the message * body or current chunk. * * The @link httpIsChunked@ function can be used to determine whether the * message body is chunked or fixed-length. * * @since CUPS 2.0/OS 10.10@ */ size_t /* O - Remaining bytes */ httpGetRemaining(http_t *http) /* I - HTTP connection */ { return (http ? (size_t)http->data_remaining : 0); } /* * 'httpGets()' - Get a line of text from a HTTP connection. */ char * /* O - Line or @code NULL@ */ httpGets(char *line, /* I - Line to read into */ int length, /* I - Max length of buffer */ http_t *http) /* I - HTTP connection */ { char *lineptr, /* Pointer into line */ *lineend, /* End of line */ *bufptr, /* Pointer into input buffer */ *bufend; /* Pointer to end of buffer */ ssize_t bytes; /* Number of bytes read */ int eol; /* End-of-line? */ DEBUG_printf(("2httpGets(line=%p, length=%d, http=%p)", (void *)line, length, (void *)http)); if (!http || !line || length <= 1) return (NULL); /* * Read a line from the buffer... */ http->error = 0; lineptr = line; lineend = line + length - 1; eol = 0; while (lineptr < lineend) { /* * Pre-load the buffer as needed... */ #ifdef WIN32 WSASetLastError(0); #else errno = 0; #endif /* WIN32 */ while (http->used == 0) { /* * No newline; see if there is more data to be read... */ while (!_httpWait(http, http->wait_value, 1)) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; DEBUG_puts("3httpGets: Timed out!"); #ifdef WIN32 http->error = WSAETIMEDOUT; #else http->error = ETIMEDOUT; #endif /* WIN32 */ return (NULL); } bytes = http_read(http, http->buffer + http->used, (size_t)(HTTP_MAX_BUFFER - http->used)); DEBUG_printf(("4httpGets: read " CUPS_LLFMT " bytes.", CUPS_LLCAST bytes)); if (bytes < 0) { /* * Nope, can't get a line this time... */ #ifdef WIN32 DEBUG_printf(("3httpGets: recv() error %d!", WSAGetLastError())); if (WSAGetLastError() == WSAEINTR) continue; else if (WSAGetLastError() == WSAEWOULDBLOCK) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; http->error = WSAGetLastError(); } else if (WSAGetLastError() != http->error) { http->error = WSAGetLastError(); continue; } #else DEBUG_printf(("3httpGets: recv() error %d!", errno)); if (errno == EINTR) continue; else if (errno == EWOULDBLOCK || errno == EAGAIN) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; else if (!http->timeout_cb && errno == EAGAIN) continue; http->error = errno; } else if (errno != http->error) { http->error = errno; continue; } #endif /* WIN32 */ return (NULL); } else if (bytes == 0) { http->error = EPIPE; return (NULL); } /* * Yup, update the amount used... */ http->used += (int)bytes; } /* * Now copy as much of the current line as possible... */ for (bufptr = http->buffer, bufend = http->buffer + http->used; lineptr < lineend && bufptr < bufend;) { if (*bufptr == 0x0a) { eol = 1; bufptr ++; break; } else if (*bufptr == 0x0d) bufptr ++; else *lineptr++ = *bufptr++; } http->used -= (int)(bufptr - http->buffer); if (http->used > 0) memmove(http->buffer, bufptr, (size_t)http->used); if (eol) { /* * End of line... */ http->activity = time(NULL); *lineptr = '\0'; DEBUG_printf(("3httpGets: Returning \"%s\"", line)); return (line); } } DEBUG_puts("3httpGets: No new line available!"); return (NULL); } /* * 'httpGetState()' - Get the current state of the HTTP request. */ http_state_t /* O - HTTP state */ httpGetState(http_t *http) /* I - HTTP connection */ { return (http ? http->state : HTTP_STATE_ERROR); } /* * 'httpGetStatus()' - Get the status of the last HTTP request. * * @since CUPS 1.2/macOS 10.5@ */ http_status_t /* O - HTTP status */ httpGetStatus(http_t *http) /* I - HTTP connection */ { return (http ? http->status : HTTP_STATUS_ERROR); } /* * 'httpGetSubField()' - Get a sub-field value. * * @deprecated@ @exclude all@ */ char * /* O - Value or @code NULL@ */ httpGetSubField(http_t *http, /* I - HTTP connection */ http_field_t field, /* I - Field index */ const char *name, /* I - Name of sub-field */ char *value) /* O - Value string */ { return (httpGetSubField2(http, field, name, value, HTTP_MAX_VALUE)); } /* * 'httpGetSubField2()' - Get a sub-field value. * * @since CUPS 1.2/macOS 10.5@ */ char * /* O - Value or @code NULL@ */ httpGetSubField2(http_t *http, /* I - HTTP connection */ http_field_t field, /* I - Field index */ const char *name, /* I - Name of sub-field */ char *value, /* O - Value string */ int valuelen) /* I - Size of value buffer */ { const char *fptr; /* Pointer into field */ char temp[HTTP_MAX_VALUE], /* Temporary buffer for name */ *ptr, /* Pointer into string buffer */ *end; /* End of value buffer */ DEBUG_printf(("2httpGetSubField2(http=%p, field=%d, name=\"%s\", value=%p, valuelen=%d)", (void *)http, field, name, (void *)value, valuelen)); if (!http || !name || !value || valuelen < 2 || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX) return (NULL); end = value + valuelen - 1; for (fptr = http->fields[field]; *fptr;) { /* * Skip leading whitespace... */ while (_cups_isspace(*fptr)) fptr ++; if (*fptr == ',') { fptr ++; continue; } /* * Get the sub-field name... */ for (ptr = temp; *fptr && *fptr != '=' && !_cups_isspace(*fptr) && ptr < (temp + sizeof(temp) - 1); *ptr++ = *fptr++); *ptr = '\0'; DEBUG_printf(("4httpGetSubField2: name=\"%s\"", temp)); /* * Skip trailing chars up to the '='... */ while (_cups_isspace(*fptr)) fptr ++; if (!*fptr) break; if (*fptr != '=') continue; /* * Skip = and leading whitespace... */ fptr ++; while (_cups_isspace(*fptr)) fptr ++; if (*fptr == '\"') { /* * Read quoted string... */ for (ptr = value, fptr ++; *fptr && *fptr != '\"' && ptr < end; *ptr++ = *fptr++); *ptr = '\0'; while (*fptr && *fptr != '\"') fptr ++; if (*fptr) fptr ++; } else { /* * Read unquoted string... */ for (ptr = value; *fptr && !_cups_isspace(*fptr) && *fptr != ',' && ptr < end; *ptr++ = *fptr++); *ptr = '\0'; while (*fptr && !_cups_isspace(*fptr) && *fptr != ',') fptr ++; } DEBUG_printf(("4httpGetSubField2: value=\"%s\"", value)); /* * See if this is the one... */ if (!strcmp(name, temp)) { DEBUG_printf(("3httpGetSubField2: Returning \"%s\"", value)); return (value); } } value[0] = '\0'; DEBUG_puts("3httpGetSubField2: Returning NULL"); return (NULL); } /* * 'httpGetVersion()' - Get the HTTP version at the other end. */ http_version_t /* O - Version number */ httpGetVersion(http_t *http) /* I - HTTP connection */ { return (http ? http->version : HTTP_VERSION_1_0); } /* * 'httpHead()' - Send a HEAD request to the server. */ int /* O - Status of call (0 = success) */ httpHead(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI for head */ { DEBUG_printf(("httpHead(http=%p, uri=\"%s\")", (void *)http, uri)); return (http_send(http, HTTP_STATE_HEAD, uri)); } /* * 'httpInitialize()' - Initialize the HTTP interface library and set the * default HTTP proxy (if any). */ void httpInitialize(void) { static int initialized = 0; /* Have we been called before? */ #ifdef WIN32 WSADATA winsockdata; /* WinSock data */ #endif /* WIN32 */ _cupsGlobalLock(); if (initialized) { _cupsGlobalUnlock(); return; } #ifdef WIN32 WSAStartup(MAKEWORD(2,2), &winsockdata); #elif !defined(SO_NOSIGPIPE) /* * Ignore SIGPIPE signals... */ # ifdef HAVE_SIGSET sigset(SIGPIPE, SIG_IGN); # elif defined(HAVE_SIGACTION) struct sigaction action; /* POSIX sigaction data */ memset(&action, 0, sizeof(action)); action.sa_handler = SIG_IGN; sigaction(SIGPIPE, &action, NULL); # else signal(SIGPIPE, SIG_IGN); # endif /* !SO_NOSIGPIPE */ #endif /* WIN32 */ # ifdef HAVE_SSL _httpTLSInitialize(); # endif /* HAVE_SSL */ initialized = 1; _cupsGlobalUnlock(); } /* * 'httpIsChunked()' - Report whether a message body is chunked. * * This function returns non-zero if the message body is composed of * variable-length chunks. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 1 if chunked, 0 if not */ httpIsChunked(http_t *http) /* I - HTTP connection */ { return (http ? http->data_encoding == HTTP_ENCODING_CHUNKED : 0); } /* * 'httpIsEncrypted()' - Report whether a connection is encrypted. * * This function returns non-zero if the connection is currently encrypted. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 1 if encrypted, 0 if not */ httpIsEncrypted(http_t *http) /* I - HTTP connection */ { return (http ? http->tls != NULL : 0); } /* * 'httpOptions()' - Send an OPTIONS request to the server. */ int /* O - Status of call (0 = success) */ httpOptions(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI for options */ { return (http_send(http, HTTP_STATE_OPTIONS, uri)); } /* * 'httpPeek()' - Peek at data from a HTTP connection. * * This function copies available data from the given HTTP connection, reading * a buffer as needed. The data is still available for reading using * @link httpRead2@. * * For non-blocking connections the usual timeouts apply. * * @since CUPS 1.7/macOS 10.9@ */ ssize_t /* O - Number of bytes copied */ httpPeek(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Buffer for data */ size_t length) /* I - Maximum number of bytes */ { ssize_t bytes; /* Bytes read */ char len[32]; /* Length string */ DEBUG_printf(("httpPeek(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length)); if (http == NULL || buffer == NULL) return (-1); http->activity = time(NULL); http->error = 0; if (length <= 0) return (0); if (http->data_encoding == HTTP_ENCODING_CHUNKED && http->data_remaining <= 0) { DEBUG_puts("2httpPeek: Getting chunk length..."); if (httpGets(len, sizeof(len), http) == NULL) { DEBUG_puts("1httpPeek: Could not get length!"); return (0); } if (!len[0]) { DEBUG_puts("1httpPeek: Blank chunk length, trying again..."); if (!httpGets(len, sizeof(len), http)) { DEBUG_puts("1httpPeek: Could not get chunk length."); return (0); } } http->data_remaining = strtoll(len, NULL, 16); if (http->data_remaining < 0) { DEBUG_puts("1httpPeek: Negative chunk length!"); return (0); } } DEBUG_printf(("2httpPeek: data_remaining=" CUPS_LLFMT, CUPS_LLCAST http->data_remaining)); if (http->data_remaining <= 0 && http->data_encoding != HTTP_ENCODING_FIELDS) { /* * A zero-length chunk ends a transfer; unless we are reading POST * data, go idle... */ #ifdef HAVE_LIBZ if (http->coding >= _HTTP_CODING_GUNZIP) http_content_coding_finish(http); #endif /* HAVE_LIBZ */ if (http->data_encoding == HTTP_ENCODING_CHUNKED) httpGets(len, sizeof(len), http); if (http->state == HTTP_STATE_POST_RECV) http->state ++; else http->state = HTTP_STATE_STATUS; DEBUG_printf(("1httpPeek: 0-length chunk, set state to %s.", httpStateString(http->state))); /* * Prevent future reads for this request... */ http->data_encoding = HTTP_ENCODING_FIELDS; return (0); } else if (length > (size_t)http->data_remaining) length = (size_t)http->data_remaining; #ifdef HAVE_LIBZ if (http->used == 0 && (http->coding == _HTTP_CODING_IDENTITY || (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in == 0))) #else if (http->used == 0) #endif /* HAVE_LIBZ */ { /* * Buffer small reads for better performance... */ ssize_t buflen; /* Length of read for buffer */ if (!http->blocking) { while (!httpWait(http, http->wait_value)) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; return (0); } } if ((size_t)http->data_remaining > sizeof(http->buffer)) buflen = sizeof(http->buffer); else buflen = (ssize_t)http->data_remaining; DEBUG_printf(("2httpPeek: Reading %d bytes into buffer.", (int)buflen)); bytes = http_read(http, http->buffer, (size_t)buflen); DEBUG_printf(("2httpPeek: Read " CUPS_LLFMT " bytes into buffer.", CUPS_LLCAST bytes)); if (bytes > 0) { #ifdef DEBUG http_debug_hex("httpPeek", http->buffer, (int)bytes); #endif /* DEBUG */ http->used = (int)bytes; } } #ifdef HAVE_LIBZ if (http->coding >= _HTTP_CODING_GUNZIP) { # ifdef HAVE_INFLATECOPY int zerr; /* Decompressor error */ z_stream stream; /* Copy of decompressor stream */ if (http->used > 0 && http->stream.avail_in < HTTP_MAX_BUFFER) { size_t buflen = buflen = HTTP_MAX_BUFFER - http->stream.avail_in; /* Number of bytes to copy */ if (http->stream.avail_in > 0 && http->stream.next_in > http->sbuffer) memmove(http->sbuffer, http->stream.next_in, http->stream.avail_in); http->stream.next_in = http->sbuffer; if (buflen > (size_t)http->data_remaining) buflen = (size_t)http->data_remaining; if (buflen > (size_t)http->used) buflen = (size_t)http->used; DEBUG_printf(("1httpPeek: Copying %d more bytes of data into " "decompression buffer.", (int)buflen)); memcpy(http->sbuffer + http->stream.avail_in, http->buffer, buflen); http->stream.avail_in += buflen; http->used -= (int)buflen; http->data_remaining -= (off_t)buflen; if (http->used > 0) memmove(http->buffer, http->buffer + buflen, (size_t)http->used); } DEBUG_printf(("2httpPeek: length=%d, avail_in=%d", (int)length, (int)http->stream.avail_in)); if (inflateCopy(&stream, &(http->stream)) != Z_OK) { DEBUG_puts("2httpPeek: Unable to copy decompressor stream."); http->error = ENOMEM; return (-1); } stream.next_out = (Bytef *)buffer; stream.avail_out = (uInt)length; zerr = inflate(&stream, Z_SYNC_FLUSH); inflateEnd(&stream); if (zerr < Z_OK) { DEBUG_printf(("2httpPeek: zerr=%d", zerr)); #ifdef DEBUG http_debug_hex("2httpPeek", (char *)http->sbuffer, (int)http->stream.avail_in); #endif /* DEBUG */ http->error = EIO; return (-1); } bytes = (ssize_t)(length - http->stream.avail_out); # else DEBUG_puts("2httpPeek: No inflateCopy on this platform, httpPeek does not " "work with compressed streams."); return (-1); # endif /* HAVE_INFLATECOPY */ } else #endif /* HAVE_LIBZ */ if (http->used > 0) { if (length > (size_t)http->used) length = (size_t)http->used; bytes = (ssize_t)length; DEBUG_printf(("2httpPeek: grabbing %d bytes from input buffer...", (int)bytes)); memcpy(buffer, http->buffer, length); } else bytes = 0; if (bytes < 0) { #ifdef WIN32 if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK) bytes = 0; else http->error = WSAGetLastError(); #else if (errno == EINTR || errno == EAGAIN) bytes = 0; else http->error = errno; #endif /* WIN32 */ } else if (bytes == 0) { http->error = EPIPE; return (0); } return (bytes); } /* * 'httpPost()' - Send a POST request to the server. */ int /* O - Status of call (0 = success) */ httpPost(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI for post */ { return (http_send(http, HTTP_STATE_POST, uri)); } /* * 'httpPrintf()' - Print a formatted string to a HTTP connection. * * @private@ */ int /* O - Number of bytes written */ httpPrintf(http_t *http, /* I - HTTP connection */ const char *format, /* I - printf-style format string */ ...) /* I - Additional args as needed */ { ssize_t bytes; /* Number of bytes to write */ char buf[16384]; /* Buffer for formatted string */ va_list ap; /* Variable argument pointer */ DEBUG_printf(("2httpPrintf(http=%p, format=\"%s\", ...)", (void *)http, format)); va_start(ap, format); bytes = vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); DEBUG_printf(("3httpPrintf: (" CUPS_LLFMT " bytes) %s", CUPS_LLCAST bytes, buf)); if (http->data_encoding == HTTP_ENCODING_FIELDS) return ((int)httpWrite2(http, buf, (size_t)bytes)); else { if (http->wused) { DEBUG_puts("4httpPrintf: flushing existing data..."); if (httpFlushWrite(http) < 0) return (-1); } return ((int)http_write(http, buf, (size_t)bytes)); } } /* * 'httpPut()' - Send a PUT request to the server. */ int /* O - Status of call (0 = success) */ httpPut(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI to put */ { DEBUG_printf(("httpPut(http=%p, uri=\"%s\")", (void *)http, uri)); return (http_send(http, HTTP_STATE_PUT, uri)); } /* * 'httpRead()' - Read data from a HTTP connection. * * This function is deprecated. Use the httpRead2() function which can * read more than 2GB of data. * * @deprecated@ @exclude all@ */ int /* O - Number of bytes read */ httpRead(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Buffer for data */ int length) /* I - Maximum number of bytes */ { return ((int)httpRead2(http, buffer, (size_t)length)); } /* * 'httpRead2()' - Read data from a HTTP connection. * * @since CUPS 1.2/macOS 10.5@ */ ssize_t /* O - Number of bytes read */ httpRead2(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Buffer for data */ size_t length) /* I - Maximum number of bytes */ { ssize_t bytes; /* Bytes read */ #ifdef HAVE_LIBZ DEBUG_printf(("httpRead2(http=%p, buffer=%p, length=" CUPS_LLFMT ") coding=%d data_encoding=%d data_remaining=" CUPS_LLFMT, (void *)http, (void *)buffer, CUPS_LLCAST length, http->coding, http->data_encoding, CUPS_LLCAST http->data_remaining)); #else DEBUG_printf(("httpRead2(http=%p, buffer=%p, length=" CUPS_LLFMT ") data_encoding=%d data_remaining=" CUPS_LLFMT, (void *)http, (void *)buffer, CUPS_LLCAST length, http->data_encoding, CUPS_LLCAST http->data_remaining)); #endif /* HAVE_LIBZ */ if (http == NULL || buffer == NULL) return (-1); http->activity = time(NULL); http->error = 0; if (length <= 0) return (0); #ifdef HAVE_LIBZ if (http->coding >= _HTTP_CODING_GUNZIP) { do { if (http->stream.avail_in > 0) { int zerr; /* Decompressor error */ DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d", (int)http->stream.avail_in, (int)length)); http->stream.next_out = (Bytef *)buffer; http->stream.avail_out = (uInt)length; if ((zerr = inflate(&(http->stream), Z_SYNC_FLUSH)) < Z_OK) { DEBUG_printf(("2httpRead2: zerr=%d", zerr)); #ifdef DEBUG http_debug_hex("2httpRead2", (char *)http->sbuffer, (int)http->stream.avail_in); #endif /* DEBUG */ http->error = EIO; return (-1); } bytes = (ssize_t)(length - http->stream.avail_out); DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d, bytes=%d", http->stream.avail_in, http->stream.avail_out, (int)bytes)); } else bytes = 0; if (bytes == 0) { ssize_t buflen = HTTP_MAX_BUFFER - (ssize_t)http->stream.avail_in; /* Additional bytes for buffer */ if (buflen > 0) { if (http->stream.avail_in > 0 && http->stream.next_in > http->sbuffer) memmove(http->sbuffer, http->stream.next_in, http->stream.avail_in); http->stream.next_in = http->sbuffer; DEBUG_printf(("1httpRead2: Reading up to %d more bytes of data into " "decompression buffer.", (int)buflen)); if (http->data_remaining > 0) { if (buflen > http->data_remaining) buflen = (ssize_t)http->data_remaining; bytes = http_read_buffered(http, (char *)http->sbuffer + http->stream.avail_in, (size_t)buflen); } else if (http->data_encoding == HTTP_ENCODING_CHUNKED) bytes = http_read_chunk(http, (char *)http->sbuffer + http->stream.avail_in, (size_t)buflen); else bytes = 0; if (bytes < 0) return (bytes); else if (bytes == 0) break; DEBUG_printf(("1httpRead2: Adding " CUPS_LLFMT " bytes to " "decompression buffer.", CUPS_LLCAST bytes)); http->data_remaining -= bytes; http->stream.avail_in += (uInt)bytes; if (http->data_remaining <= 0 && http->data_encoding == HTTP_ENCODING_CHUNKED) { /* * Read the trailing blank line now... */ char len[32]; /* Length string */ httpGets(len, sizeof(len), http); } bytes = 0; } else return (0); } } while (bytes == 0); } else #endif /* HAVE_LIBZ */ if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODING_CHUNKED) { if ((bytes = http_read_chunk(http, buffer, length)) > 0) { http->data_remaining -= bytes; if (http->data_remaining <= 0) { /* * Read the trailing blank line now... */ char len[32]; /* Length string */ httpGets(len, sizeof(len), http); } } } else if (http->data_remaining <= 0) { /* * No more data to read... */ return (0); } else { DEBUG_printf(("1httpRead2: Reading up to %d bytes into buffer.", (int)length)); if (length > (size_t)http->data_remaining) length = (size_t)http->data_remaining; if ((bytes = http_read_buffered(http, buffer, length)) > 0) { http->data_remaining -= bytes; if (http->data_remaining <= 0 && http->data_encoding == HTTP_ENCODING_CHUNKED) { /* * Read the trailing blank line now... */ char len[32]; /* Length string */ httpGets(len, sizeof(len), http); } } } if ( #ifdef HAVE_LIBZ (http->coding == _HTTP_CODING_IDENTITY || (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in == 0)) && #endif /* HAVE_LIBZ */ ((http->data_remaining <= 0 && http->data_encoding == HTTP_ENCODING_LENGTH) || (http->data_encoding == HTTP_ENCODING_CHUNKED && bytes == 0))) { #ifdef HAVE_LIBZ if (http->coding >= _HTTP_CODING_GUNZIP) http_content_coding_finish(http); #endif /* HAVE_LIBZ */ if (http->state == HTTP_STATE_POST_RECV) http->state ++; else if (http->state == HTTP_STATE_GET_SEND || http->state == HTTP_STATE_POST_SEND) http->state = HTTP_STATE_WAITING; else http->state = HTTP_STATE_STATUS; DEBUG_printf(("1httpRead2: End of content, set state to %s.", httpStateString(http->state))); } return (bytes); } /* * 'httpReadRequest()' - Read a HTTP request from a connection. * * @since CUPS 1.7/macOS 10.9@ */ http_state_t /* O - New state of connection */ httpReadRequest(http_t *http, /* I - HTTP connection */ char *uri, /* I - URI buffer */ size_t urilen) /* I - Size of URI buffer */ { char line[4096], /* HTTP request line */ *req_method, /* HTTP request method */ *req_uri, /* HTTP request URI */ *req_version; /* HTTP request version number string */ /* * Range check input... */ DEBUG_printf(("httpReadRequest(http=%p, uri=%p, urilen=" CUPS_LLFMT ")", (void *)http, (void *)uri, CUPS_LLCAST urilen)); if (uri) *uri = '\0'; if (!http || !uri || urilen < 1) { DEBUG_puts("1httpReadRequest: Bad arguments, returning HTTP_STATE_ERROR."); return (HTTP_STATE_ERROR); } else if (http->state != HTTP_STATE_WAITING) { DEBUG_printf(("1httpReadRequest: Bad state %s, returning HTTP_STATE_ERROR.", httpStateString(http->state))); return (HTTP_STATE_ERROR); } /* * Reset state... */ httpClearFields(http); http->activity = time(NULL); http->data_encoding = HTTP_ENCODING_FIELDS; http->data_remaining = 0; http->keep_alive = HTTP_KEEPALIVE_OFF; http->status = HTTP_STATUS_OK; http->version = HTTP_VERSION_1_1; /* * Read a line from the socket... */ if (!httpGets(line, sizeof(line), http)) { DEBUG_puts("1httpReadRequest: Unable to read, returning HTTP_STATE_ERROR"); return (HTTP_STATE_ERROR); } if (!line[0]) { DEBUG_puts("1httpReadRequest: Blank line, returning HTTP_STATE_WAITING"); return (HTTP_STATE_WAITING); } DEBUG_printf(("1httpReadRequest: %s", line)); /* * Parse it... */ req_method = line; req_uri = line; while (*req_uri && !isspace(*req_uri & 255)) req_uri ++; if (!*req_uri) { DEBUG_puts("1httpReadRequest: No request URI."); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No request URI."), 1); return (HTTP_STATE_ERROR); } *req_uri++ = '\0'; while (*req_uri && isspace(*req_uri & 255)) req_uri ++; req_version = req_uri; while (*req_version && !isspace(*req_version & 255)) req_version ++; if (!*req_version) { DEBUG_puts("1httpReadRequest: No request protocol version."); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No request protocol version."), 1); return (HTTP_STATE_ERROR); } *req_version++ = '\0'; while (*req_version && isspace(*req_version & 255)) req_version ++; /* * Validate... */ if (!strcmp(req_method, "OPTIONS")) http->state = HTTP_STATE_OPTIONS; else if (!strcmp(req_method, "GET")) http->state = HTTP_STATE_GET; else if (!strcmp(req_method, "HEAD")) http->state = HTTP_STATE_HEAD; else if (!strcmp(req_method, "POST")) http->state = HTTP_STATE_POST; else if (!strcmp(req_method, "PUT")) http->state = HTTP_STATE_PUT; else if (!strcmp(req_method, "DELETE")) http->state = HTTP_STATE_DELETE; else if (!strcmp(req_method, "TRACE")) http->state = HTTP_STATE_TRACE; else if (!strcmp(req_method, "CONNECT")) http->state = HTTP_STATE_CONNECT; else { DEBUG_printf(("1httpReadRequest: Unknown method \"%s\".", req_method)); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown request method."), 1); return (HTTP_STATE_UNKNOWN_METHOD); } DEBUG_printf(("1httpReadRequest: Set state to %s.", httpStateString(http->state))); if (!strcmp(req_version, "HTTP/1.0")) { http->version = HTTP_VERSION_1_0; http->keep_alive = HTTP_KEEPALIVE_OFF; } else if (!strcmp(req_version, "HTTP/1.1")) { http->version = HTTP_VERSION_1_1; http->keep_alive = HTTP_KEEPALIVE_ON; } else { DEBUG_printf(("1httpReadRequest: Unknown version \"%s\".", req_version)); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown request version."), 1); return (HTTP_STATE_UNKNOWN_VERSION); } DEBUG_printf(("1httpReadRequest: URI is \"%s\".", req_uri)); strlcpy(uri, req_uri, urilen); return (http->state); } /* * 'httpReconnect()' - Reconnect to a HTTP server. * * This function is deprecated. Please use the @link httpReconnect2@ function * instead. * * @deprecated@ @exclude all@ */ int /* O - 0 on success, non-zero on failure */ httpReconnect(http_t *http) /* I - HTTP connection */ { DEBUG_printf(("httpReconnect(http=%p)", (void *)http)); return (httpReconnect2(http, 30000, NULL)); } /* * 'httpReconnect2()' - Reconnect to a HTTP server with timeout and optional * cancel. */ int /* O - 0 on success, non-zero on failure */ httpReconnect2(http_t *http, /* I - HTTP connection */ int msec, /* I - Timeout in milliseconds */ int *cancel) /* I - Pointer to "cancel" variable */ { http_addrlist_t *addr; /* Connected address */ #ifdef DEBUG http_addrlist_t *current; /* Current address */ char temp[256]; /* Temporary address string */ #endif /* DEBUG */ DEBUG_printf(("httpReconnect2(http=%p, msec=%d, cancel=%p)", (void *)http, msec, (void *)cancel)); if (!http) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (-1); } #ifdef HAVE_SSL if (http->tls) { DEBUG_puts("2httpReconnect2: Shutting down SSL/TLS..."); _httpTLSStop(http); } #endif /* HAVE_SSL */ /* * Close any previously open socket... */ if (http->fd >= 0) { DEBUG_printf(("2httpReconnect2: Closing socket %d...", http->fd)); httpAddrClose(NULL, http->fd); http->fd = -1; } /* * Reset all state (except fields, which may be reused)... */ http->state = HTTP_STATE_WAITING; http->version = HTTP_VERSION_1_1; http->keep_alive = HTTP_KEEPALIVE_OFF; memset(&http->_hostaddr, 0, sizeof(http->_hostaddr)); http->data_encoding = HTTP_ENCODING_FIELDS; http->_data_remaining = 0; http->used = 0; http->data_remaining = 0; http->hostaddr = NULL; http->wused = 0; /* * Connect to the server... */ #ifdef DEBUG for (current = http->addrlist; current; current = current->next) DEBUG_printf(("2httpReconnect2: Address %s:%d", httpAddrString(&(current->addr), temp, sizeof(temp)), httpAddrPort(&(current->addr)))); #endif /* DEBUG */ if ((addr = httpAddrConnect2(http->addrlist, &(http->fd), msec, cancel)) == NULL) { /* * Unable to connect... */ #ifdef WIN32 http->error = WSAGetLastError(); #else http->error = errno; #endif /* WIN32 */ http->status = HTTP_STATUS_ERROR; DEBUG_printf(("1httpReconnect2: httpAddrConnect failed: %s", strerror(http->error))); return (-1); } DEBUG_printf(("2httpReconnect2: New socket=%d", http->fd)); if (http->timeout_value > 0) http_set_timeout(http->fd, http->timeout_value); http->hostaddr = &(addr->addr); http->error = 0; #ifdef HAVE_SSL if (http->encryption == HTTP_ENCRYPTION_ALWAYS) { /* * Always do encryption via SSL. */ if (_httpTLSStart(http) != 0) { httpAddrClose(NULL, http->fd); return (-1); } } else if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls_upgrade) return (http_tls_upgrade(http)); #endif /* HAVE_SSL */ DEBUG_printf(("1httpReconnect2: Connected to %s:%d...", httpAddrString(http->hostaddr, temp, sizeof(temp)), httpAddrPort(http->hostaddr))); return (0); } /* * 'httpSetAuthString()' - Set the current authorization string. * * This function just stores a copy of the current authorization string in * the HTTP connection object. You must still call @link httpSetField@ to set * @code HTTP_FIELD_AUTHORIZATION@ prior to issuing a HTTP request using * @link httpGet@, @link httpHead@, @link httpOptions@, @link httpPost@, or * @link httpPut@. * * @since CUPS 1.3/macOS 10.5@ */ void httpSetAuthString(http_t *http, /* I - HTTP connection */ const char *scheme, /* I - Auth scheme (NULL to clear it) */ const char *data) /* I - Auth data (NULL for none) */ { /* * Range check input... */ if (!http) return; if (http->authstring && http->authstring != http->_authstring) free(http->authstring); http->authstring = http->_authstring; if (scheme) { /* * Set the current authorization string... */ size_t len = strlen(scheme) + (data ? strlen(data) + 1 : 0) + 1; char *temp; if (len > sizeof(http->_authstring)) { if ((temp = malloc(len)) == NULL) len = sizeof(http->_authstring); else http->authstring = temp; } if (data) snprintf(http->authstring, len, "%s %s", scheme, data); else strlcpy(http->authstring, scheme, len); } else { /* * Clear the current authorization string... */ http->_authstring[0] = '\0'; } } /* * 'httpSetCredentials()' - Set the credentials associated with an encrypted * connection. * * @since CUPS 1.5/macOS 10.7@ */ int /* O - Status of call (0 = success) */ httpSetCredentials(http_t *http, /* I - HTTP connection */ cups_array_t *credentials) /* I - Array of credentials */ { if (!http || cupsArrayCount(credentials) < 1) return (-1); #ifdef HAVE_SSL _httpFreeCredentials(http->tls_credentials); http->tls_credentials = _httpCreateCredentials(credentials); #endif /* HAVE_SSL */ return (http->tls_credentials ? 0 : -1); } /* * 'httpSetCookie()' - Set the cookie value(s). * * @since CUPS 1.1.19/macOS 10.3@ */ void httpSetCookie(http_t *http, /* I - Connection */ const char *cookie) /* I - Cookie string */ { if (!http) return; if (http->cookie) free(http->cookie); if (cookie) http->cookie = strdup(cookie); else http->cookie = NULL; } /* * 'httpSetDefaultField()' - Set the default value of an HTTP header. * * Currently only @code HTTP_FIELD_ACCEPT_ENCODING@, @code HTTP_FIELD_SERVER@, * and @code HTTP_FIELD_USER_AGENT@ can be set. * * @since CUPS 1.7/macOS 10.9@ */ void httpSetDefaultField(http_t *http, /* I - HTTP connection */ http_field_t field, /* I - Field index */ const char *value)/* I - Value */ { DEBUG_printf(("httpSetDefaultField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value)); if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX) return; if (http->default_fields[field]) free(http->default_fields[field]); http->default_fields[field] = value ? strdup(value) : NULL; } /* * 'httpSetExpect()' - Set the Expect: header in a request. * * Currently only @code HTTP_STATUS_CONTINUE@ is supported for the "expect" * argument. * * @since CUPS 1.2/macOS 10.5@ */ void httpSetExpect(http_t *http, /* I - HTTP connection */ http_status_t expect) /* I - HTTP status to expect (@code HTTP_STATUS_CONTINUE@) */ { DEBUG_printf(("httpSetExpect(http=%p, expect=%d)", (void *)http, expect)); if (http) http->expect = expect; } /* * 'httpSetField()' - Set the value of an HTTP header. */ void httpSetField(http_t *http, /* I - HTTP connection */ http_field_t field, /* I - Field index */ const char *value) /* I - Value */ { DEBUG_printf(("httpSetField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value)); if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX || !value) return; http_add_field(http, field, value, 0); } /* * 'httpSetKeepAlive()' - Set the current Keep-Alive state of a connection. * * @since CUPS 2.0/OS 10.10@ */ void httpSetKeepAlive( http_t *http, /* I - HTTP connection */ http_keepalive_t keep_alive) /* I - New Keep-Alive value */ { if (http) http->keep_alive = keep_alive; } /* * 'httpSetLength()' - Set the content-length and content-encoding. * * @since CUPS 1.2/macOS 10.5@ */ void httpSetLength(http_t *http, /* I - HTTP connection */ size_t length) /* I - Length (0 for chunked) */ { DEBUG_printf(("httpSetLength(http=%p, length=" CUPS_LLFMT ")", (void *)http, CUPS_LLCAST length)); if (!http) return; if (!length) { httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked"); httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, ""); } else { char len[32]; /* Length string */ snprintf(len, sizeof(len), CUPS_LLFMT, CUPS_LLCAST length); httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, ""); httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, len); } } /* * 'httpSetTimeout()' - Set read/write timeouts and an optional callback. * * The optional timeout callback receives both the HTTP connection and a user * data pointer and must return 1 to continue or 0 to error (time) out. * * @since CUPS 1.5/macOS 10.7@ */ void httpSetTimeout( http_t *http, /* I - HTTP connection */ double timeout, /* I - Number of seconds for timeout, must be greater than 0 */ http_timeout_cb_t cb, /* I - Callback function or @code NULL@ */ void *user_data) /* I - User data pointer */ { if (!http || timeout <= 0.0) return; http->timeout_cb = cb; http->timeout_data = user_data; http->timeout_value = timeout; if (http->fd >= 0) http_set_timeout(http->fd, timeout); http_set_wait(http); } /* * 'httpShutdown()' - Shutdown one side of an HTTP connection. * * @since CUPS 2.0/OS 10.10@ */ void httpShutdown(http_t *http) /* I - HTTP connection */ { if (!http || http->fd < 0) return; #ifdef HAVE_SSL if (http->tls) _httpTLSStop(http); #endif /* HAVE_SSL */ #ifdef WIN32 shutdown(http->fd, SD_RECEIVE); /* Microsoft-ism... */ #else shutdown(http->fd, SHUT_RD); #endif /* WIN32 */ } /* * 'httpTrace()' - Send an TRACE request to the server. * * @exclude all@ */ int /* O - Status of call (0 = success) */ httpTrace(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI for trace */ { return (http_send(http, HTTP_STATE_TRACE, uri)); } /* * '_httpUpdate()' - Update the current HTTP status for incoming data. * * Note: Unlike httpUpdate(), this function does not flush pending write data * and only retrieves a single status line from the HTTP connection. */ int /* O - 1 to continue, 0 to stop */ _httpUpdate(http_t *http, /* I - HTTP connection */ http_status_t *status) /* O - Current HTTP status */ { char line[32768], /* Line from connection... */ *value; /* Pointer to value on line */ http_field_t field; /* Field index */ int major, minor; /* HTTP version numbers */ DEBUG_printf(("_httpUpdate(http=%p, status=%p), state=%s", (void *)http, (void *)status, httpStateString(http->state))); /* * Grab a single line from the connection... */ if (!httpGets(line, sizeof(line), http)) { *status = HTTP_STATUS_ERROR; return (0); } DEBUG_printf(("2_httpUpdate: Got \"%s\"", line)); if (line[0] == '\0') { /* * Blank line means the start of the data section (if any). Return * the result code, too... * * If we get status 100 (HTTP_STATUS_CONTINUE), then we *don't* change * states. Instead, we just return HTTP_STATUS_CONTINUE to the caller and * keep on tryin'... */ if (http->status == HTTP_STATUS_CONTINUE) { *status = http->status; return (0); } if (http->status < HTTP_STATUS_BAD_REQUEST) http->digest_tries = 0; #ifdef HAVE_SSL if (http->status == HTTP_STATUS_SWITCHING_PROTOCOLS && !http->tls) { if (_httpTLSStart(http) != 0) { httpAddrClose(NULL, http->fd); *status = http->status = HTTP_STATUS_ERROR; return (0); } *status = HTTP_STATUS_CONTINUE; return (0); } #endif /* HAVE_SSL */ if (http_set_length(http) < 0) { DEBUG_puts("1_httpUpdate: Bad Content-Length."); http->error = EINVAL; http->status = *status = HTTP_STATUS_ERROR; return (0); } switch (http->state) { case HTTP_STATE_GET : case HTTP_STATE_POST : case HTTP_STATE_POST_RECV : case HTTP_STATE_PUT : http->state ++; DEBUG_printf(("1_httpUpdate: Set state to %s.", httpStateString(http->state))); case HTTP_STATE_POST_SEND : case HTTP_STATE_HEAD : break; default : http->state = HTTP_STATE_WAITING; DEBUG_puts("1_httpUpdate: Reset state to HTTP_STATE_WAITING."); break; } #ifdef HAVE_LIBZ DEBUG_puts("1_httpUpdate: Calling http_content_coding_start."); http_content_coding_start(http, httpGetField(http, HTTP_FIELD_CONTENT_ENCODING)); #endif /* HAVE_LIBZ */ *status = http->status; return (0); } else if (!strncmp(line, "HTTP/", 5) && http->mode == _HTTP_MODE_CLIENT) { /* * Got the beginning of a response... */ int intstatus; /* Status value as an integer */ if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &intstatus) != 3) { *status = http->status = HTTP_STATUS_ERROR; return (0); } httpClearFields(http); http->version = (http_version_t)(major * 100 + minor); *status = http->status = (http_status_t)intstatus; } else if ((value = strchr(line, ':')) != NULL) { /* * Got a value... */ *value++ = '\0'; while (_cups_isspace(*value)) value ++; DEBUG_printf(("1_httpUpdate: Header %s: %s", line, value)); /* * Be tolerants of servers that send unknown attribute fields... */ if (!_cups_strcasecmp(line, "expect")) { /* * "Expect: 100-continue" or similar... */ http->expect = (http_status_t)atoi(value); } else if (!_cups_strcasecmp(line, "cookie")) { /* * "Cookie: name=value[; name=value ...]" - replaces previous cookies... */ httpSetCookie(http, value); } else if ((field = httpFieldValue(line)) != HTTP_FIELD_UNKNOWN) http_add_field(http, field, value, 1); #ifdef DEBUG else DEBUG_printf(("1_httpUpdate: unknown field %s seen!", line)); #endif /* DEBUG */ } else { DEBUG_printf(("1_httpUpdate: Bad response line \"%s\"!", line)); http->error = EINVAL; http->status = *status = HTTP_STATUS_ERROR; return (0); } return (1); } /* * 'httpUpdate()' - Update the current HTTP state for incoming data. */ http_status_t /* O - HTTP status */ httpUpdate(http_t *http) /* I - HTTP connection */ { http_status_t status; /* Request status */ DEBUG_printf(("httpUpdate(http=%p), state=%s", (void *)http, httpStateString(http->state))); /* * Flush pending data, if any... */ if (http->wused) { DEBUG_puts("2httpUpdate: flushing buffer..."); if (httpFlushWrite(http) < 0) return (HTTP_STATUS_ERROR); } /* * If we haven't issued any commands, then there is nothing to "update"... */ if (http->state == HTTP_STATE_WAITING) return (HTTP_STATUS_CONTINUE); /* * Grab all of the lines we can from the connection... */ while (_httpUpdate(http, &status)); /* * See if there was an error... */ if (http->error == EPIPE && http->status > HTTP_STATUS_CONTINUE) { DEBUG_printf(("1httpUpdate: Returning status %d...", http->status)); return (http->status); } if (http->error) { DEBUG_printf(("1httpUpdate: socket error %d - %s", http->error, strerror(http->error))); http->status = HTTP_STATUS_ERROR; return (HTTP_STATUS_ERROR); } /* * Return the current status... */ return (status); } /* * '_httpWait()' - Wait for data available on a connection (no flush). */ int /* O - 1 if data is available, 0 otherwise */ _httpWait(http_t *http, /* I - HTTP connection */ int msec, /* I - Milliseconds to wait */ int usessl) /* I - Use SSL context? */ { #ifdef HAVE_POLL struct pollfd pfd; /* Polled file descriptor */ #else fd_set input_set; /* select() input set */ struct timeval timeout; /* Timeout */ #endif /* HAVE_POLL */ int nfds; /* Result from select()/poll() */ DEBUG_printf(("4_httpWait(http=%p, msec=%d, usessl=%d)", (void *)http, msec, usessl)); if (http->fd < 0) { DEBUG_printf(("5_httpWait: Returning 0 since fd=%d", http->fd)); return (0); } /* * Check the SSL/TLS buffers for data first... */ #ifdef HAVE_SSL if (http->tls && _httpTLSPending(http)) { DEBUG_puts("5_httpWait: Return 1 since there is pending TLS data."); return (1); } #endif /* HAVE_SSL */ /* * Then try doing a select() or poll() to poll the socket... */ #ifdef HAVE_POLL pfd.fd = http->fd; pfd.events = POLLIN; do { nfds = poll(&pfd, 1, msec); } while (nfds < 0 && (errno == EINTR || errno == EAGAIN)); #else do { FD_ZERO(&input_set); FD_SET(http->fd, &input_set); DEBUG_printf(("6_httpWait: msec=%d, http->fd=%d", msec, http->fd)); if (msec >= 0) { timeout.tv_sec = msec / 1000; timeout.tv_usec = (msec % 1000) * 1000; nfds = select(http->fd + 1, &input_set, NULL, NULL, &timeout); } else nfds = select(http->fd + 1, &input_set, NULL, NULL, NULL); DEBUG_printf(("6_httpWait: select() returned %d...", nfds)); } # ifdef WIN32 while (nfds < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)); # else while (nfds < 0 && (errno == EINTR || errno == EAGAIN)); # endif /* WIN32 */ #endif /* HAVE_POLL */ DEBUG_printf(("5_httpWait: returning with nfds=%d, errno=%d...", nfds, errno)); return (nfds > 0); } /* * 'httpWait()' - Wait for data available on a connection. * * @since CUPS 1.1.19/macOS 10.3@ */ int /* O - 1 if data is available, 0 otherwise */ httpWait(http_t *http, /* I - HTTP connection */ int msec) /* I - Milliseconds to wait */ { /* * First see if there is data in the buffer... */ DEBUG_printf(("2httpWait(http=%p, msec=%d)", (void *)http, msec)); if (http == NULL) return (0); if (http->used) { DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready."); return (1); } #ifdef HAVE_LIBZ if (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in > 0) { DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready."); return (1); } #endif /* HAVE_LIBZ */ /* * Flush pending data, if any... */ if (http->wused) { DEBUG_puts("3httpWait: Flushing write buffer."); if (httpFlushWrite(http) < 0) return (0); } /* * If not, check the SSL/TLS buffers and do a select() on the connection... */ return (_httpWait(http, msec, 1)); } /* * 'httpWrite()' - Write data to a HTTP connection. * * This function is deprecated. Use the httpWrite2() function which can * write more than 2GB of data. * * @deprecated@ @exclude all@ */ int /* O - Number of bytes written */ httpWrite(http_t *http, /* I - HTTP connection */ const char *buffer, /* I - Buffer for data */ int length) /* I - Number of bytes to write */ { return ((int)httpWrite2(http, buffer, (size_t)length)); } /* * 'httpWrite2()' - Write data to a HTTP connection. * * @since CUPS 1.2/macOS 10.5@ */ ssize_t /* O - Number of bytes written */ httpWrite2(http_t *http, /* I - HTTP connection */ const char *buffer, /* I - Buffer for data */ size_t length) /* I - Number of bytes to write */ { ssize_t bytes; /* Bytes written */ DEBUG_printf(("httpWrite2(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length)); /* * Range check input... */ if (!http || !buffer) { DEBUG_puts("1httpWrite2: Returning -1 due to bad input."); return (-1); } /* * Mark activity on the connection... */ http->activity = time(NULL); /* * Buffer small writes for better performance... */ #ifdef HAVE_LIBZ if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE) { DEBUG_printf(("1httpWrite2: http->coding=%d", http->coding)); if (length == 0) { http_content_coding_finish(http); bytes = 0; } else { size_t slen; /* Bytes to write */ ssize_t sret; /* Bytes written */ http->stream.next_in = (Bytef *)buffer; http->stream.avail_in = (uInt)length; while (deflate(&(http->stream), Z_NO_FLUSH) == Z_OK) { DEBUG_printf(("1httpWrite2: avail_out=%d", http->stream.avail_out)); if (http->stream.avail_out > 0) continue; slen = _HTTP_MAX_SBUFFER - http->stream.avail_out; DEBUG_printf(("1httpWrite2: Writing intermediate chunk, len=%d", (int)slen)); if (slen > 0 && http->data_encoding == HTTP_ENCODING_CHUNKED) sret = http_write_chunk(http, (char *)http->sbuffer, slen); else if (slen > 0) sret = http_write(http, (char *)http->sbuffer, slen); else sret = 0; if (sret < 0) { DEBUG_puts("1httpWrite2: Unable to write, returning -1."); return (-1); } http->stream.next_out = (Bytef *)http->sbuffer; http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER; } bytes = (ssize_t)length; } } else #endif /* HAVE_LIBZ */ if (length > 0) { if (http->wused && (length + (size_t)http->wused) > sizeof(http->wbuffer)) { DEBUG_printf(("2httpWrite2: Flushing buffer (wused=%d, length=" CUPS_LLFMT ")", http->wused, CUPS_LLCAST length)); httpFlushWrite(http); } if ((length + (size_t)http->wused) <= sizeof(http->wbuffer) && length < sizeof(http->wbuffer)) { /* * Write to buffer... */ DEBUG_printf(("2httpWrite2: Copying " CUPS_LLFMT " bytes to wbuffer...", CUPS_LLCAST length)); memcpy(http->wbuffer + http->wused, buffer, length); http->wused += (int)length; bytes = (ssize_t)length; } else { /* * Otherwise write the data directly... */ DEBUG_printf(("2httpWrite2: Writing " CUPS_LLFMT " bytes to socket...", CUPS_LLCAST length)); if (http->data_encoding == HTTP_ENCODING_CHUNKED) bytes = (ssize_t)http_write_chunk(http, buffer, length); else bytes = (ssize_t)http_write(http, buffer, length); DEBUG_printf(("2httpWrite2: Wrote " CUPS_LLFMT " bytes...", CUPS_LLCAST bytes)); } if (http->data_encoding == HTTP_ENCODING_LENGTH) http->data_remaining -= bytes; } else bytes = 0; /* * Handle end-of-request processing... */ if ((http->data_encoding == HTTP_ENCODING_CHUNKED && length == 0) || (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0)) { /* * Finished with the transfer; unless we are sending POST or PUT * data, go idle... */ #ifdef HAVE_LIBZ if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE) http_content_coding_finish(http); #endif /* HAVE_LIBZ */ if (http->wused) { if (httpFlushWrite(http) < 0) return (-1); } if (http->data_encoding == HTTP_ENCODING_CHUNKED) { /* * Send a 0-length chunk at the end of the request... */ http_write(http, "0\r\n\r\n", 5); /* * Reset the data state... */ http->data_encoding = HTTP_ENCODING_FIELDS; http->data_remaining = 0; } if (http->state == HTTP_STATE_POST_RECV) http->state ++; else if (http->state == HTTP_STATE_POST_SEND || http->state == HTTP_STATE_GET_SEND) http->state = HTTP_STATE_WAITING; else http->state = HTTP_STATE_STATUS; DEBUG_printf(("2httpWrite2: Changed state to %s.", httpStateString(http->state))); } DEBUG_printf(("1httpWrite2: Returning " CUPS_LLFMT ".", CUPS_LLCAST bytes)); return (bytes); } /* * 'httpWriteResponse()' - Write a HTTP response to a client connection. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - 0 on success, -1 on error */ httpWriteResponse(http_t *http, /* I - HTTP connection */ http_status_t status) /* I - Status code */ { http_encoding_t old_encoding; /* Old data_encoding value */ off_t old_remaining; /* Old data_remaining value */ /* * Range check input... */ DEBUG_printf(("httpWriteResponse(http=%p, status=%d)", (void *)http, status)); if (!http || status < HTTP_STATUS_CONTINUE) { DEBUG_puts("1httpWriteResponse: Bad input."); return (-1); } /* * Set the various standard fields if they aren't already... */ if (!http->fields[HTTP_FIELD_DATE]) httpSetField(http, HTTP_FIELD_DATE, httpGetDateString(time(NULL))); if (status >= HTTP_STATUS_BAD_REQUEST && http->keep_alive) { http->keep_alive = HTTP_KEEPALIVE_OFF; httpSetField(http, HTTP_FIELD_KEEP_ALIVE, ""); } if (http->version == HTTP_VERSION_1_1) { if (!http->fields[HTTP_FIELD_CONNECTION]) { if (http->keep_alive) httpSetField(http, HTTP_FIELD_CONNECTION, "Keep-Alive"); else httpSetField(http, HTTP_FIELD_CONNECTION, "close"); } if (http->keep_alive && !http->fields[HTTP_FIELD_KEEP_ALIVE]) httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "timeout=10"); } #ifdef HAVE_SSL if (status == HTTP_STATUS_UPGRADE_REQUIRED || status == HTTP_STATUS_SWITCHING_PROTOCOLS) { if (!http->fields[HTTP_FIELD_CONNECTION]) httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade"); if (!http->fields[HTTP_FIELD_UPGRADE]) httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0"); if (!http->fields[HTTP_FIELD_CONTENT_LENGTH]) httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, "0"); } #endif /* HAVE_SSL */ if (!http->fields[HTTP_FIELD_SERVER]) httpSetField(http, HTTP_FIELD_SERVER, http->default_fields[HTTP_FIELD_SERVER] ? http->default_fields[HTTP_FIELD_SERVER] : CUPS_MINIMAL); /* * Set the Accept-Encoding field if it isn't already... */ if (!http->fields[HTTP_FIELD_ACCEPT_ENCODING]) httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, http->default_fields[HTTP_FIELD_ACCEPT_ENCODING] ? http->default_fields[HTTP_FIELD_ACCEPT_ENCODING] : #ifdef HAVE_LIBZ "gzip, deflate, identity"); #else "identity"); #endif /* HAVE_LIBZ */ /* * Send the response header... */ old_encoding = http->data_encoding; old_remaining = http->data_remaining; http->data_encoding = HTTP_ENCODING_FIELDS; if (httpPrintf(http, "HTTP/%d.%d %d %s\r\n", http->version / 100, http->version % 100, (int)status, httpStatus(status)) < 0) { http->status = HTTP_STATUS_ERROR; return (-1); } if (status != HTTP_STATUS_CONTINUE) { /* * 100 Continue doesn't have the rest of the response headers... */ int i; /* Looping var */ const char *value; /* Field value */ for (i = 0; i < HTTP_FIELD_MAX; i ++) { if ((value = httpGetField(http, i)) != NULL && *value) { if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } } } if (http->cookie) { if (strchr(http->cookie, ';')) { if (httpPrintf(http, "Set-Cookie: %s\r\n", http->cookie) < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } } else if (httpPrintf(http, "Set-Cookie: %s; path=/; httponly;%s\r\n", http->cookie, http->tls ? " secure;" : "") < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } } /* * "Click-jacking" defense (STR #4492)... */ if (httpPrintf(http, "X-Frame-Options: DENY\r\n" "Content-Security-Policy: frame-ancestors 'none'\r\n") < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } } if (httpWrite2(http, "\r\n", 2) < 2) { http->status = HTTP_STATUS_ERROR; return (-1); } if (httpFlushWrite(http) < 0) { http->status = HTTP_STATUS_ERROR; return (-1); } if (status == HTTP_STATUS_CONTINUE || status == HTTP_STATUS_SWITCHING_PROTOCOLS) { /* * Restore the old data_encoding and data_length values... */ http->data_encoding = old_encoding; http->data_remaining = old_remaining; if (old_remaining <= INT_MAX) http->_data_remaining = (int)old_remaining; else http->_data_remaining = INT_MAX; } else if (http->state == HTTP_STATE_OPTIONS || http->state == HTTP_STATE_HEAD || http->state == HTTP_STATE_PUT || http->state == HTTP_STATE_TRACE || http->state == HTTP_STATE_CONNECT || http->state == HTTP_STATE_STATUS) { DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, " "was %s.", httpStateString(http->state))); http->state = HTTP_STATE_WAITING; } else { /* * Force data_encoding and data_length to be set according to the response * headers... */ http_set_length(http); if (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0) { DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, " "was %s.", httpStateString(http->state))); http->state = HTTP_STATE_WAITING; return (0); } if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_GET) http->state ++; #ifdef HAVE_LIBZ /* * Then start any content encoding... */ DEBUG_puts("1httpWriteResponse: Calling http_content_coding_start."); http_content_coding_start(http, httpGetField(http, HTTP_FIELD_CONTENT_ENCODING)); #endif /* HAVE_LIBZ */ } return (0); } /* * 'http_add_field()' - Add a value for a HTTP field, appending if needed. */ static void http_add_field(http_t *http, /* I - HTTP connection */ http_field_t field, /* I - HTTP field */ const char *value, /* I - Value string */ int append) /* I - Append value? */ { char temp[1024]; /* Temporary value string */ size_t fieldlen, /* Length of existing value */ valuelen, /* Length of value string */ total; /* Total length of string */ if (field == HTTP_FIELD_HOST) { /* * Special-case for Host: as we don't want a trailing "." on the hostname and * need to bracket IPv6 numeric addresses. */ char *ptr = strchr(value, ':'); if (value[0] != '[' && ptr && strchr(ptr + 1, ':')) { /* * Bracket IPv6 numeric addresses... * * This is slightly inefficient (basically copying twice), but is an edge * case and not worth optimizing... */ snprintf(temp, sizeof(temp), "[%s]", value); value = temp; } else if (*value) { /* * Check for a trailing dot on the hostname... */ strlcpy(temp, value, sizeof(temp)); value = temp; ptr = temp + strlen(temp) - 1; if (*ptr == '.') *ptr = '\0'; } } if (append && field != HTTP_FIELD_ACCEPT_ENCODING && field != HTTP_FIELD_ACCEPT_LANGUAGE && field != HTTP_FIELD_ACCEPT_RANGES && field != HTTP_FIELD_ALLOW && field != HTTP_FIELD_LINK && field != HTTP_FIELD_TRANSFER_ENCODING && field != HTTP_FIELD_UPGRADE && field != HTTP_FIELD_WWW_AUTHENTICATE) append = 0; if (!append && http->fields[field]) { if (http->fields[field] != http->_fields[field]) free(http->fields[field]); http->fields[field] = NULL; } valuelen = strlen(value); if (!valuelen) { http->_fields[field][0] = '\0'; return; } if (http->fields[field]) { fieldlen = strlen(http->fields[field]); total = fieldlen + 2 + valuelen; } else { fieldlen = 0; total = valuelen; } if (total < HTTP_MAX_VALUE && field < HTTP_FIELD_ACCEPT_ENCODING) { /* * Copy short values to legacy char arrays (maintained for binary * compatibility with CUPS 1.2.x and earlier applications...) */ if (fieldlen) { char combined[HTTP_MAX_VALUE]; /* Combined value string */ snprintf(combined, sizeof(combined), "%s, %s", http->_fields[field], value); value = combined; } strlcpy(http->_fields[field], value, sizeof(http->_fields[field])); http->fields[field] = http->_fields[field]; } else if (fieldlen) { /* * Expand the field value... */ char *combined; /* New value string */ if ((combined = realloc(http->fields[field], total + 1)) != NULL) { http->fields[field] = combined; strlcat(combined, ", ", total + 1); strlcat(combined, value, total + 1); } } else { /* * Allocate the field value... */ http->fields[field] = strdup(value); } #ifdef HAVE_LIBZ if (field == HTTP_FIELD_CONTENT_ENCODING && http->data_encoding != HTTP_ENCODING_FIELDS) { DEBUG_puts("1httpSetField: Calling http_content_coding_start."); http_content_coding_start(http, value); } #endif /* HAVE_LIBZ */ } #ifdef HAVE_LIBZ /* * 'http_content_coding_finish()' - Finish doing any content encoding. */ static void http_content_coding_finish( http_t *http) /* I - HTTP connection */ { int zerr; /* Compression status */ Byte dummy[1]; /* Dummy read buffer */ size_t bytes; /* Number of bytes to write */ DEBUG_printf(("http_content_coding_finish(http=%p)", (void *)http)); DEBUG_printf(("1http_content_coding_finishing: http->coding=%d", http->coding)); switch (http->coding) { case _HTTP_CODING_DEFLATE : case _HTTP_CODING_GZIP : http->stream.next_in = dummy; http->stream.avail_in = 0; do { zerr = deflate(&(http->stream), Z_FINISH); bytes = _HTTP_MAX_SBUFFER - http->stream.avail_out; if (bytes > 0) { DEBUG_printf(("1http_content_coding_finish: Writing trailing chunk, len=%d", (int)bytes)); if (http->data_encoding == HTTP_ENCODING_CHUNKED) http_write_chunk(http, (char *)http->sbuffer, bytes); else http_write(http, (char *)http->sbuffer, bytes); } http->stream.next_out = (Bytef *)http->sbuffer; http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER; } while (zerr == Z_OK); deflateEnd(&(http->stream)); free(http->sbuffer); http->sbuffer = NULL; if (http->wused) httpFlushWrite(http); break; case _HTTP_CODING_INFLATE : case _HTTP_CODING_GUNZIP : inflateEnd(&(http->stream)); free(http->sbuffer); http->sbuffer = NULL; break; default : break; } http->coding = _HTTP_CODING_IDENTITY; } /* * 'http_content_coding_start()' - Start doing content encoding. */ static void http_content_coding_start( http_t *http, /* I - HTTP connection */ const char *value) /* I - Value of Content-Encoding */ { int zerr; /* Error/status */ _http_coding_t coding; /* Content coding value */ DEBUG_printf(("http_content_coding_start(http=%p, value=\"%s\")", (void *)http, value)); if (http->coding != _HTTP_CODING_IDENTITY) { DEBUG_printf(("1http_content_coding_start: http->coding already %d.", http->coding)); return; } else if (!strcmp(value, "x-gzip") || !strcmp(value, "gzip")) { if (http->state == HTTP_STATE_GET_SEND || http->state == HTTP_STATE_POST_SEND) coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_GZIP : _HTTP_CODING_GUNZIP; else if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_PUT_RECV) coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_GZIP : _HTTP_CODING_GUNZIP; else { DEBUG_puts("1http_content_coding_start: Not doing content coding."); return; } } else if (!strcmp(value, "x-deflate") || !strcmp(value, "deflate")) { if (http->state == HTTP_STATE_GET_SEND || http->state == HTTP_STATE_POST_SEND) coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_DEFLATE : _HTTP_CODING_INFLATE; else if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_PUT_RECV) coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_DEFLATE : _HTTP_CODING_INFLATE; else { DEBUG_puts("1http_content_coding_start: Not doing content coding."); return; } } else { DEBUG_puts("1http_content_coding_start: Not doing content coding."); return; } memset(&(http->stream), 0, sizeof(http->stream)); switch (coding) { case _HTTP_CODING_DEFLATE : case _HTTP_CODING_GZIP : if (http->wused) httpFlushWrite(http); if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL) { http->status = HTTP_STATUS_ERROR; http->error = errno; return; } /* * Window size for compression is 11 bits - optimal based on PWG Raster * sample files on pwg.org. -11 is raw deflate, 27 is gzip, per ZLIB * documentation. */ if ((zerr = deflateInit2(&(http->stream), Z_DEFAULT_COMPRESSION, Z_DEFLATED, coding == _HTTP_CODING_DEFLATE ? -11 : 27, 7, Z_DEFAULT_STRATEGY)) < Z_OK) { http->status = HTTP_STATUS_ERROR; http->error = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL; return; } http->stream.next_out = (Bytef *)http->sbuffer; http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER; break; case _HTTP_CODING_INFLATE : case _HTTP_CODING_GUNZIP : if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL) { http->status = HTTP_STATUS_ERROR; http->error = errno; return; } /* * Window size for decompression is up to 15 bits (maximum supported). * -15 is raw inflate, 31 is gunzip, per ZLIB documentation. */ if ((zerr = inflateInit2(&(http->stream), coding == _HTTP_CODING_INFLATE ? -15 : 31)) < Z_OK) { free(http->sbuffer); http->sbuffer = NULL; http->status = HTTP_STATUS_ERROR; http->error = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL; return; } http->stream.avail_in = 0; http->stream.next_in = http->sbuffer; break; default : break; } http->coding = coding; DEBUG_printf(("1http_content_coding_start: http->coding now %d.", http->coding)); } #endif /* HAVE_LIBZ */ /* * 'http_create()' - Create an unconnected HTTP connection. */ static http_t * /* O - HTTP connection */ http_create( const char *host, /* I - Hostname */ int port, /* I - Port number */ http_addrlist_t *addrlist, /* I - Address list or @code NULL@ */ int family, /* I - Address family or AF_UNSPEC */ http_encryption_t encryption, /* I - Encryption to use */ int blocking, /* I - 1 for blocking mode */ _http_mode_t mode) /* I - _HTTP_MODE_CLIENT or _SERVER */ { http_t *http; /* New HTTP connection */ char service[255]; /* Service name */ http_addrlist_t *myaddrlist = NULL; /* My address list */ DEBUG_printf(("4http_create(host=\"%s\", port=%d, addrlist=%p, family=%d, encryption=%d, blocking=%d, mode=%d)", host, port, (void *)addrlist, family, encryption, blocking, mode)); if (!host && mode == _HTTP_MODE_CLIENT) return (NULL); httpInitialize(); /* * Lookup the host... */ if (addrlist) { myaddrlist = httpAddrCopyList(addrlist); } else { snprintf(service, sizeof(service), "%d", port); myaddrlist = httpAddrGetList(host, family, service); } if (!myaddrlist) return (NULL); /* * Allocate memory for the structure... */ if ((http = calloc(sizeof(http_t), 1)) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); httpAddrFreeList(addrlist); return (NULL); } /* * Initialize the HTTP data... */ http->mode = mode; http->activity = time(NULL); http->addrlist = myaddrlist; http->blocking = blocking; http->fd = -1; #ifdef HAVE_GSSAPI http->gssctx = GSS_C_NO_CONTEXT; http->gssname = GSS_C_NO_NAME; #endif /* HAVE_GSSAPI */ http->status = HTTP_STATUS_CONTINUE; http->version = HTTP_VERSION_1_1; if (host) strlcpy(http->hostname, host, sizeof(http->hostname)); if (port == 443) /* Always use encryption for https */ http->encryption = HTTP_ENCRYPTION_ALWAYS; else http->encryption = encryption; http_set_wait(http); /* * Return the new structure... */ return (http); } #ifdef DEBUG /* * 'http_debug_hex()' - Do a hex dump of a buffer. */ static void http_debug_hex(const char *prefix, /* I - Prefix for line */ const char *buffer, /* I - Buffer to dump */ int bytes) /* I - Bytes to dump */ { int i, j, /* Looping vars */ ch; /* Current character */ char line[255], /* Line buffer */ *start, /* Start of line after prefix */ *ptr; /* Pointer into line */ if (_cups_debug_fd < 0 || _cups_debug_level < 6) return; DEBUG_printf(("6%s: %d bytes:", prefix, bytes)); snprintf(line, sizeof(line), "6%s: ", prefix); start = line + strlen(line); for (i = 0; i < bytes; i += 16) { for (j = 0, ptr = start; j < 16 && (i + j) < bytes; j ++, ptr += 2) snprintf(ptr, 3, "%02X", buffer[i + j] & 255); while (j < 16) { memcpy(ptr, " ", 3); ptr += 2; j ++; } memcpy(ptr, " ", 3); ptr += 2; for (j = 0; j < 16 && (i + j) < bytes; j ++) { ch = buffer[i + j] & 255; if (ch < ' ' || ch >= 127) ch = '.'; *ptr++ = (char)ch; } *ptr = '\0'; DEBUG_puts(line); } } #endif /* DEBUG */ /* * 'http_read()' - Read a buffer from a HTTP connection. * * This function does the low-level read from the socket, retrying and timing * out as needed. */ static ssize_t /* O - Number of bytes read or -1 on error */ http_read(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Buffer */ size_t length) /* I - Maximum bytes to read */ { ssize_t bytes; /* Bytes read */ DEBUG_printf(("http_read(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length)); if (!http->blocking) { while (!httpWait(http, http->wait_value)) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; DEBUG_puts("2http_read: Timeout."); return (0); } } DEBUG_printf(("2http_read: Reading %d bytes into buffer.", (int)length)); do { #ifdef HAVE_SSL if (http->tls) bytes = _httpTLSRead(http, buffer, (int)length); else #endif /* HAVE_SSL */ bytes = recv(http->fd, buffer, length, 0); if (bytes < 0) { #ifdef WIN32 if (WSAGetLastError() != WSAEINTR) { http->error = WSAGetLastError(); return (-1); } else if (WSAGetLastError() == WSAEWOULDBLOCK) { if (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data)) { http->error = WSAEWOULDBLOCK; return (-1); } } #else DEBUG_printf(("2http_read: %s", strerror(errno))); if (errno == EWOULDBLOCK || errno == EAGAIN) { if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data)) { http->error = errno; return (-1); } else if (!http->timeout_cb && errno != EAGAIN) { http->error = errno; return (-1); } } else if (errno != EINTR) { http->error = errno; return (-1); } #endif /* WIN32 */ } } while (bytes < 0); DEBUG_printf(("2http_read: Read " CUPS_LLFMT " bytes into buffer.", CUPS_LLCAST bytes)); #ifdef DEBUG if (bytes > 0) http_debug_hex("http_read", buffer, (int)bytes); #endif /* DEBUG */ if (bytes < 0) { #ifdef WIN32 if (WSAGetLastError() == WSAEINTR) bytes = 0; else http->error = WSAGetLastError(); #else if (errno == EINTR || (errno == EAGAIN && !http->timeout_cb)) bytes = 0; else http->error = errno; #endif /* WIN32 */ } else if (bytes == 0) { http->error = EPIPE; return (0); } return (bytes); } /* * 'http_read_buffered()' - Do a buffered read from a HTTP connection. * * This function reads data from the HTTP buffer or from the socket, as needed. */ static ssize_t /* O - Number of bytes read or -1 on error */ http_read_buffered(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Buffer */ size_t length) /* I - Maximum bytes to read */ { ssize_t bytes; /* Bytes read */ DEBUG_printf(("http_read_buffered(http=%p, buffer=%p, length=" CUPS_LLFMT ") used=%d", (void *)http, (void *)buffer, CUPS_LLCAST length, http->used)); if (http->used > 0) { if (length > (size_t)http->used) bytes = (ssize_t)http->used; else bytes = (ssize_t)length; DEBUG_printf(("2http_read: Grabbing %d bytes from input buffer.", (int)bytes)); memcpy(buffer, http->buffer, (size_t)bytes); http->used -= (int)bytes; if (http->used > 0) memmove(http->buffer, http->buffer + bytes, (size_t)http->used); } else bytes = http_read(http, buffer, length); return (bytes); } /* * 'http_read_chunk()' - Read a chunk from a HTTP connection. * * This function reads and validates the chunk length, then does a buffered read * returning the number of bytes placed in the buffer. */ static ssize_t /* O - Number of bytes read or -1 on error */ http_read_chunk(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Buffer */ size_t length) /* I - Maximum bytes to read */ { DEBUG_printf(("http_read_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length)); if (http->data_remaining <= 0) { char len[32]; /* Length string */ if (!httpGets(len, sizeof(len), http)) { DEBUG_puts("1http_read_chunk: Could not get chunk length."); return (0); } if (!len[0]) { DEBUG_puts("1http_read_chunk: Blank chunk length, trying again..."); if (!httpGets(len, sizeof(len), http)) { DEBUG_puts("1http_read_chunk: Could not get chunk length."); return (0); } } http->data_remaining = strtoll(len, NULL, 16); if (http->data_remaining < 0) { DEBUG_printf(("1http_read_chunk: Negative chunk length \"%s\" (" CUPS_LLFMT ")", len, CUPS_LLCAST http->data_remaining)); return (0); } DEBUG_printf(("2http_read_chunk: Got chunk length \"%s\" (" CUPS_LLFMT ")", len, CUPS_LLCAST http->data_remaining)); if (http->data_remaining == 0) { /* * 0-length chunk, grab trailing blank line... */ httpGets(len, sizeof(len), http); } } DEBUG_printf(("2http_read_chunk: data_remaining=" CUPS_LLFMT, CUPS_LLCAST http->data_remaining)); if (http->data_remaining <= 0) return (0); else if (length > (size_t)http->data_remaining) length = (size_t)http->data_remaining; return (http_read_buffered(http, buffer, length)); } /* * 'http_send()' - Send a request with all fields and the trailing blank line. */ static int /* O - 0 on success, non-zero on error */ http_send(http_t *http, /* I - HTTP connection */ http_state_t request, /* I - Request code */ const char *uri) /* I - URI */ { int i; /* Looping var */ char buf[1024]; /* Encoded URI buffer */ const char *value; /* Field value */ static const char * const codes[] = /* Request code strings */ { NULL, "OPTIONS", "GET", NULL, "HEAD", "POST", NULL, NULL, "PUT", NULL, "DELETE", "TRACE", "CLOSE", NULL, NULL }; DEBUG_printf(("4http_send(http=%p, request=HTTP_%s, uri=\"%s\")", (void *)http, codes[request], uri)); if (http == NULL || uri == NULL) return (-1); /* * Set the User-Agent field if it isn't already... */ if (!http->fields[HTTP_FIELD_USER_AGENT]) { if (http->default_fields[HTTP_FIELD_USER_AGENT]) httpSetField(http, HTTP_FIELD_USER_AGENT, http->default_fields[HTTP_FIELD_USER_AGENT]); else httpSetField(http, HTTP_FIELD_USER_AGENT, cupsUserAgent()); } /* * Set the Accept-Encoding field if it isn't already... */ if (!http->fields[HTTP_FIELD_ACCEPT_ENCODING] && http->default_fields[HTTP_FIELD_ACCEPT_ENCODING]) httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, http->default_fields[HTTP_FIELD_ACCEPT_ENCODING]); /* * Encode the URI as needed... */ _httpEncodeURI(buf, uri, sizeof(buf)); /* * See if we had an error the last time around; if so, reconnect... */ if (http->fd < 0 || http->status == HTTP_STATUS_ERROR || http->status >= HTTP_STATUS_BAD_REQUEST) { DEBUG_printf(("5http_send: Reconnecting, fd=%d, status=%d, tls_upgrade=%d", http->fd, http->status, http->tls_upgrade)); if (httpReconnect2(http, 30000, NULL)) return (-1); } /* * Flush any written data that is pending... */ if (http->wused) { if (httpFlushWrite(http) < 0) if (httpReconnect2(http, 30000, NULL)) return (-1); } /* * Send the request header... */ http->state = request; http->data_encoding = HTTP_ENCODING_FIELDS; if (request == HTTP_STATE_POST || request == HTTP_STATE_PUT) http->state ++; http->status = HTTP_STATUS_CONTINUE; #ifdef HAVE_SSL if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls) { httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade"); httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0"); } #endif /* HAVE_SSL */ if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } for (i = 0; i < HTTP_FIELD_MAX; i ++) if ((value = httpGetField(http, i)) != NULL && *value) { DEBUG_printf(("5http_send: %s: %s", http_fields[i], value)); if (i == HTTP_FIELD_HOST) { if (httpPrintf(http, "Host: %s:%d\r\n", value, httpAddrPort(http->hostaddr)) < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } } else if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } } if (http->cookie) if (httpPrintf(http, "Cookie: $Version=0; %s\r\n", http->cookie) < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } DEBUG_printf(("5http_send: expect=%d, mode=%d, state=%d", http->expect, http->mode, http->state)); if (http->expect == HTTP_STATUS_CONTINUE && http->mode == _HTTP_MODE_CLIENT && (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_PUT_RECV)) if (httpPrintf(http, "Expect: 100-continue\r\n") < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } if (httpPrintf(http, "\r\n") < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } if (httpFlushWrite(http) < 0) return (-1); http_set_length(http); httpClearFields(http); /* * The Kerberos and AuthRef authentication strings can only be used once... */ if (http->fields[HTTP_FIELD_AUTHORIZATION] && http->authstring && (!strncmp(http->authstring, "Negotiate", 9) || !strncmp(http->authstring, "AuthRef", 7))) { http->_authstring[0] = '\0'; if (http->authstring != http->_authstring) free(http->authstring); http->authstring = http->_authstring; } return (0); } /* * 'http_set_length()' - Set the data_encoding and data_remaining values. */ static off_t /* O - Remainder or -1 on error */ http_set_length(http_t *http) /* I - Connection */ { off_t remaining; /* Remainder */ DEBUG_printf(("http_set_length(http=%p) mode=%d state=%s", (void *)http, http->mode, httpStateString(http->state))); if ((remaining = httpGetLength2(http)) >= 0) { if (http->mode == _HTTP_MODE_SERVER && http->state != HTTP_STATE_GET_SEND && http->state != HTTP_STATE_PUT && http->state != HTTP_STATE_POST && http->state != HTTP_STATE_POST_SEND) { DEBUG_puts("1http_set_length: Not setting data_encoding/remaining."); return (remaining); } if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_TRANSFER_ENCODING), "chunked")) { DEBUG_puts("1http_set_length: Setting data_encoding to " "HTTP_ENCODING_CHUNKED."); http->data_encoding = HTTP_ENCODING_CHUNKED; } else { DEBUG_puts("1http_set_length: Setting data_encoding to " "HTTP_ENCODING_LENGTH."); http->data_encoding = HTTP_ENCODING_LENGTH; } DEBUG_printf(("1http_set_length: Setting data_remaining to " CUPS_LLFMT ".", CUPS_LLCAST remaining)); http->data_remaining = remaining; if (remaining <= INT_MAX) http->_data_remaining = (int)remaining; else http->_data_remaining = INT_MAX; } return (remaining); } /* * 'http_set_timeout()' - Set the socket timeout values. */ static void http_set_timeout(int fd, /* I - File descriptor */ double timeout) /* I - Timeout in seconds */ { #ifdef WIN32 DWORD tv = (DWORD)(timeout * 1000); /* Timeout in milliseconds */ setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv)); setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv)); #else struct timeval tv; /* Timeout in secs and usecs */ tv.tv_sec = (int)timeout; tv.tv_usec = (int)(1000000 * fmod(timeout, 1.0)); setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv)); setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv)); #endif /* WIN32 */ } /* * 'http_set_wait()' - Set the default wait value for reads. */ static void http_set_wait(http_t *http) /* I - HTTP connection */ { if (http->blocking) { http->wait_value = (int)(http->timeout_value * 1000); if (http->wait_value <= 0) http->wait_value = 60000; } else http->wait_value = 10000; } #ifdef HAVE_SSL /* * 'http_tls_upgrade()' - Force upgrade to TLS encryption. */ static int /* O - Status of connection */ http_tls_upgrade(http_t *http) /* I - HTTP connection */ { int ret; /* Return value */ http_t myhttp; /* Local copy of HTTP data */ DEBUG_printf(("7http_tls_upgrade(%p)", (void *)http)); /* * Flush the connection to make sure any previous "Upgrade" message * has been read. */ httpFlush(http); /* * Copy the HTTP data to a local variable so we can do the OPTIONS * request without interfering with the existing request data... */ memcpy(&myhttp, http, sizeof(myhttp)); /* * Send an OPTIONS request to the server, requiring SSL or TLS * encryption on the link... */ http->tls_upgrade = 1; memset(http->fields, 0, sizeof(http->fields)); http->expect = (http_status_t)0; if (http->hostname[0] == '/') httpSetField(http, HTTP_FIELD_HOST, "localhost"); else httpSetField(http, HTTP_FIELD_HOST, http->hostname); httpSetField(http, HTTP_FIELD_CONNECTION, "upgrade"); httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0"); if ((ret = httpOptions(http, "*")) == 0) { /* * Wait for the secure connection... */ while (httpUpdate(http) == HTTP_STATUS_CONTINUE); } /* * Restore the HTTP request data... */ memcpy(http->_fields, myhttp._fields, sizeof(http->_fields)); memcpy(http->fields, myhttp.fields, sizeof(http->fields)); http->data_encoding = myhttp.data_encoding; http->data_remaining = myhttp.data_remaining; http->_data_remaining = myhttp._data_remaining; http->expect = myhttp.expect; http->digest_tries = myhttp.digest_tries; http->tls_upgrade = 0; /* * See if we actually went secure... */ if (!http->tls) { /* * Server does not support HTTP upgrade... */ DEBUG_puts("8http_tls_upgrade: Server does not support HTTP upgrade!"); _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Encryption is not supported."), 1); httpAddrClose(NULL, http->fd); http->fd = -1; return (-1); } else return (ret); } #endif /* HAVE_SSL */ /* * 'http_write()' - Write a buffer to a HTTP connection. */ static ssize_t /* O - Number of bytes written */ http_write(http_t *http, /* I - HTTP connection */ const char *buffer, /* I - Buffer for data */ size_t length) /* I - Number of bytes to write */ { ssize_t tbytes, /* Total bytes sent */ bytes; /* Bytes sent */ DEBUG_printf(("2http_write(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length)); http->error = 0; tbytes = 0; while (length > 0) { DEBUG_printf(("3http_write: About to write %d bytes.", (int)length)); if (http->timeout_cb) { #ifdef HAVE_POLL struct pollfd pfd; /* Polled file descriptor */ #else fd_set output_set; /* Output ready for write? */ struct timeval timeout; /* Timeout value */ #endif /* HAVE_POLL */ int nfds; /* Result from select()/poll() */ do { #ifdef HAVE_POLL pfd.fd = http->fd; pfd.events = POLLOUT; while ((nfds = poll(&pfd, 1, http->wait_value)) < 0 && (errno == EINTR || errno == EAGAIN)) /* do nothing */; #else do { FD_ZERO(&output_set); FD_SET(http->fd, &output_set); timeout.tv_sec = http->wait_value / 1000; timeout.tv_usec = 1000 * (http->wait_value % 1000); nfds = select(http->fd + 1, NULL, &output_set, NULL, &timeout); } # ifdef WIN32 while (nfds < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)); # else while (nfds < 0 && (errno == EINTR || errno == EAGAIN)); # endif /* WIN32 */ #endif /* HAVE_POLL */ if (nfds < 0) { http->error = errno; return (-1); } else if (nfds == 0 && !(*http->timeout_cb)(http, http->timeout_data)) { #ifdef WIN32 http->error = WSAEWOULDBLOCK; #else http->error = EWOULDBLOCK; #endif /* WIN32 */ return (-1); } } while (nfds <= 0); } #ifdef HAVE_SSL if (http->tls) bytes = _httpTLSWrite(http, buffer, (int)length); else #endif /* HAVE_SSL */ bytes = send(http->fd, buffer, length, 0); DEBUG_printf(("3http_write: Write of " CUPS_LLFMT " bytes returned " CUPS_LLFMT ".", CUPS_LLCAST length, CUPS_LLCAST bytes)); if (bytes < 0) { #ifdef WIN32 if (WSAGetLastError() == WSAEINTR) continue; else if (WSAGetLastError() == WSAEWOULDBLOCK) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; http->error = WSAGetLastError(); } else if (WSAGetLastError() != http->error && WSAGetLastError() != WSAECONNRESET) { http->error = WSAGetLastError(); continue; } #else if (errno == EINTR) continue; else if (errno == EWOULDBLOCK || errno == EAGAIN) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; else if (!http->timeout_cb && errno == EAGAIN) continue; http->error = errno; } else if (errno != http->error && errno != ECONNRESET) { http->error = errno; continue; } #endif /* WIN32 */ DEBUG_printf(("3http_write: error writing data (%s).", strerror(http->error))); return (-1); } buffer += bytes; tbytes += bytes; length -= (size_t)bytes; } #ifdef DEBUG http_debug_hex("http_write", buffer - tbytes, (int)tbytes); #endif /* DEBUG */ DEBUG_printf(("3http_write: Returning " CUPS_LLFMT ".", CUPS_LLCAST tbytes)); return (tbytes); } /* * 'http_write_chunk()' - Write a chunked buffer. */ static ssize_t /* O - Number bytes written */ http_write_chunk(http_t *http, /* I - HTTP connection */ const char *buffer, /* I - Buffer to write */ size_t length) /* I - Length of buffer */ { char header[16]; /* Chunk header */ ssize_t bytes; /* Bytes written */ DEBUG_printf(("7http_write_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length)); /* * Write the chunk header, data, and trailer. */ snprintf(header, sizeof(header), "%x\r\n", (unsigned)length); if (http_write(http, header, strlen(header)) < 0) { DEBUG_puts("8http_write_chunk: http_write of length failed."); return (-1); } if ((bytes = http_write(http, buffer, length)) < 0) { DEBUG_puts("8http_write_chunk: http_write of buffer failed."); return (-1); } if (http_write(http, "\r\n", 2) < 0) { DEBUG_puts("8http_write_chunk: http_write of CR LF failed."); return (-1); } return (bytes); } ippsample/cups/debug-private.h0000644000175000017500000000537013240604116015425 0ustar tilltill/* * Private debugging macros for CUPS. * * Copyright 2007-2012 by Apple Inc. * Copyright 1997-2005 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_DEBUG_PRIVATE_H_ # define _CUPS_DEBUG_PRIVATE_H_ /* * Include necessary headers... */ # include /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * The debug macros are used if you compile with DEBUG defined. * * Usage: * * DEBUG_puts("string") * DEBUG_printf(("format string", arg, arg, ...)); * * Note the extra parenthesis around the DEBUG_printf macro... * * Newlines are not required on the end of messages, as both add one when * writing the output. * * If the first character is a digit, then it represents the "log level" of the * message from 0 to 9. The default level is 1. The following defines the * current levels we use: * * 0 = public APIs, other than value accessor functions * 1 = return values for public APIs * 2 = public value accessor APIs, progress for public APIs * 3 = return values for value accessor APIs * 4 = private APIs, progress for value accessor APIs * 5 = return values for private APIs * 6 = progress for private APIs * 7 = static functions * 8 = return values for static functions * 9 = progress for static functions * * The DEBUG_set macro allows an application to programmatically enable (or * disable) debug logging. The arguments correspond to the CUPS_DEBUG_LOG, * CUPS_DEBUG_LEVEL, and CUPS_DEBUG_FILTER environment variables. */ # ifdef DEBUG # ifdef WIN32 # ifdef LIBCUPS2_EXPORTS # define DLLExport __declspec(dllexport) # else # define DLLExport # endif /* LIBCUPS2_EXPORTS */ # else # define DLLExport # endif /* WIN32 */ # define DEBUG_puts(x) _cups_debug_puts(x) # define DEBUG_printf(x) _cups_debug_printf x # define DEBUG_set(logfile,level,filter) _cups_debug_set(logfile,level,filter,1) # else # define DLLExport # define DEBUG_puts(x) # define DEBUG_printf(x) # define DEBUG_set(logfile,level,filter) # endif /* DEBUG */ /* * Prototypes... */ extern int _cups_debug_fd; extern int _cups_debug_level; extern void DLLExport _cups_debug_printf(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2))); extern void DLLExport _cups_debug_puts(const char *s); extern void DLLExport _cups_debug_set(const char *logfile, const char *level, const char *filter, int force); # ifdef WIN32 extern int _cups_gettimeofday(struct timeval *tv, void *tz); # define gettimeofday(a,b) _cups_gettimeofday(a, b) # endif /* WIN32 */ # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_DEBUG_PRIVATE_H_ */ ippsample/cups/utf8demo.txt0000644000175000017500000003332513240604116015013 0ustar tilltillUTF-8 encoded sample plain-text file ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ Markus Kuhn [ˈmaʳkʊs kuːn] — 2002-07-25 The ASCII compatible UTF-8 encoding used in this plain-text file is defined in Unicode, ISO 10646-1, and RFC 2279. Using Unicode/UTF-8, you can write in emails and source code things such as Mathematics and sciences: ∮ E⋅da = Q, n → ∞, ∑ f(i) = ∏ g(i), ⎧⎡⎛┌─────┐⎞⎤⎫ ⎪⎢⎜│a²+b³ ⎟⎥⎪ ∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β), ⎪⎢⎜│───── ⎟⎥⎪ ⎪⎢⎜⎷ c₈ ⎟⎥⎪ ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ, ⎨⎢⎜ ⎟⎥⎬ ⎪⎢⎜ ∞ ⎟⎥⎪ ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (⟦A⟧ ⇔ ⟪B⟫), ⎪⎢⎜ ⎲ ⎟⎥⎪ ⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪ 2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm ⎩⎣⎝i=1 ⎠⎦⎭ Linguistics and dictionaries: ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ] APL: ((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈ Nicer typography in plain text files: ╔══════════════════════════════════════════╗ ║ ║ ║ • ‘single’ and “double” quotes ║ ║ ║ ║ • Curly apostrophes: “We’ve been here” ║ ║ ║ ║ • Latin-1 apostrophe and accents: '´` ║ ║ ║ ║ • ‚deutsche‘ „Anführungszeichen“ ║ ║ ║ ║ • †, ‡, ‰, •, 3–4, —, −5/+5, ™, … ║ ║ ║ ║ • ASCII safety test: 1lI|, 0OD, 8B ║ ║ ╭─────────╮ ║ ║ • the euro symbol: │ 14.95 € │ ║ ║ ╰─────────╯ ║ ╚══════════════════════════════════════════╝ Combining characters: STARGΛ̊TE SG-1, a = v̇ = r̈, a⃑ ⊥ b⃑ Greek (in Polytonic): The Greek anthem: Σὲ γνωρίζω ἀπὸ τὴν κόψη τοῦ σπαθιοῦ τὴν τρομερή, σὲ γνωρίζω ἀπὸ τὴν ὄψη ποὺ μὲ βία μετράει τὴ γῆ. ᾿Απ᾿ τὰ κόκκαλα βγαλμένη τῶν ῾Ελλήνων τὰ ἱερά καὶ σὰν πρῶτα ἀνδρειωμένη χαῖρε, ὦ χαῖρε, ᾿Ελευθεριά! From a speech of Demosthenes in the 4th century BC: Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι, ὅταν τ᾿ εἰς τὰ πράγματα ἀποβλέψω καὶ ὅταν πρὸς τοὺς λόγους οὓς ἀκούω· τοὺς μὲν γὰρ λόγους περὶ τοῦ τιμωρήσασθαι Φίλιππον ὁρῶ γιγνομένους, τὰ δὲ πράγματ᾿ εἰς τοῦτο προήκοντα, ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αὐτοὶ πρότερον κακῶς σκέψασθαι δέον. οὐδέν οὖν ἄλλο μοι δοκοῦσιν οἱ τὰ τοιαῦτα λέγοντες ἢ τὴν ὑπόθεσιν, περὶ ἧς βουλεύεσθαι, οὐχὶ τὴν οὖσαν παριστάντες ὑμῖν ἁμαρτάνειν. ἐγὼ δέ, ὅτι μέν ποτ᾿ ἐξῆν τῇ πόλει καὶ τὰ αὑτῆς ἔχειν ἀσφαλῶς καὶ Φίλιππον τιμωρήσασθαι, καὶ μάλ᾿ ἀκριβῶς οἶδα· ἐπ᾿ ἐμοῦ γάρ, οὐ πάλαι γέγονεν ταῦτ᾿ ἀμφότερα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν προλαβεῖν ἡμῖν εἶναι τὴν πρώτην, ὅπως τοὺς συμμάχους σώσομεν. ἐὰν γὰρ τοῦτο βεβαίως ὑπάρξῃ, τότε καὶ περὶ τοῦ τίνα τιμωρήσεταί τις καὶ ὃν τρόπον ἐξέσται σκοπεῖν· πρὶν δὲ τὴν ἀρχὴν ὀρθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι περὶ τῆς τελευτῆς ὁντινοῦν ποιεῖσθαι λόγον. Δημοσθένους, Γ´ ᾿Ολυνθιακὸς Georgian: From a Unicode conference invitation: გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო კონფერენციაზე დასასწრებად, რომელიც გაიმართება 10-12 მარტს, ქ. მაინცში, გერმანიაში. კონფერენცია შეჰკრებს ერთად მსოფლიოს ექსპერტებს ისეთ დარგებში როგორიცაა ინტერნეტი და Unicode-ი, ინტერნაციონალიზაცია და ლოკალიზაცია, Unicode-ის გამოყენება ოპერაციულ სისტემებსა, და გამოყენებით პროგრამებში, შრიფტებში, ტექსტების დამუშავებასა და მრავალენოვან კომპიუტერულ სისტემებში. Russian: From a Unicode conference invitation: Зарегистрируйтесь сейчас на Десятую Международную Конференцию по Unicode, которая состоится 10-12 марта 1997 года в Майнце в Германии. Конференция соберет широкий круг экспертов по вопросам глобального Интернета и Unicode, локализации и интернационализации, воплощению и применению Unicode в различных операционных системах и программных приложениях, шрифтах, верстке и многоязычных компьютерных системах. Thai (UCS Level 2): Excerpt from a poetry on The Romance of The Three Kingdoms (a Chinese classic 'San Gua'): [----------------------------|------------------------] ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่ สิบสองกษัตริย์ก่อนหน้าแลถัดไป สององค์ไซร้โง่เขลาเบาปัญญา ทรงนับถือขันทีเป็นที่พึ่ง บ้านเมืองจึงวิปริตเป็นนักหนา โฮจิ๋นเรียกทัพทั่วหัวเมืองมา หมายจะฆ่ามดชั่วตัวสำคัญ เหมือนขับไสไล่เสือจากเคหา รับหมาป่าเข้ามาเลยอาสัญ ฝ่ายอ้องอุ้นยุแยกให้แตกกัน ใช้สาวนั้นเป็นชนวนชื่นชวนใจ พลันลิฉุยกุยกีกลับก่อเหตุ ช่างอาเพศจริงหนาฟ้าร้องไห้ ต้องรบราฆ่าฟันจนบรรลัย ฤๅหาใครค้ำชูกู้บรรลังก์ ฯ (The above is a two-column text. If combining characters are handled correctly, the lines of the second column should be aligned with the | character above.) Ethiopian: Proverbs in the Amharic language: ሰማይ አይታረስ ንጉሥ አይከሰስ። ብላ ካለኝ እንደአባቴ በቆመጠኝ። ጌጥ ያለቤቱ ቁምጥና ነው። ደሀ በሕልሙ ቅቤ ባይጠጣ ንጣት በገደለው። የአፍ ወለምታ በቅቤ አይታሽም። አይጥ በበላ ዳዋ ተመታ። ሲተረጉሙ ይደረግሙ። ቀስ በቀስ፥ ዕንቁላል በእግሩ ይሄዳል። ድር ቢያብር አንበሳ ያስር። ሰው እንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርም። እግዜር የከፈተውን ጉሮሮ ሳይዘጋው አይድርም። የጎረቤት ሌባ፥ ቢያዩት ይስቅ ባያዩት ያጠልቅ። ሥራ ከመፍታት ልጄን ላፋታት። ዓባይ ማደሪያ የለው፥ ግንድ ይዞ ይዞራል። የእስላም አገሩ መካ የአሞራ አገሩ ዋርካ። ተንጋሎ ቢተፉ ተመልሶ ባፉ። ወዳጅህ ማር ቢሆን ጨርስህ አትላሰው። እግርህን በፍራሽህ ልክ ዘርጋ። Runes: ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ (Old English, which transcribed into Latin reads 'He cwaeth that he bude thaem lande northweardum with tha Westsae.' and means 'He said that he lived in the northern land near the Western Sea.') Braille: ⡌⠁⠧⠑ ⠼⠁⠒ ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠙⠑⠁⠙⠒ ⠞⠕ ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ ⠊⠎ ⠝⠕ ⠙⠳⠃⠞ ⠱⠁⠞⠑⠧⠻ ⠁⠃⠳⠞ ⠹⠁⠞⠲ ⡹⠑ ⠗⠑⠛⠊⠌⠻ ⠕⠋ ⠙⠊⠎ ⠃⠥⠗⠊⠁⠇ ⠺⠁⠎ ⠎⠊⠛⠝⠫ ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹⠍⠁⠝⠂ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ ⠥⠝⠙⠻⠞⠁⠅⠻⠂ ⠁⠝⠙ ⠹⠑ ⠡⠊⠑⠋ ⠍⠳⠗⠝⠻⠲ ⡎⠊⠗⠕⠕⠛⠑ ⠎⠊⠛⠝⠫ ⠊⠞⠲ ⡁⠝⠙ ⡎⠊⠗⠕⠕⠛⠑⠰⠎ ⠝⠁⠍⠑ ⠺⠁⠎ ⠛⠕⠕⠙ ⠥⠏⠕⠝ ⠰⡡⠁⠝⠛⠑⠂ ⠋⠕⠗ ⠁⠝⠹⠹⠔⠛ ⠙⠑ ⠡⠕⠎⠑ ⠞⠕ ⠏⠥⠞ ⠙⠊⠎ ⠙⠁⠝⠙ ⠞⠕⠲ ⡕⠇⠙ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞ ⠍⠑⠁⠝ ⠞⠕ ⠎⠁⠹ ⠹⠁⠞ ⡊ ⠅⠝⠪⠂ ⠕⠋ ⠍⠹ ⠪⠝ ⠅⠝⠪⠇⠫⠛⠑⠂ ⠱⠁⠞ ⠹⠻⠑ ⠊⠎ ⠏⠜⠞⠊⠊⠥⠇⠜⠇⠹ ⠙⠑⠁⠙ ⠁⠃⠳⠞ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡊ ⠍⠊⠣⠞ ⠙⠁⠧⠑ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ ⠍⠹⠎⠑⠇⠋⠂ ⠞⠕ ⠗⠑⠛⠜⠙ ⠁ ⠊⠕⠋⠋⠔⠤⠝⠁⠊⠇ ⠁⠎ ⠹⠑ ⠙⠑⠁⠙⠑⠌ ⠏⠊⠑⠊⠑ ⠕⠋ ⠊⠗⠕⠝⠍⠕⠝⠛⠻⠹ ⠔ ⠹⠑ ⠞⠗⠁⠙⠑⠲ ⡃⠥⠞ ⠹⠑ ⠺⠊⠎⠙⠕⠍ ⠕⠋ ⠳⠗ ⠁⠝⠊⠑⠌⠕⠗⠎ ⠊⠎ ⠔ ⠹⠑ ⠎⠊⠍⠊⠇⠑⠆ ⠁⠝⠙ ⠍⠹ ⠥⠝⠙⠁⠇⠇⠪⠫ ⠙⠁⠝⠙⠎ ⠩⠁⠇⠇ ⠝⠕⠞ ⠙⠊⠌⠥⠗⠃ ⠊⠞⠂ ⠕⠗ ⠹⠑ ⡊⠳⠝⠞⠗⠹⠰⠎ ⠙⠕⠝⠑ ⠋⠕⠗⠲ ⡹⠳ ⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ ⠏⠻⠍⠊⠞ ⠍⠑ ⠞⠕ ⠗⠑⠏⠑⠁⠞⠂ ⠑⠍⠏⠙⠁⠞⠊⠊⠁⠇⠇⠹⠂ ⠹⠁⠞ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ (The first couple of paragraphs of "A Christmas Carol" by Dickens) Compact font selection example text: ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789 abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ –—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд ∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi?⑀₂ἠḂӥẄɐː⍎אԱა Greetings in various languages: Hello world, Καλημέρα κόσμε, コンニチハ Box drawing alignment tests: █ ▉ ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳ ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳ ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳ ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳ ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎ ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏ ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ ▗▄▖▛▀▜ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█ ▝▀▘▙▄▟ ippsample/cups/testi18n.c0000644000175000017500000003370613240604116014345 0ustar tilltill/* * Internationalization test for CUPS. * * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "string-private.h" #include "language-private.h" #include #include #include /* * Local globals... */ static const char * const lang_encodings[] = { /* Encoding strings */ "us-ascii", "iso-8859-1", "iso-8859-2", "iso-8859-3", "iso-8859-4", "iso-8859-5", "iso-8859-6", "iso-8859-7", "iso-8859-8", "iso-8859-9", "iso-8859-10", "utf-8", "iso-8859-13", "iso-8859-14", "iso-8859-15", "windows-874", "windows-1250", "windows-1251", "windows-1252", "windows-1253", "windows-1254", "windows-1255", "windows-1256", "windows-1257", "windows-1258", "koi8-r", "koi8-u", "iso-8859-11", "iso-8859-16", "mac-roman", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "windows-932", "windows-936", "windows-949", "windows-950", "windows-1361", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "euc-cn", "euc-jp", "euc-kr", "euc-tw", "jis-x0213" }; /* * Local functions... */ static void print_utf8(const char *msg, const cups_utf8_t *src); /* * 'main()' - Main entry for internationalization test module. */ int /* O - Exit code */ main(int argc, /* I - Argument Count */ char *argv[]) /* I - Arguments */ { FILE *fp; /* File pointer */ int count; /* File line counter */ int status, /* Status of current test */ errors; /* Error count */ char line[1024]; /* File line source string */ int len; /* Length (count) of string */ char legsrc[1024], /* Legacy source string */ legdest[1024], /* Legacy destination string */ *legptr; /* Pointer into legacy string */ cups_utf8_t utf8latin[] = /* UTF-8 Latin-1 source */ { 0x41, 0x20, 0x21, 0x3D, 0x20, 0xC3, 0x84, 0x2E, 0x00 }; /* "A != ." - use ISO 8859-1 */ cups_utf8_t utf8repla[] = /* UTF-8 Latin-1 replacement */ { 0x41, 0x20, 0xE2, 0x89, 0xA2, 0x20, 0xC3, 0x84, 0x2E, 0x00 }; /* "A ." */ cups_utf8_t utf8greek[] = /* UTF-8 Greek source string */ { 0x41, 0x20, 0x21, 0x3D, 0x20, 0xCE, 0x91, 0x2E, 0x00 }; /* "A != ." - use ISO 8859-7 */ cups_utf8_t utf8japan[] = /* UTF-8 Japanese source */ { 0x41, 0x20, 0x21, 0x3D, 0x20, 0xEE, 0x9C, 0x80, 0x2E, 0x00 }; /* "A != ." - use Windows 932 or EUC-JP */ cups_utf8_t utf8taiwan[] = /* UTF-8 Chinese source */ { 0x41, 0x20, 0x21, 0x3D, 0x20, 0xE4, 0xB9, 0x82, 0x2E, 0x00 }; /* "A != ." - use Windows 950 (Big5) or EUC-TW */ cups_utf8_t utf8dest[1024]; /* UTF-8 destination string */ cups_utf32_t utf32dest[1024]; /* UTF-32 destination string */ if (argc > 1) { int i; /* Looping var */ cups_encoding_t encoding; /* Source encoding */ if (argc != 3) { puts("Usage: ./testi18n [filename charset]"); return (1); } if ((fp = fopen(argv[1], "rb")) == NULL) { perror(argv[1]); return (1); } for (i = 0, encoding = CUPS_AUTO_ENCODING; i < (int)(sizeof(lang_encodings) / sizeof(lang_encodings[0])); i ++) if (!_cups_strcasecmp(lang_encodings[i], argv[2])) { encoding = (cups_encoding_t)i; break; } if (encoding == CUPS_AUTO_ENCODING) { fprintf(stderr, "%s: Unknown character set!\n", argv[2]); return (1); } while (fgets(line, sizeof(line), fp)) { if (cupsCharsetToUTF8(utf8dest, line, sizeof(utf8dest), encoding) < 0) { fprintf(stderr, "%s: Unable to convert line: %s", argv[1], line); return (1); } fputs((char *)utf8dest, stdout); } fclose(fp); return (0); } /* * Start with some conversion tests from a UTF-8 test file. */ errors = 0; if ((fp = fopen("utf8demo.txt", "rb")) == NULL) { perror("utf8demo.txt"); return (1); } /* * cupsUTF8ToUTF32 */ fputs("cupsUTF8ToUTF32 of utfdemo.txt: ", stdout); for (count = 0, status = 0; fgets(line, sizeof(line), fp);) { count ++; if (cupsUTF8ToUTF32(utf32dest, (cups_utf8_t *)line, 1024) < 0) { printf("FAIL (UTF-8 to UTF-32 on line %d)\n", count); errors ++; status = 1; break; } } if (!status) puts("PASS"); /* * cupsUTF8ToCharset(CUPS_EUC_JP) */ fputs("cupsUTF8ToCharset(CUPS_EUC_JP) of utfdemo.txt: ", stdout); rewind(fp); for (count = 0, status = 0; fgets(line, sizeof(line), fp);) { count ++; len = cupsUTF8ToCharset(legdest, (cups_utf8_t *)line, 1024, CUPS_EUC_JP); if (len < 0) { printf("FAIL (UTF-8 to EUC-JP on line %d)\n", count); errors ++; status = 1; break; } } if (!status) puts("PASS"); fclose(fp); /* * Test UTF-8 to legacy charset (ISO 8859-1)... */ fputs("cupsUTF8ToCharset(CUPS_ISO8859_1): ", stdout); legdest[0] = 0; len = cupsUTF8ToCharset(legdest, utf8latin, 1024, CUPS_ISO8859_1); if (len < 0) { printf("FAIL (len=%d)\n", len); errors ++; } else puts("PASS"); /* * cupsCharsetToUTF8 */ fputs("cupsCharsetToUTF8(CUPS_ISO8859_1): ", stdout); strlcpy(legsrc, legdest, sizeof(legsrc)); len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_ISO8859_1); if ((size_t)len != strlen((char *)utf8latin)) { printf("FAIL (len=%d, expected %d)\n", len, (int)strlen((char *)utf8latin)); print_utf8(" utf8latin", utf8latin); print_utf8(" utf8dest", utf8dest); errors ++; } else if (memcmp(utf8latin, utf8dest, (size_t)len)) { puts("FAIL (results do not match)"); print_utf8(" utf8latin", utf8latin); print_utf8(" utf8dest", utf8dest); errors ++; } else if (cupsUTF8ToCharset(legdest, utf8repla, 1024, CUPS_ISO8859_1) < 0) { puts("FAIL (replacement characters do not work!)"); errors ++; } else puts("PASS"); /* * Test UTF-8 to/from legacy charset (ISO 8859-7)... */ fputs("cupsUTF8ToCharset(CUPS_ISO8859_7): ", stdout); if (cupsUTF8ToCharset(legdest, utf8greek, 1024, CUPS_ISO8859_7) < 0) { puts("FAIL"); errors ++; } else { for (legptr = legdest; *legptr && *legptr != '?'; legptr ++); if (*legptr) { puts("FAIL (unknown character)"); errors ++; } else puts("PASS"); } fputs("cupsCharsetToUTF8(CUPS_ISO8859_7): ", stdout); strlcpy(legsrc, legdest, sizeof(legsrc)); len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_ISO8859_7); if ((size_t)len != strlen((char *)utf8greek)) { printf("FAIL (len=%d, expected %d)\n", len, (int)strlen((char *)utf8greek)); print_utf8(" utf8greek", utf8greek); print_utf8(" utf8dest", utf8dest); errors ++; } else if (memcmp(utf8greek, utf8dest, (size_t)len)) { puts("FAIL (results do not match)"); print_utf8(" utf8greek", utf8greek); print_utf8(" utf8dest", utf8dest); errors ++; } else puts("PASS"); /* * Test UTF-8 to/from legacy charset (Windows 932)... */ fputs("cupsUTF8ToCharset(CUPS_WINDOWS_932): ", stdout); if (cupsUTF8ToCharset(legdest, utf8japan, 1024, CUPS_WINDOWS_932) < 0) { puts("FAIL"); errors ++; } else { for (legptr = legdest; *legptr && *legptr != '?'; legptr ++); if (*legptr) { puts("FAIL (unknown character)"); errors ++; } else puts("PASS"); } fputs("cupsCharsetToUTF8(CUPS_WINDOWS_932): ", stdout); strlcpy(legsrc, legdest, sizeof(legsrc)); len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_WINDOWS_932); if ((size_t)len != strlen((char *)utf8japan)) { printf("FAIL (len=%d, expected %d)\n", len, (int)strlen((char *)utf8japan)); print_utf8(" utf8japan", utf8japan); print_utf8(" utf8dest", utf8dest); errors ++; } else if (memcmp(utf8japan, utf8dest, (size_t)len)) { puts("FAIL (results do not match)"); print_utf8(" utf8japan", utf8japan); print_utf8(" utf8dest", utf8dest); errors ++; } else puts("PASS"); /* * Test UTF-8 to/from legacy charset (EUC-JP)... */ fputs("cupsUTF8ToCharset(CUPS_EUC_JP): ", stdout); if (cupsUTF8ToCharset(legdest, utf8japan, 1024, CUPS_EUC_JP) < 0) { puts("FAIL"); errors ++; } else { for (legptr = legdest; *legptr && *legptr != '?'; legptr ++); if (*legptr) { puts("FAIL (unknown character)"); errors ++; } else puts("PASS"); } #ifndef __linux fputs("cupsCharsetToUTF8(CUPS_EUC_JP): ", stdout); strlcpy(legsrc, legdest, sizeof(legsrc)); len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_EUC_JP); if ((size_t)len != strlen((char *)utf8japan)) { printf("FAIL (len=%d, expected %d)\n", len, (int)strlen((char *)utf8japan)); print_utf8(" utf8japan", utf8japan); print_utf8(" utf8dest", utf8dest); errors ++; } else if (memcmp(utf8japan, utf8dest, (size_t)len)) { puts("FAIL (results do not match)"); print_utf8(" utf8japan", utf8japan); print_utf8(" utf8dest", utf8dest); errors ++; } else puts("PASS"); #endif /* !__linux */ /* * Test UTF-8 to/from legacy charset (Windows 950)... */ fputs("cupsUTF8ToCharset(CUPS_WINDOWS_950): ", stdout); if (cupsUTF8ToCharset(legdest, utf8taiwan, 1024, CUPS_WINDOWS_950) < 0) { puts("FAIL"); errors ++; } else { for (legptr = legdest; *legptr && *legptr != '?'; legptr ++); if (*legptr) { puts("FAIL (unknown character)"); errors ++; } else puts("PASS"); } fputs("cupsCharsetToUTF8(CUPS_WINDOWS_950): ", stdout); strlcpy(legsrc, legdest, sizeof(legsrc)); len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_WINDOWS_950); if ((size_t)len != strlen((char *)utf8taiwan)) { printf("FAIL (len=%d, expected %d)\n", len, (int)strlen((char *)utf8taiwan)); print_utf8(" utf8taiwan", utf8taiwan); print_utf8(" utf8dest", utf8dest); errors ++; } else if (memcmp(utf8taiwan, utf8dest, (size_t)len)) { puts("FAIL (results do not match)"); print_utf8(" utf8taiwan", utf8taiwan); print_utf8(" utf8dest", utf8dest); errors ++; } else puts("PASS"); /* * Test UTF-8 to/from legacy charset (EUC-TW)... */ fputs("cupsUTF8ToCharset(CUPS_EUC_TW): ", stdout); if (cupsUTF8ToCharset(legdest, utf8taiwan, 1024, CUPS_EUC_TW) < 0) { puts("FAIL"); errors ++; } else { for (legptr = legdest; *legptr && *legptr != '?'; legptr ++); if (*legptr) { puts("FAIL (unknown character)"); errors ++; } else puts("PASS"); } fputs("cupsCharsetToUTF8(CUPS_EUC_TW): ", stdout); strlcpy(legsrc, legdest, sizeof(legsrc)); len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_EUC_TW); if ((size_t)len != strlen((char *)utf8taiwan)) { printf("FAIL (len=%d, expected %d)\n", len, (int)strlen((char *)utf8taiwan)); print_utf8(" utf8taiwan", utf8taiwan); print_utf8(" utf8dest", utf8dest); errors ++; } else if (memcmp(utf8taiwan, utf8dest, (size_t)len)) { puts("FAIL (results do not match)"); print_utf8(" utf8taiwan", utf8taiwan); print_utf8(" utf8dest", utf8dest); errors ++; } else puts("PASS"); #if 0 /* * Test UTF-8 (16-bit) to UTF-32 (w/ BOM)... */ if (verbose) printf("\ntesti18n: Testing UTF-8 to UTF-32 (w/ BOM)...\n"); len = cupsUTF8ToUTF32(utf32dest, utf8good, 1024); if (len < 0) return (1); if (verbose) { print_utf8(" utf8good ", utf8good); print_utf32(" utf32dest", utf32dest); } memcpy(utf32src, utf32dest, (len + 1) * sizeof(cups_utf32_t)); len = cupsUTF32ToUTF8(utf8dest, utf32src, 1024); if (len < 0) return (1); if (len != strlen ((char *) utf8good)) return (1); if (memcmp(utf8good, utf8dest, len) != 0) return (1); /* * Test invalid UTF-8 (16-bit) to UTF-32 (w/ BOM)... */ if (verbose) printf("\ntesti18n: Testing UTF-8 bad 16-bit source string...\n"); len = cupsUTF8ToUTF32(utf32dest, utf8bad, 1024); if (len >= 0) return (1); if (verbose) print_utf8(" utf8bad ", utf8bad); /* * Test _cupsCharmapFlush()... */ if (verbose) printf("\ntesti18n: Testing _cupsCharmapFlush()...\n"); _cupsCharmapFlush(); return (0); #endif /* 0 */ return (errors > 0); } /* * 'print_utf8()' - Print UTF-8 string with (optional) message. */ static void print_utf8(const char *msg, /* I - Message String */ const cups_utf8_t *src) /* I - UTF-8 Source String */ { const char *prefix; /* Prefix string */ if (msg) printf("%s:", msg); for (prefix = " "; *src; src ++) { printf("%s%02x", prefix, *src); if ((src[0] & 0x80) && (src[1] & 0x80)) prefix = ""; else prefix = " "; } putchar('\n'); } ippsample/cups/tls-sspi.c0000644000175000017500000021032513240604116014436 0ustar tilltill/* * TLS support for CUPS on Windows using the Security Support Provider * Interface (SSPI). * * Copyright 2010-2018 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /**** This file is included from tls.c ****/ /* * Include necessary headers... */ #include "debug-private.h" /* * Include necessary libraries... */ #pragma comment(lib, "Crypt32.lib") #pragma comment(lib, "Secur32.lib") #pragma comment(lib, "Ws2_32.lib") /* * Constants... */ #ifndef SECURITY_FLAG_IGNORE_UNKNOWN_CA # define SECURITY_FLAG_IGNORE_UNKNOWN_CA 0x00000100 /* Untrusted root */ #endif /* SECURITY_FLAG_IGNORE_UNKNOWN_CA */ #ifndef SECURITY_FLAG_IGNORE_CERT_CN_INVALID # define SECURITY_FLAG_IGNORE_CERT_CN_INVALID 0x00001000 /* Common name does not match */ #endif /* !SECURITY_FLAG_IGNORE_CERT_CN_INVALID */ #ifndef SECURITY_FLAG_IGNORE_CERT_DATE_INVALID # define SECURITY_FLAG_IGNORE_CERT_DATE_INVALID 0x00002000 /* Expired X509 Cert. */ #endif /* !SECURITY_FLAG_IGNORE_CERT_DATE_INVALID */ /* * Local globals... */ static int tls_options = -1,/* Options for TLS connections */ tls_min_version = _HTTP_TLS_1_0, tls_max_version = _HTTP_TLS_MAX; /* * Local functions... */ static _http_sspi_t *http_sspi_alloc(void); static int http_sspi_client(http_t *http, const char *hostname); static PCCERT_CONTEXT http_sspi_create_credential(http_credential_t *cred); static BOOL http_sspi_find_credentials(http_t *http, const LPWSTR containerName, const char *common_name); static void http_sspi_free(_http_sspi_t *sspi); static BOOL http_sspi_make_credentials(_http_sspi_t *sspi, const LPWSTR containerName, const char *common_name, _http_mode_t mode, int years); static int http_sspi_server(http_t *http, const char *hostname); static void http_sspi_set_allows_any_root(_http_sspi_t *sspi, BOOL allow); static void http_sspi_set_allows_expired_certs(_http_sspi_t *sspi, BOOL allow); static const char *http_sspi_strerror(char *buffer, size_t bufsize, DWORD code); static DWORD http_sspi_verify(PCCERT_CONTEXT cert, const char *common_name, DWORD dwCertFlags); /* * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 1 on success, 0 on failure */ cupsMakeServerCredentials( const char *path, /* I - Keychain path or @code NULL@ for default */ const char *common_name, /* I - Common name */ int num_alt_names, /* I - Number of subject alternate names */ const char **alt_names, /* I - Subject Alternate Names */ time_t expiration_date) /* I - Expiration date */ { _http_sspi_t *sspi; /* SSPI data */ int ret; /* Return value */ DEBUG_printf(("cupsMakeServerCredentials(path=\"%s\", common_name=\"%s\", num_alt_names=%d, alt_names=%p, expiration_date=%d)", path, common_name, num_alt_names, alt_names, (int)expiration_date)); (void)path; (void)num_alt_names; (void)alt_names; sspi = http_sspi_alloc(); ret = http_sspi_make_credentials(sspi, L"ServerContainer", common_name, _HTTP_MODE_SERVER, (int)((expiration_date - time(NULL) + 86399) / 86400 / 365)); http_sspi_free(sspi); return (ret); } /* * 'cupsSetServerCredentials()' - Set the default server credentials. * * Note: The server credentials are used by all threads in the running process. * This function is threadsafe. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 1 on success, 0 on failure */ cupsSetServerCredentials( const char *path, /* I - Keychain path or @code NULL@ for default */ const char *common_name, /* I - Default common name for server */ int auto_create) /* I - 1 = automatically create self-signed certificates */ { DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path, common_name, auto_create)); (void)path; (void)common_name; (void)auto_create; return (0); } /* * 'httpCopyCredentials()' - Copy the credentials associated with the peer in * an encrypted connection. * * @since CUPS 1.5/macOS 10.7@ */ int /* O - Status of call (0 = success) */ httpCopyCredentials( http_t *http, /* I - Connection to server */ cups_array_t **credentials) /* O - Array of credentials */ { DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http, credentials)); if (!http || !http->tls || !http->tls->remoteCert || !credentials) { if (credentials) *credentials = NULL; return (-1); } *credentials = cupsArrayNew(NULL, NULL); httpAddCredential(*credentials, http->tls->remoteCert->pbCertEncoded, http->tls->remoteCert->cbCertEncoded); return (0); } /* * '_httpCreateCredentials()' - Create credentials in the internal format. */ http_tls_credentials_t /* O - Internal credentials */ _httpCreateCredentials( cups_array_t *credentials) /* I - Array of credentials */ { return (http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials))); } /* * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 1 if valid, 0 otherwise */ httpCredentialsAreValidForName( cups_array_t *credentials, /* I - Credentials */ const char *common_name) /* I - Name to check */ { int valid = 1; /* Valid name? */ PCCERT_CONTEXT cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials)); /* Certificate */ char cert_name[1024]; /* Name from certificate */ if (cert) { if (CertNameToStr(X509_ASN_ENCODING, &(cert->pCertInfo->Subject), CERT_SIMPLE_NAME_STR, cert_name, sizeof(cert_name))) { /* * Extract common name at end... */ char *ptr = strrchr(cert_name, ','); if (ptr && ptr[1]) _cups_strcpy(cert_name, ptr + 2); } else strlcpy(cert_name, "unknown", sizeof(cert_name)); CertFreeCertificateContext(cert); } else strlcpy(cert_name, "unknown", sizeof(cert_name)); /* * Compare the common names... */ if (_cups_strcasecmp(common_name, cert_name)) { /* * Not an exact match for the common name, check for wildcard certs... */ const char *domain = strchr(common_name, '.'); /* Domain in common name */ if (strncmp(cert_name, "*.", 2) || !domain || _cups_strcasecmp(domain, cert_name + 1)) { /* * Not a wildcard match. */ /* TODO: Check subject alternate names */ valid = 0; } } return (valid); } /* * 'httpCredentialsGetTrust()' - Return the trust of credentials. * * @since CUPS 2.0/OS 10.10@ */ http_trust_t /* O - Level of trust */ httpCredentialsGetTrust( cups_array_t *credentials, /* I - Credentials */ const char *common_name) /* I - Common name for trust lookup */ { http_trust_t trust = HTTP_TRUST_OK; /* Level of trust */ PCCERT_CONTEXT cert = NULL; /* Certificate to validate */ DWORD certFlags = 0; /* Cert verification flags */ _cups_globals_t *cg = _cupsGlobals(); /* Per-thread global data */ if (!common_name) return (HTTP_TRUST_UNKNOWN); cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials)); if (!cert) return (HTTP_TRUST_UNKNOWN); if (cg->any_root < 0) _cupsSetDefaults(); if (cg->any_root) certFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA; if (cg->expired_certs) certFlags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; if (!cg->validate_certs) certFlags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID; if (http_sspi_verify(cert, common_name, certFlags) != SEC_E_OK) trust = HTTP_TRUST_INVALID; CertFreeCertificateContext(cert); return (trust); } /* * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials. * * @since CUPS 2.0/OS 10.10@ */ time_t /* O - Expiration date of credentials */ httpCredentialsGetExpiration( cups_array_t *credentials) /* I - Credentials */ { time_t expiration_date = 0; /* Expiration data of credentials */ PCCERT_CONTEXT cert = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials)); /* Certificate */ if (cert) { SYSTEMTIME systime; /* System time */ struct tm tm; /* UNIX date/time */ FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime); tm.tm_year = systime.wYear - 1900; tm.tm_mon = systime.wMonth - 1; tm.tm_mday = systime.wDay; tm.tm_hour = systime.wHour; tm.tm_min = systime.wMinute; tm.tm_sec = systime.wSecond; expiration_date = mktime(&tm); CertFreeCertificateContext(cert); } return (expiration_date); } /* * 'httpCredentialsString()' - Return a string representing the credentials. * * @since CUPS 2.0/OS 10.10@ */ size_t /* O - Total size of credentials string */ httpCredentialsString( cups_array_t *credentials, /* I - Credentials */ char *buffer, /* I - Buffer or @code NULL@ */ size_t bufsize) /* I - Size of buffer */ { http_credential_t *first = (http_credential_t *)cupsArrayFirst(credentials); /* First certificate */ PCCERT_CONTEXT cert; /* Certificate */ DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", credentials, buffer, CUPS_LLCAST bufsize)); if (!buffer) return (0); if (buffer && bufsize > 0) *buffer = '\0'; cert = http_sspi_create_credential(first); if (cert) { char cert_name[256]; /* Common name */ SYSTEMTIME systime; /* System time */ struct tm tm; /* UNIX date/time */ time_t expiration; /* Expiration date of cert */ unsigned char md5_digest[16]; /* MD5 result */ FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime); tm.tm_year = systime.wYear - 1900; tm.tm_mon = systime.wMonth - 1; tm.tm_mday = systime.wDay; tm.tm_hour = systime.wHour; tm.tm_min = systime.wMinute; tm.tm_sec = systime.wSecond; expiration = mktime(&tm); if (CertNameToStr(X509_ASN_ENCODING, &(cert->pCertInfo->Subject), CERT_SIMPLE_NAME_STR, cert_name, sizeof(cert_name))) { /* * Extract common name at end... */ char *ptr = strrchr(cert_name, ','); if (ptr && ptr[1]) _cups_strcpy(cert_name, ptr + 2); } else strlcpy(cert_name, "unknown", sizeof(cert_name)); cupsHashData("md5", first->data, first->datalen, md5_digest, sizeof(md5_digest)); snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", cert_name, httpGetDateString(expiration), md5_digest[0], md5_digest[1], md5_digest[2], md5_digest[3], md5_digest[4], md5_digest[5], md5_digest[6], md5_digest[7], md5_digest[8], md5_digest[9], md5_digest[10], md5_digest[11], md5_digest[12], md5_digest[13], md5_digest[14], md5_digest[15]); CertFreeCertificateContext(cert); } DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer)); return (strlen(buffer)); } /* * '_httpFreeCredentials()' - Free internal credentials. */ void _httpFreeCredentials( http_tls_credentials_t credentials) /* I - Internal credentials */ { if (!credentials) return; CertFreeCertificateContext(credentials); } /* * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 0 on success, -1 on error */ httpLoadCredentials( const char *path, /* I - Keychain path or @code NULL@ for default */ cups_array_t **credentials, /* IO - Credentials */ const char *common_name) /* I - Common name for credentials */ { HCERTSTORE store = NULL; /* Certificate store */ PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */ DWORD dwSize = 0; /* 32 bit size */ PBYTE p = NULL; /* Temporary storage */ HCRYPTPROV hProv = (HCRYPTPROV)NULL; /* Handle to a CSP */ CERT_NAME_BLOB sib; /* Arbitrary array of bytes */ #ifdef DEBUG char error[1024]; /* Error message buffer */ #endif /* DEBUG */ DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name)); (void)path; if (credentials) { *credentials = NULL; } else { DEBUG_puts("1httpLoadCredentials: NULL credentials pointer, returning -1."); return (-1); } if (!common_name) { DEBUG_puts("1httpLoadCredentials: Bad common name, returning -1."); return (-1); } if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET)) { if (GetLastError() == NTE_EXISTS) { if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) { DEBUG_printf(("1httpLoadCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); goto cleanup; } } } store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY"); if (!store) { DEBUG_printf(("1httpLoadCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); goto cleanup; } dwSize = 0; if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL)) { DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); goto cleanup; } p = (PBYTE)malloc(dwSize); if (!p) { DEBUG_printf(("1httpLoadCredentials: malloc failed for %d bytes.", dwSize)); goto cleanup; } if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL)) { DEBUG_printf(("1httpLoadCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); goto cleanup; } sib.cbData = dwSize; sib.pbData = p; storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL); if (!storedContext) { DEBUG_printf(("1httpLoadCredentials: Unable to find credentials for \"%s\".", common_name)); goto cleanup; } *credentials = cupsArrayNew(NULL, NULL); httpAddCredential(*credentials, storedContext->pbCertEncoded, storedContext->cbCertEncoded); cleanup: /* * Cleanup */ if (storedContext) CertFreeCertificateContext(storedContext); if (p) free(p); if (store) CertCloseStore(store, 0); if (hProv) CryptReleaseContext(hProv, 0); DEBUG_printf(("1httpLoadCredentials: Returning %d.", *credentials ? 0 : -1)); return (*credentials ? 0 : -1); } /* * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file. * * @since CUPS 2.0/OS 10.10@ */ int /* O - -1 on error, 0 on success */ httpSaveCredentials( const char *path, /* I - Keychain path or @code NULL@ for default */ cups_array_t *credentials, /* I - Credentials */ const char *common_name) /* I - Common name for credentials */ { HCERTSTORE store = NULL; /* Certificate store */ PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */ PCCERT_CONTEXT createdContext = NULL; /* Context created by us */ DWORD dwSize = 0; /* 32 bit size */ PBYTE p = NULL; /* Temporary storage */ HCRYPTPROV hProv = (HCRYPTPROV)NULL; /* Handle to a CSP */ CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */ int ret = -1; /* Return value */ #ifdef DEBUG char error[1024]; /* Error message buffer */ #endif /* DEBUG */ DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, credentials, common_name)); (void)path; if (!common_name) { DEBUG_puts("1httpSaveCredentials: Bad common name, returning -1."); return (-1); } createdContext = http_sspi_create_credential((http_credential_t *)cupsArrayFirst(credentials)); if (!createdContext) { DEBUG_puts("1httpSaveCredentials: Bad credentials, returning -1."); return (-1); } if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET)) { if (GetLastError() == NTE_EXISTS) { if (!CryptAcquireContextW(&hProv, L"RememberedContainer", MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) { DEBUG_printf(("1httpSaveCredentials: CryptAcquireContext failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); goto cleanup; } } } store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY"); if (!store) { DEBUG_printf(("1httpSaveCredentials: CertOpenSystemStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); goto cleanup; } dwSize = 0; if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL)) { DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); goto cleanup; } p = (PBYTE)malloc(dwSize); if (!p) { DEBUG_printf(("1httpSaveCredentials: malloc failed for %d bytes.", dwSize)); goto cleanup; } if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL)) { DEBUG_printf(("1httpSaveCredentials: CertStrToName failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); goto cleanup; } /* * Add the created context to the named store, and associate it with the named * container... */ if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext)) { DEBUG_printf(("1httpSaveCredentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); goto cleanup; } ZeroMemory(&ckp, sizeof(ckp)); ckp.pwszContainerName = L"RememberedContainer"; ckp.pwszProvName = MS_DEF_PROV_W; ckp.dwProvType = PROV_RSA_FULL; ckp.dwFlags = CRYPT_MACHINE_KEYSET; ckp.dwKeySpec = AT_KEYEXCHANGE; if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp)) { DEBUG_printf(("1httpSaveCredentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(error, sizeof(error), GetLastError()))); goto cleanup; } ret = 0; cleanup: /* * Cleanup */ if (createdContext) CertFreeCertificateContext(createdContext); if (storedContext) CertFreeCertificateContext(storedContext); if (p) free(p); if (store) CertCloseStore(store, 0); if (hProv) CryptReleaseContext(hProv, 0); DEBUG_printf(("1httpSaveCredentials: Returning %d.", ret)); return (ret); } /* * '_httpTLSInitialize()' - Initialize the TLS stack. */ void _httpTLSInitialize(void) { /* * Nothing to do... */ } /* * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes. */ size_t /* O - Bytes available */ _httpTLSPending(http_t *http) /* I - HTTP connection */ { if (http->tls) return (http->tls->readBufferUsed); else return (0); } /* * '_httpTLSRead()' - Read from a SSL/TLS connection. */ int /* O - Bytes read */ _httpTLSRead(http_t *http, /* I - HTTP connection */ char *buf, /* I - Buffer to store data */ int len) /* I - Length of buffer */ { int i; /* Looping var */ _http_sspi_t *sspi = http->tls; /* SSPI data */ SecBufferDesc message; /* Array of SecBuffer struct */ SecBuffer buffers[4] = { 0 }; /* Security package buffer */ int num = 0; /* Return value */ PSecBuffer pDataBuffer; /* Data buffer */ PSecBuffer pExtraBuffer; /* Excess data buffer */ SECURITY_STATUS scRet; /* SSPI status */ DEBUG_printf(("4_httpTLSRead(http=%p, buf=%p, len=%d)", http, buf, len)); /* * If there are bytes that have already been decrypted and have not yet been * read, return those... */ if (sspi->readBufferUsed > 0) { int bytesToCopy = min(sspi->readBufferUsed, len); /* Number of bytes to copy */ memcpy(buf, sspi->readBuffer, bytesToCopy); sspi->readBufferUsed -= bytesToCopy; if (sspi->readBufferUsed > 0) memmove(sspi->readBuffer, sspi->readBuffer + bytesToCopy, sspi->readBufferUsed); DEBUG_printf(("5_httpTLSRead: Returning %d bytes previously decrypted.", bytesToCopy)); return (bytesToCopy); } /* * Initialize security buffer structs */ message.ulVersion = SECBUFFER_VERSION; message.cBuffers = 4; message.pBuffers = buffers; do { /* * If there is not enough space in the buffer, then increase its size... */ if (sspi->decryptBufferLength <= sspi->decryptBufferUsed) { BYTE *temp; /* New buffer */ if (sspi->decryptBufferLength >= 262144) { WSASetLastError(E_OUTOFMEMORY); DEBUG_puts("_httpTLSRead: Decryption buffer too large (>256k)"); return (-1); } if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL) { DEBUG_printf(("_httpTLSRead: Unable to allocate %d byte decryption buffer.", sspi->decryptBufferLength + 4096)); WSASetLastError(E_OUTOFMEMORY); return (-1); } sspi->decryptBufferLength += 4096; sspi->decryptBuffer = temp; DEBUG_printf(("_httpTLSRead: Resized decryption buffer to %d bytes.", sspi->decryptBufferLength)); } buffers[0].pvBuffer = sspi->decryptBuffer; buffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed; buffers[0].BufferType = SECBUFFER_DATA; buffers[1].BufferType = SECBUFFER_EMPTY; buffers[2].BufferType = SECBUFFER_EMPTY; buffers[3].BufferType = SECBUFFER_EMPTY; DEBUG_printf(("5_httpTLSRead: decryptBufferUsed=%d", sspi->decryptBufferUsed)); scRet = DecryptMessage(&sspi->context, &message, 0, NULL); if (scRet == SEC_E_INCOMPLETE_MESSAGE) { num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0); if (num < 0) { DEBUG_printf(("5_httpTLSRead: recv failed: %d", WSAGetLastError())); return (-1); } else if (num == 0) { DEBUG_puts("5_httpTLSRead: Server disconnected."); return (0); } DEBUG_printf(("5_httpTLSRead: Read %d bytes into decryption buffer.", num)); sspi->decryptBufferUsed += num; } } while (scRet == SEC_E_INCOMPLETE_MESSAGE); if (scRet == SEC_I_CONTEXT_EXPIRED) { DEBUG_puts("5_httpTLSRead: Context expired."); WSASetLastError(WSAECONNRESET); return (-1); } else if (scRet != SEC_E_OK) { DEBUG_printf(("5_httpTLSRead: DecryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); WSASetLastError(WSASYSCALLFAILURE); return (-1); } /* * The decryption worked. Now, locate data buffer. */ pDataBuffer = NULL; pExtraBuffer = NULL; for (i = 1; i < 4; i++) { if (buffers[i].BufferType == SECBUFFER_DATA) pDataBuffer = &buffers[i]; else if (!pExtraBuffer && (buffers[i].BufferType == SECBUFFER_EXTRA)) pExtraBuffer = &buffers[i]; } /* * If a data buffer is found, then copy the decrypted bytes to the passed-in * buffer... */ if (pDataBuffer) { int bytesToCopy = min((int)pDataBuffer->cbBuffer, len); /* Number of bytes to copy into buf */ int bytesToSave = pDataBuffer->cbBuffer - bytesToCopy; /* Number of bytes to save in our read buffer */ if (bytesToCopy) memcpy(buf, pDataBuffer->pvBuffer, bytesToCopy); /* * If there are more decrypted bytes than can be copied to the passed in * buffer, then save them... */ if (bytesToSave) { if ((sspi->readBufferLength - sspi->readBufferUsed) < bytesToSave) { BYTE *temp; /* New buffer pointer */ if ((temp = realloc(sspi->readBuffer, sspi->readBufferUsed + bytesToSave)) == NULL) { DEBUG_printf(("_httpTLSRead: Unable to allocate %d bytes.", sspi->readBufferUsed + bytesToSave)); WSASetLastError(E_OUTOFMEMORY); return (-1); } sspi->readBufferLength = sspi->readBufferUsed + bytesToSave; sspi->readBuffer = temp; } memcpy(((BYTE *)sspi->readBuffer) + sspi->readBufferUsed, ((BYTE *)pDataBuffer->pvBuffer) + bytesToCopy, bytesToSave); sspi->readBufferUsed += bytesToSave; } num = bytesToCopy; } else { DEBUG_puts("_httpTLSRead: Unable to find data buffer."); WSASetLastError(WSASYSCALLFAILURE); return (-1); } /* * If the decryption process left extra bytes, then save those back in * decryptBuffer. They will be processed the next time through the loop. */ if (pExtraBuffer) { memmove(sspi->decryptBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer); sspi->decryptBufferUsed = pExtraBuffer->cbBuffer; } else { sspi->decryptBufferUsed = 0; } return (num); } /* * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options. */ void _httpTLSSetOptions(int options, /* I - Options */ int min_version, /* I - Minimum TLS version */ int max_version) /* I - Maximum TLS version */ { if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0) { tls_options = options; tls_min_version = min_version; tls_max_version = max_version; } } /* * '_httpTLSStart()' - Set up SSL/TLS support on a connection. */ int /* O - 0 on success, -1 on failure */ _httpTLSStart(http_t *http) /* I - HTTP connection */ { char hostname[256], /* Hostname */ *hostptr; /* Pointer into hostname */ DEBUG_printf(("3_httpTLSStart(http=%p)", http)); if (tls_options < 0) { DEBUG_puts("4_httpTLSStart: Setting defaults."); _cupsSetDefaults(); DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options)); } if ((http->tls = http_sspi_alloc()) == NULL) return (-1); if (http->mode == _HTTP_MODE_CLIENT) { /* * Client: determine hostname... */ if (httpAddrLocalhost(http->hostaddr)) { strlcpy(hostname, "localhost", sizeof(hostname)); } else { /* * Otherwise make sure the hostname we have does not end in a trailing dot. */ strlcpy(hostname, http->hostname, sizeof(hostname)); if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && *hostptr == '.') *hostptr = '\0'; } return (http_sspi_client(http, hostname)); } else { /* * Server: determine hostname to use... */ if (http->fields[HTTP_FIELD_HOST]) { /* * Use hostname for TLS upgrade... */ strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname)); } else { /* * Resolve hostname from connection address... */ http_addr_t addr; /* Connection address */ socklen_t addrlen; /* Length of address */ addrlen = sizeof(addr); if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen)) { DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno))); hostname[0] = '\0'; } else if (httpAddrLocalhost(&addr)) hostname[0] = '\0'; else { httpAddrLookup(&addr, hostname, sizeof(hostname)); DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname)); } } return (http_sspi_server(http, hostname)); } } /* * '_httpTLSStop()' - Shut down SSL/TLS on a connection. */ void _httpTLSStop(http_t *http) /* I - HTTP connection */ { _http_sspi_t *sspi = http->tls; /* SSPI data */ if (sspi->contextInitialized && http->fd >= 0) { SecBufferDesc message; /* Array of SecBuffer struct */ SecBuffer buffers[1] = { 0 }; /* Security package buffer */ DWORD dwType; /* Type */ DWORD status; /* Status */ /* * Notify schannel that we are about to close the connection. */ dwType = SCHANNEL_SHUTDOWN; buffers[0].pvBuffer = &dwType; buffers[0].BufferType = SECBUFFER_TOKEN; buffers[0].cbBuffer = sizeof(dwType); message.cBuffers = 1; message.pBuffers = buffers; message.ulVersion = SECBUFFER_VERSION; status = ApplyControlToken(&sspi->context, &message); if (SUCCEEDED(status)) { PBYTE pbMessage; /* Message buffer */ DWORD cbMessage; /* Message buffer count */ DWORD cbData; /* Data count */ DWORD dwSSPIFlags; /* SSL attributes we requested */ DWORD dwSSPIOutFlags; /* SSL attributes we received */ TimeStamp tsExpiry; /* Time stamp */ dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT | ASC_REQ_REPLAY_DETECT | ASC_REQ_CONFIDENTIALITY | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_STREAM; buffers[0].pvBuffer = NULL; buffers[0].BufferType = SECBUFFER_TOKEN; buffers[0].cbBuffer = 0; message.cBuffers = 1; message.pBuffers = buffers; message.ulVersion = SECBUFFER_VERSION; status = AcceptSecurityContext(&sspi->creds, &sspi->context, NULL, dwSSPIFlags, SECURITY_NATIVE_DREP, NULL, &message, &dwSSPIOutFlags, &tsExpiry); if (SUCCEEDED(status)) { pbMessage = buffers[0].pvBuffer; cbMessage = buffers[0].cbBuffer; /* * Send the close notify message to the client. */ if (pbMessage && cbMessage) { cbData = send(http->fd, pbMessage, cbMessage, 0); if ((cbData == SOCKET_ERROR) || (cbData == 0)) { status = WSAGetLastError(); DEBUG_printf(("_httpTLSStop: sending close notify failed: %d", status)); } else { FreeContextBuffer(pbMessage); } } } else { DEBUG_printf(("_httpTLSStop: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status))); } } else { DEBUG_printf(("_httpTLSStop: ApplyControlToken failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), status))); } } http_sspi_free(sspi); http->tls = NULL; } /* * '_httpTLSWrite()' - Write to a SSL/TLS connection. */ int /* O - Bytes written */ _httpTLSWrite(http_t *http, /* I - HTTP connection */ const char *buf, /* I - Buffer holding data */ int len) /* I - Length of buffer */ { _http_sspi_t *sspi = http->tls; /* SSPI data */ SecBufferDesc message; /* Array of SecBuffer struct */ SecBuffer buffers[4] = { 0 }; /* Security package buffer */ int bufferLen; /* Buffer length */ int bytesLeft; /* Bytes left to write */ const char *bufptr; /* Pointer into buffer */ int num = 0; /* Return value */ bufferLen = sspi->streamSizes.cbMaximumMessage + sspi->streamSizes.cbHeader + sspi->streamSizes.cbTrailer; if (bufferLen > sspi->writeBufferLength) { BYTE *temp; /* New buffer pointer */ if ((temp = (BYTE *)realloc(sspi->writeBuffer, bufferLen)) == NULL) { DEBUG_printf(("_httpTLSWrite: Unable to allocate buffer of %d bytes.", bufferLen)); WSASetLastError(E_OUTOFMEMORY); return (-1); } sspi->writeBuffer = temp; sspi->writeBufferLength = bufferLen; } bytesLeft = len; bufptr = buf; while (bytesLeft) { int chunk = min((int)sspi->streamSizes.cbMaximumMessage, bytesLeft); /* Size of data to write */ SECURITY_STATUS scRet; /* SSPI status */ /* * Copy user data into the buffer, starting just past the header... */ memcpy(sspi->writeBuffer + sspi->streamSizes.cbHeader, bufptr, chunk); /* * Setup the SSPI buffers */ message.ulVersion = SECBUFFER_VERSION; message.cBuffers = 4; message.pBuffers = buffers; buffers[0].pvBuffer = sspi->writeBuffer; buffers[0].cbBuffer = sspi->streamSizes.cbHeader; buffers[0].BufferType = SECBUFFER_STREAM_HEADER; buffers[1].pvBuffer = sspi->writeBuffer + sspi->streamSizes.cbHeader; buffers[1].cbBuffer = (unsigned long) chunk; buffers[1].BufferType = SECBUFFER_DATA; buffers[2].pvBuffer = sspi->writeBuffer + sspi->streamSizes.cbHeader + chunk; buffers[2].cbBuffer = sspi->streamSizes.cbTrailer; buffers[2].BufferType = SECBUFFER_STREAM_TRAILER; buffers[3].BufferType = SECBUFFER_EMPTY; /* * Encrypt the data */ scRet = EncryptMessage(&sspi->context, 0, &message, 0); if (FAILED(scRet)) { DEBUG_printf(("_httpTLSWrite: EncryptMessage failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); WSASetLastError(WSASYSCALLFAILURE); return (-1); } /* * Send the data. Remember the size of the total data to send is the size * of the header, the size of the data the caller passed in and the size * of the trailer... */ num = send(http->fd, sspi->writeBuffer, buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer, 0); if (num <= 0) { DEBUG_printf(("_httpTLSWrite: send failed: %ld", WSAGetLastError())); return (num); } bytesLeft -= chunk; bufptr += chunk; } return (len); } #if 0 /* * 'http_setup_ssl()' - Set up SSL/TLS support on a connection. */ static int /* O - 0 on success, -1 on failure */ http_setup_ssl(http_t *http) /* I - Connection to server */ { char hostname[256], /* Hostname */ *hostptr; /* Pointer into hostname */ TCHAR username[256]; /* Username returned from GetUserName() */ TCHAR commonName[256];/* Common name for certificate */ DWORD dwSize; /* 32 bit size */ DEBUG_printf(("7http_setup_ssl(http=%p)", http)); /* * Get the hostname to use for SSL... */ if (httpAddrLocalhost(http->hostaddr)) { strlcpy(hostname, "localhost", sizeof(hostname)); } else { /* * Otherwise make sure the hostname we have does not end in a trailing dot. */ strlcpy(hostname, http->hostname, sizeof(hostname)); if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && *hostptr == '.') *hostptr = '\0'; } http->tls = http_sspi_alloc(); if (!http->tls) { _cupsSetHTTPError(HTTP_STATUS_ERROR); return (-1); } dwSize = sizeof(username) / sizeof(TCHAR); GetUserName(username, &dwSize); _sntprintf_s(commonName, sizeof(commonName) / sizeof(TCHAR), sizeof(commonName) / sizeof(TCHAR), TEXT("CN=%s"), username); if (!_sspiGetCredentials(http->tls, L"ClientContainer", commonName, FALSE)) { _sspiFree(http->tls); http->tls = NULL; http->error = EIO; http->status = HTTP_STATUS_ERROR; _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Unable to establish a secure connection to host."), 1); return (-1); } _sspiSetAllowsAnyRoot(http->tls, TRUE); _sspiSetAllowsExpiredCerts(http->tls, TRUE); if (!_sspiConnect(http->tls, hostname)) { _sspiFree(http->tls); http->tls = NULL; http->error = EIO; http->status = HTTP_STATUS_ERROR; _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Unable to establish a secure connection to host."), 1); return (-1); } return (0); } #endif // 0 /* * 'http_sspi_alloc()' - Allocate SSPI object. */ static _http_sspi_t * /* O - New SSPI/SSL object */ http_sspi_alloc(void) { return ((_http_sspi_t *)calloc(sizeof(_http_sspi_t), 1)); } /* * 'http_sspi_client()' - Negotiate a TLS connection as a client. */ static int /* O - 0 on success, -1 on failure */ http_sspi_client(http_t *http, /* I - Client connection */ const char *hostname) /* I - Server hostname */ { _http_sspi_t *sspi = http->tls; /* SSPI data */ DWORD dwSize; /* Size for buffer */ DWORD dwSSPIFlags; /* SSL connection attributes we want */ DWORD dwSSPIOutFlags; /* SSL connection attributes we got */ TimeStamp tsExpiry; /* Time stamp */ SECURITY_STATUS scRet; /* Status */ int cbData; /* Data count */ SecBufferDesc inBuffer; /* Array of SecBuffer structs */ SecBuffer inBuffers[2]; /* Security package buffer */ SecBufferDesc outBuffer; /* Array of SecBuffer structs */ SecBuffer outBuffers[1]; /* Security package buffer */ int ret = 0; /* Return value */ char username[1024], /* Current username */ common_name[1024]; /* CN=username */ DEBUG_printf(("4http_sspi_client(http=%p, hostname=\"%s\")", http, hostname)); dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; /* * Lookup the client certificate... */ dwSize = sizeof(username); GetUserName(username, &dwSize); snprintf(common_name, sizeof(common_name), "CN=%s", username); if (!http_sspi_find_credentials(http, L"ClientContainer", common_name)) if (!http_sspi_make_credentials(http->tls, L"ClientContainer", common_name, _HTTP_MODE_CLIENT, 10)) { DEBUG_puts("5http_sspi_client: Unable to get client credentials."); return (-1); } /* * Initiate a ClientHello message and generate a token. */ outBuffers[0].pvBuffer = NULL; outBuffers[0].BufferType = SECBUFFER_TOKEN; outBuffers[0].cbBuffer = 0; outBuffer.cBuffers = 1; outBuffer.pBuffers = outBuffers; outBuffer.ulVersion = SECBUFFER_VERSION; scRet = InitializeSecurityContext(&sspi->creds, NULL, TEXT(""), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &sspi->context, &outBuffer, &dwSSPIOutFlags, &tsExpiry); if (scRet != SEC_I_CONTINUE_NEEDED) { DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(1) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); return (-1); } /* * Send response to server if there is one. */ if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) { if ((cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0)) <= 0) { DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError())); FreeContextBuffer(outBuffers[0].pvBuffer); DeleteSecurityContext(&sspi->context); return (-1); } DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData)); FreeContextBuffer(outBuffers[0].pvBuffer); outBuffers[0].pvBuffer = NULL; } dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; sspi->decryptBufferUsed = 0; /* * Loop until the handshake is finished or an error occurs. */ scRet = SEC_I_CONTINUE_NEEDED; while(scRet == SEC_I_CONTINUE_NEEDED || scRet == SEC_E_INCOMPLETE_MESSAGE || scRet == SEC_I_INCOMPLETE_CREDENTIALS) { if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE) { if (sspi->decryptBufferLength <= sspi->decryptBufferUsed) { BYTE *temp; /* New buffer */ if (sspi->decryptBufferLength >= 262144) { WSASetLastError(E_OUTOFMEMORY); DEBUG_puts("5http_sspi_client: Decryption buffer too large (>256k)"); return (-1); } if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL) { DEBUG_printf(("5http_sspi_client: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096)); WSASetLastError(E_OUTOFMEMORY); return (-1); } sspi->decryptBufferLength += 4096; sspi->decryptBuffer = temp; } cbData = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0); if (cbData < 0) { DEBUG_printf(("5http_sspi_client: recv failed: %d", WSAGetLastError())); return (-1); } else if (cbData == 0) { DEBUG_printf(("5http_sspi_client: Server unexpectedly disconnected.")); return (-1); } DEBUG_printf(("5http_sspi_client: %d bytes of handshake data received", cbData)); sspi->decryptBufferUsed += cbData; } /* * Set up the input buffers. Buffer 0 is used to pass in data received from * the server. Schannel will consume some or all of this. Leftover data * (if any) will be placed in buffer 1 and given a buffer type of * SECBUFFER_EXTRA. */ inBuffers[0].pvBuffer = sspi->decryptBuffer; inBuffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed; inBuffers[0].BufferType = SECBUFFER_TOKEN; inBuffers[1].pvBuffer = NULL; inBuffers[1].cbBuffer = 0; inBuffers[1].BufferType = SECBUFFER_EMPTY; inBuffer.cBuffers = 2; inBuffer.pBuffers = inBuffers; inBuffer.ulVersion = SECBUFFER_VERSION; /* * Set up the output buffers. These are initialized to NULL so as to make it * less likely we'll attempt to free random garbage later. */ outBuffers[0].pvBuffer = NULL; outBuffers[0].BufferType = SECBUFFER_TOKEN; outBuffers[0].cbBuffer = 0; outBuffer.cBuffers = 1; outBuffer.pBuffers = outBuffers; outBuffer.ulVersion = SECBUFFER_VERSION; /* * Call InitializeSecurityContext. */ scRet = InitializeSecurityContext(&sspi->creds, &sspi->context, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL, &outBuffer, &dwSSPIOutFlags, &tsExpiry); /* * If InitializeSecurityContext was successful (or if the error was one of * the special extended ones), send the contents of the output buffer to the * server. */ if (scRet == SEC_E_OK || scRet == SEC_I_CONTINUE_NEEDED || FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR)) { if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) { cbData = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); if (cbData <= 0) { DEBUG_printf(("5http_sspi_client: send failed: %d", WSAGetLastError())); FreeContextBuffer(outBuffers[0].pvBuffer); DeleteSecurityContext(&sspi->context); return (-1); } DEBUG_printf(("5http_sspi_client: %d bytes of handshake data sent.", cbData)); /* * Free output buffer. */ FreeContextBuffer(outBuffers[0].pvBuffer); outBuffers[0].pvBuffer = NULL; } } /* * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, then we * need to read more data from the server and try again. */ if (scRet == SEC_E_INCOMPLETE_MESSAGE) continue; /* * If InitializeSecurityContext returned SEC_E_OK, then the handshake * completed successfully. */ if (scRet == SEC_E_OK) { /* * If the "extra" buffer contains data, this is encrypted application * protocol layer stuff. It needs to be saved. The application layer will * later decrypt it with DecryptMessage. */ DEBUG_puts("5http_sspi_client: Handshake was successful."); if (inBuffers[1].BufferType == SECBUFFER_EXTRA) { memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer); sspi->decryptBufferUsed = inBuffers[1].cbBuffer; DEBUG_printf(("5http_sspi_client: %d bytes of app data was bundled with handshake data", sspi->decryptBufferUsed)); } else sspi->decryptBufferUsed = 0; /* * Bail out to quit */ break; } /* * Check for fatal error. */ if (FAILED(scRet)) { DEBUG_printf(("5http_sspi_client: InitializeSecurityContext(2) failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); ret = -1; break; } /* * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS, * then the server just requested client authentication. */ if (scRet == SEC_I_INCOMPLETE_CREDENTIALS) { /* * Unimplemented */ DEBUG_printf(("5http_sspi_client: server requested client credentials.")); ret = -1; break; } /* * Copy any leftover data from the "extra" buffer, and go around again. */ if (inBuffers[1].BufferType == SECBUFFER_EXTRA) { memmove(sspi->decryptBuffer, sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer, inBuffers[1].cbBuffer); sspi->decryptBufferUsed = inBuffers[1].cbBuffer; } else { sspi->decryptBufferUsed = 0; } } if (!ret) { /* * Success! Get the server cert */ sspi->contextInitialized = TRUE; scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID *)&(sspi->remoteCert)); if (scRet != SEC_E_OK) { DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); return (-1); } /* * Find out how big the header/trailer will be: */ scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes); if (scRet != SEC_E_OK) { DEBUG_printf(("5http_sspi_client: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); ret = -1; } } return (ret); } /* * 'http_sspi_create_credential()' - Create an SSPI certificate context. */ static PCCERT_CONTEXT /* O - Certificate context */ http_sspi_create_credential( http_credential_t *cred) /* I - Credential */ { if (cred) return (CertCreateCertificateContext(X509_ASN_ENCODING, cred->data, cred->datalen)); else return (NULL); } /* * 'http_sspi_find_credentials()' - Retrieve a TLS certificate from the system store. */ static BOOL /* O - 1 on success, 0 on failure */ http_sspi_find_credentials( http_t *http, /* I - HTTP connection */ const LPWSTR container, /* I - Cert container name */ const char *common_name) /* I - Common name of certificate */ { _http_sspi_t *sspi = http->tls; /* SSPI data */ HCERTSTORE store = NULL; /* Certificate store */ PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */ DWORD dwSize = 0; /* 32 bit size */ PBYTE p = NULL; /* Temporary storage */ HCRYPTPROV hProv = (HCRYPTPROV)NULL; /* Handle to a CSP */ CERT_NAME_BLOB sib; /* Arbitrary array of bytes */ SCHANNEL_CRED SchannelCred; /* Schannel credential data */ TimeStamp tsExpiry; /* Time stamp */ SECURITY_STATUS Status; /* Status */ BOOL ok = TRUE; /* Return value */ if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET)) { if (GetLastError() == NTE_EXISTS) { if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) { DEBUG_printf(("5http_sspi_find_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); ok = FALSE; goto cleanup; } } } store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY"); if (!store) { DEBUG_printf(("5http_sspi_find_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); ok = FALSE; goto cleanup; } dwSize = 0; if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL)) { DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); ok = FALSE; goto cleanup; } p = (PBYTE)malloc(dwSize); if (!p) { DEBUG_printf(("5http_sspi_find_credentials: malloc failed for %d bytes.", dwSize)); ok = FALSE; goto cleanup; } if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL)) { DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); ok = FALSE; goto cleanup; } sib.cbData = dwSize; sib.pbData = p; storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL); if (!storedContext) { DEBUG_printf(("5http_sspi_find_credentials: Unable to find credentials for \"%s\".", common_name)); ok = FALSE; goto cleanup; } ZeroMemory(&SchannelCred, sizeof(SchannelCred)); SchannelCred.dwVersion = SCHANNEL_CRED_VERSION; SchannelCred.cCreds = 1; SchannelCred.paCred = &storedContext; /* * Set supported protocols (can also be overriden in the registry...) */ #ifdef SP_PROT_TLS1_2_SERVER if (http->mode == _HTTP_MODE_SERVER) { if (tls_options & _HTTP_TLS_DENY_TLS10) SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER; else if (tls_options & _HTTP_TLS_ALLOW_SSL3) SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER | SP_PROT_SSL3_SERVER; else SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER; } else { if (tls_options & _HTTP_TLS_DENY_TLS10) SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT; else if (tls_options & _HTTP_TLS_ALLOW_SSL3) SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT | SP_PROT_SSL3_CLIENT; else SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT; } #else if (http->mode == _HTTP_MODE_SERVER) { if (tls_min_version == _HTTP_TLS_SSL3) SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER | SP_PROT_SSL3_SERVER; else SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER; } else { if (tls_min_version == _HTTP_TLS_SSL3) SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT | SP_PROT_SSL3_CLIENT; else SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT; } #endif /* SP_PROT_TLS1_2_SERVER */ /* TODO: Support _HTTP_TLS_ALLOW_RC4, _HTTP_TLS_ALLOW_DH, and _HTTP_TLS_DENY_CBC options; right now we'll rely on Windows registry to enable/disable RC4/DH/CBC... */ /* * Create an SSPI credential. */ Status = AcquireCredentialsHandle(NULL, UNISP_NAME, http->mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry); if (Status != SEC_E_OK) { DEBUG_printf(("5http_sspi_find_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status))); ok = FALSE; goto cleanup; } cleanup: /* * Cleanup */ if (storedContext) CertFreeCertificateContext(storedContext); if (p) free(p); if (store) CertCloseStore(store, 0); if (hProv) CryptReleaseContext(hProv, 0); return (ok); } /* * 'http_sspi_free()' - Close a connection and free resources. */ static void http_sspi_free(_http_sspi_t *sspi) /* I - SSPI data */ { if (!sspi) return; if (sspi->contextInitialized) DeleteSecurityContext(&sspi->context); if (sspi->decryptBuffer) free(sspi->decryptBuffer); if (sspi->readBuffer) free(sspi->readBuffer); if (sspi->writeBuffer) free(sspi->writeBuffer); if (sspi->localCert) CertFreeCertificateContext(sspi->localCert); if (sspi->remoteCert) CertFreeCertificateContext(sspi->remoteCert); free(sspi); } /* * 'http_sspi_make_credentials()' - Create a TLS certificate in the system store. */ static BOOL /* O - 1 on success, 0 on failure */ http_sspi_make_credentials( _http_sspi_t *sspi, /* I - SSPI data */ const LPWSTR container, /* I - Cert container name */ const char *common_name, /* I - Common name of certificate */ _http_mode_t mode, /* I - Client or server? */ int years) /* I - Years until expiration */ { HCERTSTORE store = NULL; /* Certificate store */ PCCERT_CONTEXT storedContext = NULL; /* Context created from the store */ PCCERT_CONTEXT createdContext = NULL; /* Context created by us */ DWORD dwSize = 0; /* 32 bit size */ PBYTE p = NULL; /* Temporary storage */ HCRYPTPROV hProv = (HCRYPTPROV)NULL; /* Handle to a CSP */ CERT_NAME_BLOB sib; /* Arbitrary array of bytes */ SCHANNEL_CRED SchannelCred; /* Schannel credential data */ TimeStamp tsExpiry; /* Time stamp */ SECURITY_STATUS Status; /* Status */ HCRYPTKEY hKey = (HCRYPTKEY)NULL; /* Handle to crypto key */ CRYPT_KEY_PROV_INFO kpi; /* Key container info */ SYSTEMTIME et; /* System time */ CERT_EXTENSIONS exts; /* Array of cert extensions */ CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */ BOOL ok = TRUE; /* Return value */ DEBUG_printf(("4http_sspi_make_credentials(sspi=%p, container=%p, common_name=\"%s\", mode=%d, years=%d)", sspi, container, common_name, mode, years)); if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET)) { if (GetLastError() == NTE_EXISTS) { if (!CryptAcquireContextW(&hProv, (LPWSTR)container, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) { DEBUG_printf(("5http_sspi_make_credentials: CryptAcquireContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); ok = FALSE; goto cleanup; } } } store = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_OPEN_EXISTING_FLAG, L"MY"); if (!store) { DEBUG_printf(("5http_sspi_make_credentials: CertOpenSystemStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); ok = FALSE; goto cleanup; } dwSize = 0; if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL)) { DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); ok = FALSE; goto cleanup; } p = (PBYTE)malloc(dwSize); if (!p) { DEBUG_printf(("5http_sspi_make_credentials: malloc failed for %d bytes", dwSize)); ok = FALSE; goto cleanup; } if (!CertStrToName(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL)) { DEBUG_printf(("5http_sspi_make_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); ok = FALSE; goto cleanup; } /* * Create a private key and self-signed certificate... */ if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey)) { DEBUG_printf(("5http_sspi_make_credentials: CryptGenKey failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); ok = FALSE; goto cleanup; } ZeroMemory(&kpi, sizeof(kpi)); kpi.pwszContainerName = (LPWSTR)container; kpi.pwszProvName = MS_DEF_PROV_W; kpi.dwProvType = PROV_RSA_FULL; kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID; kpi.dwKeySpec = AT_KEYEXCHANGE; GetSystemTime(&et); et.wYear += years; ZeroMemory(&exts, sizeof(exts)); createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL, &et, &exts); if (!createdContext) { DEBUG_printf(("5http_sspi_make_credentials: CertCreateSelfSignCertificate failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); ok = FALSE; goto cleanup; } /* * Add the created context to the named store, and associate it with the named * container... */ if (!CertAddCertificateContextToStore(store, createdContext, CERT_STORE_ADD_REPLACE_EXISTING, &storedContext)) { DEBUG_printf(("5http_sspi_make_credentials: CertAddCertificateContextToStore failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); ok = FALSE; goto cleanup; } ZeroMemory(&ckp, sizeof(ckp)); ckp.pwszContainerName = (LPWSTR) container; ckp.pwszProvName = MS_DEF_PROV_W; ckp.dwProvType = PROV_RSA_FULL; ckp.dwFlags = CRYPT_MACHINE_KEYSET; ckp.dwKeySpec = AT_KEYEXCHANGE; if (!CertSetCertificateContextProperty(storedContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &ckp)) { DEBUG_printf(("5http_sspi_make_credentials: CertSetCertificateContextProperty failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); ok = FALSE; goto cleanup; } /* * Get a handle to use the certificate... */ ZeroMemory(&SchannelCred, sizeof(SchannelCred)); SchannelCred.dwVersion = SCHANNEL_CRED_VERSION; SchannelCred.cCreds = 1; SchannelCred.paCred = &storedContext; /* * SSPI doesn't seem to like it if grbitEnabledProtocols is set for a client. */ if (mode == _HTTP_MODE_SERVER) SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1; /* * Create an SSPI credential. */ Status = AcquireCredentialsHandle(NULL, UNISP_NAME, mode == _HTTP_MODE_SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &sspi->creds, &tsExpiry); if (Status != SEC_E_OK) { DEBUG_printf(("5http_sspi_make_credentials: AcquireCredentialsHandle failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), Status))); ok = FALSE; goto cleanup; } cleanup: /* * Cleanup */ if (hKey) CryptDestroyKey(hKey); if (createdContext) CertFreeCertificateContext(createdContext); if (storedContext) CertFreeCertificateContext(storedContext); if (p) free(p); if (store) CertCloseStore(store, 0); if (hProv) CryptReleaseContext(hProv, 0); return (ok); } /* * 'http_sspi_server()' - Negotiate a TLS connection as a server. */ static int /* O - 0 on success, -1 on failure */ http_sspi_server(http_t *http, /* I - HTTP connection */ const char *hostname) /* I - Hostname of server */ { _http_sspi_t *sspi = http->tls; /* I - SSPI data */ char common_name[512]; /* Common name for cert */ DWORD dwSSPIFlags; /* SSL connection attributes we want */ DWORD dwSSPIOutFlags; /* SSL connection attributes we got */ TimeStamp tsExpiry; /* Time stamp */ SECURITY_STATUS scRet; /* SSPI Status */ SecBufferDesc inBuffer; /* Array of SecBuffer structs */ SecBuffer inBuffers[2]; /* Security package buffer */ SecBufferDesc outBuffer; /* Array of SecBuffer structs */ SecBuffer outBuffers[1]; /* Security package buffer */ int num = 0; /* 32 bit status value */ BOOL fInitContext = TRUE; /* Has the context been init'd? */ int ret = 0; /* Return value */ DEBUG_printf(("4http_sspi_server(http=%p, hostname=\"%s\")", http, hostname)); dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT | ASC_REQ_REPLAY_DETECT | ASC_REQ_CONFIDENTIALITY | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_STREAM; sspi->decryptBufferUsed = 0; /* * Lookup the server certificate... */ snprintf(common_name, sizeof(common_name), "CN=%s", hostname); if (!http_sspi_find_credentials(http, L"ServerContainer", common_name)) if (!http_sspi_make_credentials(http->tls, L"ServerContainer", common_name, _HTTP_MODE_SERVER, 10)) { DEBUG_puts("5http_sspi_server: Unable to get server credentials."); return (-1); } /* * Set OutBuffer for AcceptSecurityContext call */ outBuffer.cBuffers = 1; outBuffer.pBuffers = outBuffers; outBuffer.ulVersion = SECBUFFER_VERSION; scRet = SEC_I_CONTINUE_NEEDED; while (scRet == SEC_I_CONTINUE_NEEDED || scRet == SEC_E_INCOMPLETE_MESSAGE || scRet == SEC_I_INCOMPLETE_CREDENTIALS) { if (sspi->decryptBufferUsed == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE) { if (sspi->decryptBufferLength <= sspi->decryptBufferUsed) { BYTE *temp; /* New buffer */ if (sspi->decryptBufferLength >= 262144) { WSASetLastError(E_OUTOFMEMORY); DEBUG_puts("5http_sspi_server: Decryption buffer too large (>256k)"); return (-1); } if ((temp = realloc(sspi->decryptBuffer, sspi->decryptBufferLength + 4096)) == NULL) { DEBUG_printf(("5http_sspi_server: Unable to allocate %d byte buffer.", sspi->decryptBufferLength + 4096)); WSASetLastError(E_OUTOFMEMORY); return (-1); } sspi->decryptBufferLength += 4096; sspi->decryptBuffer = temp; } for (;;) { num = recv(http->fd, sspi->decryptBuffer + sspi->decryptBufferUsed, (int)(sspi->decryptBufferLength - sspi->decryptBufferUsed), 0); if (num == -1 && WSAGetLastError() == WSAEWOULDBLOCK) Sleep(1); else break; } if (num < 0) { DEBUG_printf(("5http_sspi_server: recv failed: %d", WSAGetLastError())); return (-1); } else if (num == 0) { DEBUG_puts("5http_sspi_server: client disconnected"); return (-1); } DEBUG_printf(("5http_sspi_server: received %d (handshake) bytes from client.", num)); sspi->decryptBufferUsed += num; } /* * InBuffers[1] is for getting extra data that SSPI/SCHANNEL doesn't process * on this run around the loop. */ inBuffers[0].pvBuffer = sspi->decryptBuffer; inBuffers[0].cbBuffer = (unsigned long)sspi->decryptBufferUsed; inBuffers[0].BufferType = SECBUFFER_TOKEN; inBuffers[1].pvBuffer = NULL; inBuffers[1].cbBuffer = 0; inBuffers[1].BufferType = SECBUFFER_EMPTY; inBuffer.cBuffers = 2; inBuffer.pBuffers = inBuffers; inBuffer.ulVersion = SECBUFFER_VERSION; /* * Initialize these so if we fail, pvBuffer contains NULL, so we don't try to * free random garbage at the quit. */ outBuffers[0].pvBuffer = NULL; outBuffers[0].BufferType = SECBUFFER_TOKEN; outBuffers[0].cbBuffer = 0; scRet = AcceptSecurityContext(&sspi->creds, (fInitContext?NULL:&sspi->context), &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP, (fInitContext?&sspi->context:NULL), &outBuffer, &dwSSPIOutFlags, &tsExpiry); fInitContext = FALSE; if (scRet == SEC_E_OK || scRet == SEC_I_CONTINUE_NEEDED || (FAILED(scRet) && ((dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR) != 0))) { if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) { /* * Send response to server if there is one. */ num = send(http->fd, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); if (num <= 0) { DEBUG_printf(("5http_sspi_server: handshake send failed: %d", WSAGetLastError())); return (-1); } DEBUG_printf(("5http_sspi_server: sent %d handshake bytes to client.", outBuffers[0].cbBuffer)); FreeContextBuffer(outBuffers[0].pvBuffer); outBuffers[0].pvBuffer = NULL; } } if (scRet == SEC_E_OK) { /* * If there's extra data then save it for next time we go to decrypt. */ if (inBuffers[1].BufferType == SECBUFFER_EXTRA) { memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer); sspi->decryptBufferUsed = inBuffers[1].cbBuffer; } else { sspi->decryptBufferUsed = 0; } break; } else if (FAILED(scRet) && scRet != SEC_E_INCOMPLETE_MESSAGE) { DEBUG_printf(("5http_sspi_server: AcceptSecurityContext failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); ret = -1; break; } if (scRet != SEC_E_INCOMPLETE_MESSAGE && scRet != SEC_I_INCOMPLETE_CREDENTIALS) { if (inBuffers[1].BufferType == SECBUFFER_EXTRA) { memcpy(sspi->decryptBuffer, (LPBYTE)(sspi->decryptBuffer + sspi->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer); sspi->decryptBufferUsed = inBuffers[1].cbBuffer; } else { sspi->decryptBufferUsed = 0; } } } if (!ret) { sspi->contextInitialized = TRUE; /* * Find out how big the header will be: */ scRet = QueryContextAttributes(&sspi->context, SECPKG_ATTR_STREAM_SIZES, &sspi->streamSizes); if (scRet != SEC_E_OK) { DEBUG_printf(("5http_sspi_server: QueryContextAttributes failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), scRet))); ret = -1; } } return (ret); } /* * 'http_sspi_strerror()' - Return a string for the specified error code. */ static const char * /* O - String for error */ http_sspi_strerror(char *buffer, /* I - Error message buffer */ size_t bufsize, /* I - Size of buffer */ DWORD code) /* I - Error code */ { if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, buffer, bufsize, NULL)) { /* * Strip trailing CR + LF... */ char *ptr; /* Pointer into error message */ for (ptr = buffer + strlen(buffer) - 1; ptr >= buffer; ptr --) if (*ptr == '\n' || *ptr == '\r') *ptr = '\0'; else break; } else snprintf(buffer, bufsize, "Unknown error %x", code); return (buffer); } /* * 'http_sspi_verify()' - Verify a certificate. */ static DWORD /* O - Error code (0 == No error) */ http_sspi_verify( PCCERT_CONTEXT cert, /* I - Server certificate */ const char *common_name, /* I - Common name */ DWORD dwCertFlags) /* I - Verification flags */ { HTTPSPolicyCallbackData httpsPolicy; /* HTTPS Policy Struct */ CERT_CHAIN_POLICY_PARA policyPara; /* Cert chain policy parameters */ CERT_CHAIN_POLICY_STATUS policyStatus;/* Cert chain policy status */ CERT_CHAIN_PARA chainPara; /* Used for searching and matching criteria */ PCCERT_CHAIN_CONTEXT chainContext = NULL; /* Certificate chain */ PWSTR commonNameUnicode = NULL; /* Unicode common name */ LPSTR rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE }; /* How are we using this certificate? */ DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR); /* Number of ites in rgszUsages */ DWORD count; /* 32 bit count variable */ DWORD status; /* Return value */ #ifdef DEBUG char error[1024]; /* Error message string */ #endif /* DEBUG */ if (!cert) return (SEC_E_WRONG_PRINCIPAL); /* * Convert common name to Unicode. */ if (!common_name || !*common_name) return (SEC_E_WRONG_PRINCIPAL); count = MultiByteToWideChar(CP_ACP, 0, common_name, -1, NULL, 0); commonNameUnicode = LocalAlloc(LMEM_FIXED, count * sizeof(WCHAR)); if (!commonNameUnicode) return (SEC_E_INSUFFICIENT_MEMORY); if (!MultiByteToWideChar(CP_ACP, 0, common_name, -1, commonNameUnicode, count)) { LocalFree(commonNameUnicode); return (SEC_E_WRONG_PRINCIPAL); } /* * Build certificate chain. */ ZeroMemory(&chainPara, sizeof(chainPara)); chainPara.cbSize = sizeof(chainPara); chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; chainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages; chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages; if (!CertGetCertificateChain(NULL, cert, NULL, cert->hCertStore, &chainPara, 0, NULL, &chainContext)) { status = GetLastError(); DEBUG_printf(("CertGetCertificateChain returned: %s", http_sspi_strerror(error, sizeof(error), status))); LocalFree(commonNameUnicode); return (status); } /* * Validate certificate chain. */ ZeroMemory(&httpsPolicy, sizeof(HTTPSPolicyCallbackData)); httpsPolicy.cbStruct = sizeof(HTTPSPolicyCallbackData); httpsPolicy.dwAuthType = AUTHTYPE_SERVER; httpsPolicy.fdwChecks = dwCertFlags; httpsPolicy.pwszServerName = commonNameUnicode; memset(&policyPara, 0, sizeof(policyPara)); policyPara.cbSize = sizeof(policyPara); policyPara.pvExtraPolicyPara = &httpsPolicy; memset(&policyStatus, 0, sizeof(policyStatus)); policyStatus.cbSize = sizeof(policyStatus); if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext, &policyPara, &policyStatus)) { status = GetLastError(); DEBUG_printf(("CertVerifyCertificateChainPolicy returned %s", http_sspi_strerror(error, sizeof(error), status))); } else if (policyStatus.dwError) status = policyStatus.dwError; else status = SEC_E_OK; if (chainContext) CertFreeCertificateChain(chainContext); if (commonNameUnicode) LocalFree(commonNameUnicode); return (status); } ippsample/cups/auth.c0000644000175000017500000010315413240604116013622 0ustar tilltill/* * Authentication functions for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * This file contains Kerberos support code, copyright 2006 by * Jelmer Vernooij. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #include #include #if defined(WIN32) || defined(__EMX__) # include #else # include #endif /* WIN32 || __EMX__ */ #if HAVE_AUTHORIZATION_H # include # ifdef HAVE_SECBASEPRIV_H # include # else extern const char *cssmErrorString(int error); # endif /* HAVE_SECBASEPRIV_H */ #endif /* HAVE_AUTHORIZATION_H */ #if defined(SO_PEERCRED) && defined(AF_LOCAL) # include #endif /* SO_PEERCRED && AF_LOCAL */ /* * Local functions... */ static const char *cups_auth_find(const char *www_authenticate, const char *scheme); static const char *cups_auth_param(const char *scheme, const char *name, char *value, size_t valsize); static const char *cups_auth_scheme(const char *www_authenticate, char *scheme, size_t schemesize); #ifdef HAVE_GSSAPI # ifdef HAVE_GSS_ACQUIRE_CRED_EX_F # ifdef HAVE_GSS_GSSAPI_SPI_H # include # else # define GSS_AUTH_IDENTITY_TYPE_1 1 # define gss_acquire_cred_ex_f __ApplePrivate_gss_acquire_cred_ex_f typedef struct gss_auth_identity /* @private@ */ { uint32_t type; uint32_t flags; char *username; char *realm; char *password; gss_buffer_t *credentialsRef; } gss_auth_identity_desc; extern OM_uint32 gss_acquire_cred_ex_f(gss_status_id_t, const gss_name_t, OM_uint32, OM_uint32, const gss_OID, gss_cred_usage_t, gss_auth_identity_t, void *, void (*)(void *, OM_uint32, gss_status_id_t, gss_cred_id_t, gss_OID_set, OM_uint32)); # endif /* HAVE_GSS_GSSAPI_SPI_H */ # include typedef struct _cups_gss_acquire_s /* Acquire callback data */ { dispatch_semaphore_t sem; /* Synchronization semaphore */ OM_uint32 major; /* Returned status code */ gss_cred_id_t creds; /* Returned credentials */ } _cups_gss_acquire_t; static void cups_gss_acquire(void *ctx, OM_uint32 major, gss_status_id_t status, gss_cred_id_t creds, gss_OID_set oids, OM_uint32 time_rec); # endif /* HAVE_GSS_ACQUIRE_CRED_EX_F */ static gss_name_t cups_gss_getname(http_t *http, const char *service_name); # ifdef DEBUG static void cups_gss_printf(OM_uint32 major_status, OM_uint32 minor_status, const char *message); # else # define cups_gss_printf(major, minor, message) # endif /* DEBUG */ #endif /* HAVE_GSSAPI */ static int cups_local_auth(http_t *http); /* * 'cupsDoAuthentication()' - Authenticate a request. * * This function should be called in response to a @code HTTP_STATUS_UNAUTHORIZED@ * status, prior to resubmitting your request. * * @since CUPS 1.1.20/macOS 10.4@ */ int /* O - 0 on success, -1 on error */ cupsDoAuthentication( http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *method, /* I - Request method ("GET", "POST", "PUT") */ const char *resource) /* I - Resource path */ { const char *password, /* Password string */ *www_auth, /* WWW-Authenticate header */ *schemedata; /* Scheme-specific data */ char scheme[256], /* Scheme name */ prompt[1024], /* Prompt for user */ realm[HTTP_MAX_VALUE], /* realm="xyz" string */ nonce[HTTP_MAX_VALUE]; /* nonce="xyz" string */ int localauth; /* Local authentication result */ _cups_globals_t *cg; /* Global data */ DEBUG_printf(("cupsDoAuthentication(http=%p, method=\"%s\", resource=\"%s\")", (void *)http, method, resource)); if (!http) http = _cupsConnect(); if (!http || !method || !resource) return (-1); DEBUG_printf(("2cupsDoAuthentication: digest_tries=%d, userpass=\"%s\"", http->digest_tries, http->userpass)); DEBUG_printf(("2cupsDoAuthentication: WWW-Authenticate=\"%s\"", httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE))); /* * Clear the current authentication string... */ httpSetAuthString(http, NULL, NULL); /* * See if we can do local authentication... */ if (http->digest_tries < 3) { if ((localauth = cups_local_auth(http)) == 0) { DEBUG_printf(("2cupsDoAuthentication: authstring=\"%s\"", http->authstring)); if (http->status == HTTP_STATUS_UNAUTHORIZED) http->digest_tries ++; return (0); } else if (localauth == -1) { http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; return (-1); /* Error or canceled */ } } /* * Nope, loop through the authentication schemes to find the first we support. */ www_auth = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE); for (schemedata = cups_auth_scheme(www_auth, scheme, sizeof(scheme)); schemedata; schemedata = cups_auth_scheme(schemedata + strlen(scheme), scheme, sizeof(scheme))) { /* * Check the scheme name... */ #ifdef HAVE_GSSAPI if (!_cups_strcasecmp(scheme, "Negotiate")) { /* * Kerberos authentication... */ if (_cupsSetNegotiateAuthString(http, method, resource)) { http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; return (-1); } break; } else #endif /* HAVE_GSSAPI */ if (_cups_strcasecmp(scheme, "Basic") && _cups_strcasecmp(scheme, "Digest")) continue; /* Not supported (yet) */ /* * See if we should retry the current username:password... */ if ((http->digest_tries > 1 || !http->userpass[0]) && (!_cups_strcasecmp(scheme, "Basic") || (!_cups_strcasecmp(scheme, "Digest")))) { /* * Nope - get a new password from the user... */ char default_username[HTTP_MAX_VALUE]; /* Default username */ cg = _cupsGlobals(); if (!cg->lang_default) cg->lang_default = cupsLangDefault(); if (cups_auth_param(scheme, "username", default_username, sizeof(default_username))) cupsSetUser(default_username); snprintf(prompt, sizeof(prompt), _cupsLangString(cg->lang_default, _("Password for %s on %s? ")), cupsUser(), http->hostname[0] == '/' ? "localhost" : http->hostname); http->digest_tries = _cups_strncasecmp(scheme, "Digest", 6) != 0; http->userpass[0] = '\0'; if ((password = cupsGetPassword2(prompt, http, method, resource)) == NULL) { http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; return (-1); } snprintf(http->userpass, sizeof(http->userpass), "%s:%s", cupsUser(), password); } else if (http->status == HTTP_STATUS_UNAUTHORIZED) http->digest_tries ++; if (http->status == HTTP_STATUS_UNAUTHORIZED && http->digest_tries >= 3) { DEBUG_printf(("1cupsDoAuthentication: Too many authentication tries (%d)", http->digest_tries)); http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; return (-1); } /* * Got a password; encode it for the server... */ if (!_cups_strcasecmp(scheme, "Basic")) { /* * Basic authentication... */ char encode[256]; /* Base64 buffer */ httpEncode64_2(encode, sizeof(encode), http->userpass, (int)strlen(http->userpass)); httpSetAuthString(http, "Basic", encode); } else if (!_cups_strcasecmp(scheme, "Digest")) { /* * Digest authentication... */ int i; /* Looping var */ char algorithm[65], /* Hashing algorithm */ opaque[HTTP_MAX_VALUE], /* Opaque data from server */ cnonce[65], /* cnonce value */ kd[65], /* Final MD5/SHA-256 digest */ ha1[65], /* Hash of username:realm:password */ ha2[65], /* Hash of method:request-uri */ hdata[65], /* Hash of auth data */ temp[1024], /* Temporary string */ digest[1024]; /* Digest auth data */ unsigned char hash[32]; /* Hash buffer */ const char *hashalg; /* Hashing algorithm */ size_t hashsize; /* Size of hash */ if (strcmp(nonce, http->nonce)) { strlcpy(http->nonce, nonce, sizeof(http->nonce)); http->nonce_count = 1; } else http->nonce_count ++; cups_auth_param(schemedata, "opaque", opaque, sizeof(opaque)); cups_auth_param(schemedata, "nonce", nonce, sizeof(nonce)); cups_auth_param(schemedata, "realm", realm, sizeof(realm)); for (i = 0; i < 64; i ++) cnonce[i] = "0123456789ABCDEF"[CUPS_RAND() & 15]; cnonce[64] = '\0'; if (cups_auth_param(schemedata, "algorithm", algorithm, sizeof(algorithm))) { /* * Follow RFC 2617/7616... */ if (!_cups_strcasecmp(algorithm, "MD5")) { /* * RFC 2617 Digest with MD5 */ hashalg = "md5"; } else if (!_cups_strcasecmp(algorithm, "SHA-256")) { /* * RFC 7616 Digest with SHA-256 */ hashalg = "sha2-256"; } else { /* * Some other algorithm we don't support, skip this one... */ continue; } /* * Calculate digest value... */ /* H(A1) = H(username:realm:password) */ snprintf(temp, sizeof(temp), "%s:%s:%s", cupsUser(), realm, strchr(http->userpass, ':') + 1); hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); cupsHashString(hash, hashsize, ha1, sizeof(ha1)); /* H(A2) = H(method:uri) */ snprintf(temp, sizeof(temp), "%s:%s", method, resource); hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); cupsHashString(hash, hashsize, ha2, sizeof(ha2)); /* H(data) = H(nonce:nc:cnonce:qop:H(A2)) */ snprintf(temp, sizeof(temp), "%s:%08x:%s:auth:%s", nonce, http->nonce_count, cnonce, ha2); hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); cupsHashString(hash, hashsize, hdata, sizeof(hdata)); /* KD = H(H(A1):H(data)) */ snprintf(temp, sizeof(temp), "%s:%s", ha1, hdata); hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); cupsHashString(hash, hashsize, kd, sizeof(kd)); /* Pass the RFC 2617/7616 WWW-Authenticate header */ if (opaque[0]) snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", algorithm=%s, qop=auth, opaque=\"%s\", cnonce=\"%s\", nc=%08x, uri=\"%s\", response=\"%s\"", cupsUser(), realm, nonce, algorithm, opaque, cnonce, http->nonce_count, resource, kd); else snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", algorithm=%s, qop=auth, cnonce=\"%s\", nc=%08x, uri=\"%s\", response=\"%s\"", cupsUser(), realm, nonce, algorithm, cnonce, http->nonce_count, resource, kd); } else { /* * Use old RFC 2069 Digest method... */ /* H(A1) = H(username:realm:password) */ snprintf(temp, sizeof(temp), "%s:%s:%s", cupsUser(), realm, strchr(http->userpass, ':') + 1); hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); cupsHashString(hash, hashsize, ha1, sizeof(ha1)); /* H(A2) = H(method:uri) */ snprintf(temp, sizeof(temp), "%s:%s", method, resource); hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); cupsHashString(hash, hashsize, ha2, sizeof(ha2)); /* KD = H(H(A1):nonce:H(A2)) */ snprintf(temp, sizeof(temp), "%s:%s:%s", ha1, nonce, ha2); hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); cupsHashString(hash, hashsize, kd, sizeof(kd)); /* Pass the RFC 2069 WWW-Authenticate header */ snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"", cupsUser(), realm, nonce, resource, kd); } httpSetAuthString(http, "Digest", digest); } } if (http->authstring) { DEBUG_printf(("1cupsDoAuthentication: authstring=\"%s\"", http->authstring)); return (0); } else { DEBUG_printf(("1cupsDoAuthentication: Unknown auth type: \"%s\"", www_auth)); http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; return (-1); } } #ifdef HAVE_GSSAPI /* * '_cupsSetNegotiateAuthString()' - Set the Kerberos authentication string. */ int /* O - 0 on success, -1 on error */ _cupsSetNegotiateAuthString( http_t *http, /* I - Connection to server */ const char *method, /* I - Request method ("GET", "POST", "PUT") */ const char *resource) /* I - Resource path */ { OM_uint32 minor_status, /* Minor status code */ major_status; /* Major status code */ gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; /* Output token */ (void)method; (void)resource; # ifdef __APPLE__ /* * If the weak-linked GSSAPI/Kerberos library is not present, don't try * to use it... */ if (&gss_init_sec_context == NULL) { DEBUG_puts("1_cupsSetNegotiateAuthString: Weak-linked GSSAPI/Kerberos " "framework is not present"); return (-1); } # endif /* __APPLE__ */ if (http->gssname == GSS_C_NO_NAME) { http->gssname = cups_gss_getname(http, _cupsGSSServiceName()); } if (http->gssctx != GSS_C_NO_CONTEXT) { gss_delete_sec_context(&minor_status, &http->gssctx, GSS_C_NO_BUFFER); http->gssctx = GSS_C_NO_CONTEXT; } major_status = gss_init_sec_context(&minor_status, GSS_C_NO_CREDENTIAL, &http->gssctx, http->gssname, http->gssmech, GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG, GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, GSS_C_NO_BUFFER, &http->gssmech, &output_token, NULL, NULL); # ifdef HAVE_GSS_ACQUIRE_CRED_EX_F if (major_status == GSS_S_NO_CRED) { /* * Ask the user for credentials... */ char prompt[1024], /* Prompt for user */ userbuf[256]; /* Kerberos username */ const char *username, /* Username string */ *password; /* Password string */ _cups_gss_acquire_t data; /* Callback data */ gss_auth_identity_desc identity; /* Kerberos user identity */ _cups_globals_t *cg = _cupsGlobals(); /* Per-thread global data */ if (!cg->lang_default) cg->lang_default = cupsLangDefault(); snprintf(prompt, sizeof(prompt), _cupsLangString(cg->lang_default, _("Password for %s on %s? ")), cupsUser(), http->gsshost); if ((password = cupsGetPassword2(prompt, http, method, resource)) == NULL) return (-1); /* * Try to acquire credentials... */ username = cupsUser(); if (!strchr(username, '@')) { snprintf(userbuf, sizeof(userbuf), "%s@%s", username, http->gsshost); username = userbuf; } identity.type = GSS_AUTH_IDENTITY_TYPE_1; identity.flags = 0; identity.username = (char *)username; identity.realm = (char *)""; identity.password = (char *)password; identity.credentialsRef = NULL; data.sem = dispatch_semaphore_create(0); data.major = 0; data.creds = NULL; if (data.sem) { major_status = gss_acquire_cred_ex_f(NULL, GSS_C_NO_NAME, 0, GSS_C_INDEFINITE, GSS_KRB5_MECHANISM, GSS_C_INITIATE, (gss_auth_identity_t)&identity, &data, cups_gss_acquire); if (major_status == GSS_S_COMPLETE) { dispatch_semaphore_wait(data.sem, DISPATCH_TIME_FOREVER); major_status = data.major; } dispatch_release(data.sem); if (major_status == GSS_S_COMPLETE) { OM_uint32 release_minor; /* Minor status from releasing creds */ major_status = gss_init_sec_context(&minor_status, data.creds, &http->gssctx, http->gssname, http->gssmech, GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG, GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, GSS_C_NO_BUFFER, &http->gssmech, &output_token, NULL, NULL); gss_release_cred(&release_minor, &data.creds); } } } # endif /* HAVE_GSS_ACQUIRED_CRED_EX_F */ if (GSS_ERROR(major_status)) { cups_gss_printf(major_status, minor_status, "_cupsSetNegotiateAuthString: Unable to initialize " "security context"); return (-1); } # ifdef DEBUG else if (major_status == GSS_S_CONTINUE_NEEDED) cups_gss_printf(major_status, minor_status, "_cupsSetNegotiateAuthString: Continuation needed!"); # endif /* DEBUG */ if (output_token.length > 0 && output_token.length <= 65536) { /* * Allocate the authorization string since Windows KDCs can have * arbitrarily large credentials... */ int authsize = 10 + /* "Negotiate " */ (int)output_token.length * 4 / 3 + 1 + 1; /* Base64 + nul */ httpSetAuthString(http, NULL, NULL); if ((http->authstring = malloc((size_t)authsize)) == NULL) { http->authstring = http->_authstring; authsize = sizeof(http->_authstring); } strlcpy(http->authstring, "Negotiate ", (size_t)authsize); httpEncode64_2(http->authstring + 10, authsize - 10, output_token.value, (int)output_token.length); gss_release_buffer(&minor_status, &output_token); } else { DEBUG_printf(("1_cupsSetNegotiateAuthString: Kerberos credentials too " "large - %d bytes!", (int)output_token.length)); gss_release_buffer(&minor_status, &output_token); return (-1); } return (0); } #endif /* HAVE_GSSAPI */ /* * 'cups_auth_find()' - Find the named WWW-Authenticate scheme. * * The "www_authenticate" parameter points to the current position in the header. * * Returns @code NULL@ if the auth scheme is not present. */ static const char * /* O - Start of matching scheme or @code NULL@ if not found */ cups_auth_find(const char *www_authenticate, /* I - Pointer into WWW-Authenticate header */ const char *scheme) /* I - Authentication scheme */ { size_t schemelen = strlen(scheme); /* Length of scheme */ DEBUG_printf(("8cups_auth_find(www_authenticate=\"%s\", scheme=\"%s\"(%d))", www_authenticate, scheme, (int)schemelen)); while (*www_authenticate) { /* * Skip leading whitespace and commas... */ DEBUG_printf(("9cups_auth_find: Before whitespace: \"%s\"", www_authenticate)); while (isspace(*www_authenticate & 255) || *www_authenticate == ',') www_authenticate ++; DEBUG_printf(("9cups_auth_find: After whitespace: \"%s\"", www_authenticate)); /* * See if this is "Scheme" followed by whitespace or the end of the string. */ if (!strncmp(www_authenticate, scheme, schemelen) && (isspace(www_authenticate[schemelen] & 255) || !www_authenticate[schemelen])) { /* * Yes, this is the start of the scheme-specific information... */ DEBUG_printf(("9cups_auth_find: Returning \"%s\".", www_authenticate)); return (www_authenticate); } /* * Skip the scheme name or param="value" string... */ while (!isspace(*www_authenticate & 255) && *www_authenticate) { if (*www_authenticate == '\"') { /* * Skip quoted value... */ www_authenticate ++; while (*www_authenticate && *www_authenticate != '\"') www_authenticate ++; DEBUG_printf(("9cups_auth_find: After quoted: \"%s\"", www_authenticate)); } www_authenticate ++; } DEBUG_printf(("9cups_auth_find: After skip: \"%s\"", www_authenticate)); } DEBUG_puts("9cups_auth_find: Returning NULL."); return (NULL); } /* * 'cups_auth_param()' - Copy the value for the named authentication parameter, * if present. */ static const char * /* O - Parameter value or @code NULL@ if not present */ cups_auth_param(const char *scheme, /* I - Pointer to auth data */ const char *name, /* I - Name of parameter */ char *value, /* I - Value buffer */ size_t valsize) /* I - Size of value buffer */ { char *valptr = value, /* Pointer into value buffer */ *valend = value + valsize - 1; /* Pointer to end of buffer */ size_t namelen = strlen(name); /* Name length */ int param; /* Is this a parameter? */ DEBUG_printf(("8cups_auth_param(scheme=\"%s\", name=\"%s\", value=%p, valsize=%d)", scheme, name, (void *)value, (int)valsize)); while (!isspace(*scheme & 255) && *scheme) scheme ++; while (*scheme) { while (isspace(*scheme & 255) || *scheme == ',') scheme ++; if (!strncmp(scheme, name, namelen) && scheme[namelen] == '=') { /* * Found the parameter, copy the value... */ scheme += namelen + 1; if (*scheme == '\"') { scheme ++; while (*scheme && *scheme != '\"') { if (valptr < valend) *valptr++ = *scheme; scheme ++; } } else { while (*scheme && strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~+/=", *scheme)) { if (valptr < valend) *valptr++ = *scheme; scheme ++; } } *valptr = '\0'; DEBUG_printf(("9cups_auth_param: Returning \"%s\".", value)); return (value); } /* * Skip the param=value string... */ param = 0; while (!isspace(*scheme & 255) && *scheme) { if (*scheme == '=') param = 1; else if (*scheme == '\"') { /* * Skip quoted value... */ scheme ++; while (*scheme && *scheme != '\"') scheme ++; } scheme ++; } /* * If this wasn't a parameter, we are at the end of this scheme's * parameters... */ if (!param) break; } *value = '\0'; DEBUG_puts("9cups_auth_param: Returning NULL."); return (NULL); } /* * 'cups_auth_scheme()' - Get the (next) WWW-Authenticate scheme. * * The "www_authenticate" parameter points to the current position in the header. * * Returns @code NULL@ if there are no (more) auth schemes present. */ static const char * /* O - Start of scheme or @code NULL@ if not found */ cups_auth_scheme(const char *www_authenticate, /* I - Pointer into WWW-Authenticate header */ char *scheme, /* I - Scheme name buffer */ size_t schemesize) /* I - Size of buffer */ { const char *start; /* Start of scheme data */ char *sptr = scheme, /* Pointer into scheme buffer */ *send = scheme + schemesize - 1;/* End of scheme buffer */ int param; /* Is this a parameter? */ DEBUG_printf(("8cups_auth_scheme(www_authenticate=\"%s\", scheme=%p, schemesize=%d)", www_authenticate, (void *)scheme, (int)schemesize)); while (*www_authenticate) { /* * Skip leading whitespace and commas... */ while (isspace(*www_authenticate & 255) || *www_authenticate == ',') www_authenticate ++; /* * Parse the scheme name or param="value" string... */ for (sptr = scheme, start = www_authenticate, param = 0; *www_authenticate && !isspace(*www_authenticate & 255); www_authenticate ++) { if (*www_authenticate == '=') param = 1; else if (!param && sptr < send) *sptr++ = *www_authenticate; else if (*www_authenticate == '\"') { /* * Skip quoted value... */ www_authenticate ++; while (*www_authenticate && *www_authenticate != '\"') www_authenticate ++; } } if (sptr > scheme && !param) { *sptr = '\0'; DEBUG_printf(("9cups_auth_scheme: Returning \"%s\".", start)); return (start); } } *scheme = '\0'; DEBUG_puts("9cups_auth_scheme: Returning NULL."); return (NULL); } #ifdef HAVE_GSSAPI # ifdef HAVE_GSS_ACQUIRE_CRED_EX_F /* * 'cups_gss_acquire()' - Kerberos credentials callback. */ static void cups_gss_acquire( void *ctx, /* I - Caller context */ OM_uint32 major, /* I - Major error code */ gss_status_id_t status, /* I - Status (unused) */ gss_cred_id_t creds, /* I - Credentials (if any) */ gss_OID_set oids, /* I - Mechanism OIDs (unused) */ OM_uint32 time_rec) /* I - Timestamp (unused) */ { uint32_t min; /* Minor error code */ _cups_gss_acquire_t *data; /* Callback data */ (void)status; (void)time_rec; data = (_cups_gss_acquire_t *)ctx; data->major = major; data->creds = creds; gss_release_oid_set(&min, &oids); dispatch_semaphore_signal(data->sem); } # endif /* HAVE_GSS_ACQUIRE_CRED_EX_F */ /* * 'cups_gss_getname()' - Get CUPS service credentials for authentication. */ static gss_name_t /* O - Server name */ cups_gss_getname( http_t *http, /* I - Connection to server */ const char *service_name) /* I - Service name */ { gss_buffer_desc token = GSS_C_EMPTY_BUFFER; /* Service token */ OM_uint32 major_status, /* Major status code */ minor_status; /* Minor status code */ gss_name_t server_name; /* Server name */ char buf[1024]; /* Name buffer */ DEBUG_printf(("7cups_gss_getname(http=%p, service_name=\"%s\")", http, service_name)); /* * Get the hostname... */ if (!http->gsshost[0]) { httpGetHostname(http, http->gsshost, sizeof(http->gsshost)); if (!strcmp(http->gsshost, "localhost")) { if (gethostname(http->gsshost, sizeof(http->gsshost)) < 0) { DEBUG_printf(("1cups_gss_getname: gethostname() failed: %s", strerror(errno))); http->gsshost[0] = '\0'; return (NULL); } if (!strchr(http->gsshost, '.')) { /* * The hostname is not a FQDN, so look it up... */ struct hostent *host; /* Host entry to get FQDN */ if ((host = gethostbyname(http->gsshost)) != NULL && host->h_name) { /* * Use the resolved hostname... */ strlcpy(http->gsshost, host->h_name, sizeof(http->gsshost)); } else { DEBUG_printf(("1cups_gss_getname: gethostbyname(\"%s\") failed.", http->gsshost)); http->gsshost[0] = '\0'; return (NULL); } } } } /* * Get a service name we can use for authentication purposes... */ snprintf(buf, sizeof(buf), "%s@%s", service_name, http->gsshost); DEBUG_printf(("8cups_gss_getname: Looking up \"%s\".", buf)); token.value = buf; token.length = strlen(buf); server_name = GSS_C_NO_NAME; major_status = gss_import_name(&minor_status, &token, GSS_C_NT_HOSTBASED_SERVICE, &server_name); if (GSS_ERROR(major_status)) { cups_gss_printf(major_status, minor_status, "cups_gss_getname: gss_import_name() failed"); return (NULL); } return (server_name); } # ifdef DEBUG /* * 'cups_gss_printf()' - Show debug error messages from GSSAPI. */ static void cups_gss_printf(OM_uint32 major_status,/* I - Major status code */ OM_uint32 minor_status,/* I - Minor status code */ const char *message) /* I - Prefix for error message */ { OM_uint32 err_major_status, /* Major status code for display */ err_minor_status; /* Minor status code for display */ OM_uint32 msg_ctx; /* Message context */ gss_buffer_desc major_status_string = GSS_C_EMPTY_BUFFER, /* Major status message */ minor_status_string = GSS_C_EMPTY_BUFFER; /* Minor status message */ msg_ctx = 0; err_major_status = gss_display_status(&err_minor_status, major_status, GSS_C_GSS_CODE, GSS_C_NO_OID, &msg_ctx, &major_status_string); if (!GSS_ERROR(err_major_status)) gss_display_status(&err_minor_status, minor_status, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &minor_status_string); DEBUG_printf(("1%s: %s, %s", message, (char *)major_status_string.value, (char *)minor_status_string.value)); gss_release_buffer(&err_minor_status, &major_status_string); gss_release_buffer(&err_minor_status, &minor_status_string); } # endif /* DEBUG */ #endif /* HAVE_GSSAPI */ /* * 'cups_local_auth()' - Get the local authorization certificate if * available/applicable. */ static int /* O - 0 if available */ /* 1 if not available */ /* -1 error */ cups_local_auth(http_t *http) /* I - HTTP connection to server */ { #if defined(WIN32) || defined(__EMX__) /* * Currently WIN32 and OS-2 do not support the CUPS server... */ return (1); #else int pid; /* Current process ID */ FILE *fp; /* Certificate file */ char trc[16], /* Try Root Certificate parameter */ filename[1024]; /* Certificate filename */ const char *www_auth, /* WWW-Authenticate header */ *schemedata; /* Data for the named auth scheme */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ # if defined(HAVE_AUTHORIZATION_H) OSStatus status; /* Status */ AuthorizationItem auth_right; /* Authorization right */ AuthorizationRights auth_rights; /* Authorization rights */ AuthorizationFlags auth_flags; /* Authorization flags */ AuthorizationExternalForm auth_extrn; /* Authorization ref external */ char auth_key[1024]; /* Buffer */ char buffer[1024]; /* Buffer */ # endif /* HAVE_AUTHORIZATION_H */ DEBUG_printf(("7cups_local_auth(http=%p) hostaddr=%s, hostname=\"%s\"", (void *)http, httpAddrString(http->hostaddr, filename, sizeof(filename)), http->hostname)); /* * See if we are accessing localhost... */ if (!httpAddrLocalhost(http->hostaddr) && _cups_strcasecmp(http->hostname, "localhost") != 0) { DEBUG_puts("8cups_local_auth: Not a local connection!"); return (1); } www_auth = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE); # if defined(HAVE_AUTHORIZATION_H) /* * Delete any previous authorization reference... */ if (http->auth_ref) { AuthorizationFree(http->auth_ref, kAuthorizationFlagDefaults); http->auth_ref = NULL; } if (!getenv("GATEWAY_INTERFACE") && (schemedata = cups_auth_find(www_auth, "AuthRef")) != NULL && cups_auth_param(schemedata, "key", auth_key, sizeof(auth_key))) { status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &http->auth_ref); if (status != errAuthorizationSuccess) { DEBUG_printf(("8cups_local_auth: AuthorizationCreate() returned %d (%s)", (int)status, cssmErrorString(status))); return (-1); } auth_right.name = auth_key; auth_right.valueLength = 0; auth_right.value = NULL; auth_right.flags = 0; auth_rights.count = 1; auth_rights.items = &auth_right; auth_flags = kAuthorizationFlagDefaults | kAuthorizationFlagPreAuthorize | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights; status = AuthorizationCopyRights(http->auth_ref, &auth_rights, kAuthorizationEmptyEnvironment, auth_flags, NULL); if (status == errAuthorizationSuccess) status = AuthorizationMakeExternalForm(http->auth_ref, &auth_extrn); if (status == errAuthorizationSuccess) { /* * Set the authorization string and return... */ httpEncode64_2(buffer, sizeof(buffer), (void *)&auth_extrn, sizeof(auth_extrn)); httpSetAuthString(http, "AuthRef", buffer); DEBUG_printf(("8cups_local_auth: Returning authstring=\"%s\"", http->authstring)); return (0); } else if (status == errAuthorizationCanceled) return (-1); DEBUG_printf(("9cups_local_auth: AuthorizationCopyRights() returned %d (%s)", (int)status, cssmErrorString(status))); /* * Fall through to try certificates... */ } # endif /* HAVE_AUTHORIZATION_H */ # ifdef HAVE_GSSAPI if (cups_auth_find(www_auth, "Negotiate")) return (1); # endif /* HAVE_GSSAPI */ # ifdef HAVE_AUTHORIZATION_H if (cups_auth_find(www_auth, "AuthRef")) return (1); # endif /* HAVE_AUTHORIZATION_H */ # if defined(SO_PEERCRED) && defined(AF_LOCAL) /* * See if we can authenticate using the peer credentials provided over a * domain socket; if so, specify "PeerCred username" as the authentication * information... */ if (http->hostaddr->addr.sa_family == AF_LOCAL && !getenv("GATEWAY_INTERFACE") && /* Not via CGI programs... */ cups_auth_find(www_auth, "PeerCred")) { /* * Verify that the current cupsUser() matches the current UID... */ struct passwd *pwd; /* Password information */ const char *username; /* Current username */ username = cupsUser(); if ((pwd = getpwnam(username)) != NULL && pwd->pw_uid == getuid()) { httpSetAuthString(http, "PeerCred", username); DEBUG_printf(("8cups_local_auth: Returning authstring=\"%s\"", http->authstring)); return (0); } } # endif /* SO_PEERCRED && AF_LOCAL */ if ((schemedata = cups_auth_find(www_auth, "Local")) == NULL) return (1); /* * Try opening a certificate file for this PID. If that fails, * try the root certificate... */ pid = getpid(); snprintf(filename, sizeof(filename), "%s/certs/%d", cg->cups_statedir, pid); if ((fp = fopen(filename, "r")) == NULL && pid > 0) { /* * No certificate for this PID; see if we can get the root certificate... */ DEBUG_printf(("9cups_local_auth: Unable to open file %s: %s", filename, strerror(errno))); if (!cups_auth_param(schemedata, "trc", trc, sizeof(trc))) { /* * Scheduler doesn't want us to use the root certificate... */ return (1); } snprintf(filename, sizeof(filename), "%s/certs/0", cg->cups_statedir); fp = fopen(filename, "r"); } if (fp) { /* * Read the certificate from the file... */ char certificate[33], /* Certificate string */ *certptr; /* Pointer to certificate string */ certptr = fgets(certificate, sizeof(certificate), fp); fclose(fp); if (certptr) { /* * Set the authorization string and return... */ httpSetAuthString(http, "Local", certificate); DEBUG_printf(("8cups_local_auth: Returning authstring=\"%s\"", http->authstring)); return (0); } } return (1); #endif /* WIN32 || __EMX__ */ } ippsample/cups/globals.c0000644000175000017500000002064513240604116014307 0ustar tilltill/* * Global variable access routines for CUPS. * * Copyright 2007-2015 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" /* * Local globals... */ #ifdef DEBUG static int cups_global_index = 0; /* Next thread number */ #endif /* DEBUG */ static _cups_threadkey_t cups_globals_key = _CUPS_THREADKEY_INITIALIZER; /* Thread local storage key */ #ifdef HAVE_PTHREAD_H static pthread_once_t cups_globals_key_once = PTHREAD_ONCE_INIT; /* One-time initialization object */ #endif /* HAVE_PTHREAD_H */ #if defined(HAVE_PTHREAD_H) || defined(WIN32) static _cups_mutex_t cups_global_mutex = _CUPS_MUTEX_INITIALIZER; /* Global critical section */ #endif /* HAVE_PTHREAD_H || WIN32 */ /* * Local functions... */ #ifdef WIN32 static void cups_fix_path(char *path); #endif /* WIN32 */ static _cups_globals_t *cups_globals_alloc(void); #if defined(HAVE_PTHREAD_H) || defined(WIN32) static void cups_globals_free(_cups_globals_t *g); #endif /* HAVE_PTHREAD_H || WIN32 */ #ifdef HAVE_PTHREAD_H static void cups_globals_init(void); #endif /* HAVE_PTHREAD_H */ /* * '_cupsGlobalLock()' - Lock the global mutex. */ void _cupsGlobalLock(void) { #ifdef HAVE_PTHREAD_H pthread_mutex_lock(&cups_global_mutex); #elif defined(WIN32) EnterCriticalSection(&cups_global_mutex.m_criticalSection); #endif /* HAVE_PTHREAD_H */ } /* * '_cupsGlobals()' - Return a pointer to thread local storage */ _cups_globals_t * /* O - Pointer to global data */ _cupsGlobals(void) { _cups_globals_t *cg; /* Pointer to global data */ #ifdef HAVE_PTHREAD_H /* * Initialize the global data exactly once... */ pthread_once(&cups_globals_key_once, cups_globals_init); #endif /* HAVE_PTHREAD_H */ /* * See if we have allocated the data yet... */ if ((cg = (_cups_globals_t *)_cupsThreadGetData(cups_globals_key)) == NULL) { /* * No, allocate memory as set the pointer for the key... */ if ((cg = cups_globals_alloc()) != NULL) _cupsThreadSetData(cups_globals_key, cg); } /* * Return the pointer to the data... */ return (cg); } /* * '_cupsGlobalUnlock()' - Unlock the global mutex. */ void _cupsGlobalUnlock(void) { #ifdef HAVE_PTHREAD_H pthread_mutex_unlock(&cups_global_mutex); #elif defined(WIN32) LeaveCriticalSection(&cups_global_mutex.m_criticalSection); #endif /* HAVE_PTHREAD_H */ } #ifdef WIN32 /* * 'DllMain()' - Main entry for library. */ BOOL WINAPI /* O - Success/failure */ DllMain(HINSTANCE hinst, /* I - DLL module handle */ DWORD reason, /* I - Reason */ LPVOID reserved) /* I - Unused */ { _cups_globals_t *cg; /* Global data */ (void)hinst; (void)reserved; switch (reason) { case DLL_PROCESS_ATTACH : /* Called on library initialization */ InitializeCriticalSection(&cups_global_mutex.m_criticalSection); if ((cups_globals_key = TlsAlloc()) == TLS_OUT_OF_INDEXES) return (FALSE); break; case DLL_THREAD_DETACH : /* Called when a thread terminates */ if ((cg = (_cups_globals_t *)TlsGetValue(cups_globals_key)) != NULL) cups_globals_free(cg); break; case DLL_PROCESS_DETACH : /* Called when library is unloaded */ if ((cg = (_cups_globals_t *)TlsGetValue(cups_globals_key)) != NULL) cups_globals_free(cg); TlsFree(cups_globals_key); DeleteCriticalSection(&cups_global_mutex.m_criticalSection); break; default: break; } return (TRUE); } #endif /* WIN32 */ /* * 'cups_globals_alloc()' - Allocate and initialize global data. */ static _cups_globals_t * /* O - Pointer to global data */ cups_globals_alloc(void) { _cups_globals_t *cg = malloc(sizeof(_cups_globals_t)); /* Pointer to global data */ #ifdef WIN32 HKEY key; /* Registry key */ DWORD size; /* Size of string */ static char installdir[1024] = "", /* Install directory */ confdir[1024] = "", /* Server root directory */ localedir[1024] = ""; /* Locale directory */ #endif /* WIN32 */ if (!cg) return (NULL); /* * Clear the global storage and set the default encryption and password * callback values... */ memset(cg, 0, sizeof(_cups_globals_t)); cg->encryption = (http_encryption_t)-1; cg->password_cb = (cups_password_cb2_t)_cupsGetPassword; cg->trust_first = -1; cg->any_root = -1; cg->expired_certs = -1; cg->validate_certs = -1; #ifdef DEBUG /* * Friendly thread ID for debugging... */ cg->thread_id = ++ cups_global_index; #endif /* DEBUG */ /* * Then set directories as appropriate... */ #ifdef WIN32 if (!installdir[0]) { /* * Open the registry... */ strlcpy(installdir, "C:/Program Files/cups.org", sizeof(installdir)); if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\cups.org", 0, KEY_READ, &key)) { /* * Grab the installation directory... */ char *ptr; /* Pointer into installdir */ size = sizeof(installdir); RegQueryValueEx(key, "installdir", NULL, NULL, installdir, &size); RegCloseKey(key); for (ptr = installdir; *ptr;) { if (*ptr == '\\') { if (ptr[1]) *ptr++ = '/'; else *ptr = '\0'; /* Strip trailing \ */ } else if (*ptr == '/' && !ptr[1]) *ptr = '\0'; /* Strip trailing / */ else ptr ++; } } snprintf(confdir, sizeof(confdir), "%s/conf", installdir); snprintf(localedir, sizeof(localedir), "%s/locale", installdir); } if ((cg->cups_datadir = getenv("CUPS_DATADIR")) == NULL) cg->cups_datadir = installdir; if ((cg->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL) cg->cups_serverbin = installdir; if ((cg->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL) cg->cups_serverroot = confdir; if ((cg->cups_statedir = getenv("CUPS_STATEDIR")) == NULL) cg->cups_statedir = confdir; if ((cg->localedir = getenv("LOCALEDIR")) == NULL) cg->localedir = localedir; #else # ifdef HAVE_GETEUID if ((geteuid() != getuid() && getuid()) || getegid() != getgid()) # else if (!getuid()) # endif /* HAVE_GETEUID */ { /* * When running setuid/setgid, don't allow environment variables to override * the directories... */ cg->cups_datadir = CUPS_DATADIR; cg->cups_serverbin = CUPS_SERVERBIN; cg->cups_serverroot = CUPS_SERVERROOT; cg->cups_statedir = CUPS_STATEDIR; cg->localedir = CUPS_LOCALEDIR; } else { /* * Allow directories to be overridden by environment variables. */ if ((cg->cups_datadir = getenv("CUPS_DATADIR")) == NULL) cg->cups_datadir = CUPS_DATADIR; if ((cg->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL) cg->cups_serverbin = CUPS_SERVERBIN; if ((cg->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL) cg->cups_serverroot = CUPS_SERVERROOT; if ((cg->cups_statedir = getenv("CUPS_STATEDIR")) == NULL) cg->cups_statedir = CUPS_STATEDIR; if ((cg->localedir = getenv("LOCALEDIR")) == NULL) cg->localedir = CUPS_LOCALEDIR; } #endif /* WIN32 */ return (cg); } /* * 'cups_globals_free()' - Free global data. */ #if defined(HAVE_PTHREAD_H) || defined(WIN32) static void cups_globals_free(_cups_globals_t *cg) /* I - Pointer to global data */ { _cups_buffer_t *buffer, /* Current read/write buffer */ *next; /* Next buffer */ if (cg->last_status_message) _cupsStrFree(cg->last_status_message); for (buffer = cg->cups_buffers; buffer; buffer = next) { next = buffer->next; free(buffer); } cupsArrayDelete(cg->leg_size_lut); cupsArrayDelete(cg->ppd_size_lut); cupsArrayDelete(cg->pwg_size_lut); httpClose(cg->http); #ifdef HAVE_SSL _httpFreeCredentials(cg->tls_credentials); #endif /* HAVE_SSL */ cupsFileClose(cg->stdio_files[0]); cupsFileClose(cg->stdio_files[1]); cupsFileClose(cg->stdio_files[2]); cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings); free(cg); } #endif /* HAVE_PTHREAD_H || WIN32 */ #ifdef HAVE_PTHREAD_H /* * 'cups_globals_init()' - Initialize environment variables. */ static void cups_globals_init(void) { /* * Register the global data for this thread... */ pthread_key_create(&cups_globals_key, (void (*)(void *))cups_globals_free); } #endif /* HAVE_PTHREAD_H */ ippsample/cups/language.c0000644000175000017500000012657613240604116014461 0ustar tilltill/* * I18N/language support for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #ifdef HAVE_LANGINFO_H # include #endif /* HAVE_LANGINFO_H */ #ifdef WIN32 # include #else # include #endif /* WIN32 */ #ifdef HAVE_COREFOUNDATION_H # include #endif /* HAVE_COREFOUNDATION_H */ /* * Local globals... */ static _cups_mutex_t lang_mutex = _CUPS_MUTEX_INITIALIZER; /* Mutex to control access to cache */ static cups_lang_t *lang_cache = NULL; /* Language string cache */ static const char * const lang_encodings[] = { /* Encoding strings */ "us-ascii", "iso-8859-1", "iso-8859-2", "iso-8859-3", "iso-8859-4", "iso-8859-5", "iso-8859-6", "iso-8859-7", "iso-8859-8", "iso-8859-9", "iso-8859-10", "utf-8", "iso-8859-13", "iso-8859-14", "iso-8859-15", "cp874", "cp1250", "cp1251", "cp1252", "cp1253", "cp1254", "cp1255", "cp1256", "cp1257", "cp1258", "koi8-r", "koi8-u", "iso-8859-11", "iso-8859-16", "mac", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "cp932", "cp936", "cp949", "cp950", "cp1361", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "euc-cn", "euc-jp", "euc-kr", "euc-tw", "shift_jisx0213" }; #ifdef __APPLE__ typedef struct { const char * const language; /* Language ID */ const char * const locale; /* Locale ID */ } _apple_language_locale_t; static const _apple_language_locale_t apple_language_locale[] = { /* Language to locale ID LUT */ { "en", "en_US" }, { "nb", "no" }, { "nb_NO", "no" }, { "zh-Hans", "zh_CN" }, { "zh_HANS", "zh_CN" }, { "zh-Hant", "zh_TW" }, { "zh_HANT", "zh_TW" }, { "zh-Hant_CN", "zh_TW" } }; #endif /* __APPLE__ */ /* * Local functions... */ #ifdef __APPLE__ static const char *appleLangDefault(void); # ifdef CUPS_BUNDLEDIR # ifndef CF_RETURNS_RETAINED # if __has_feature(attribute_cf_returns_retained) # define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) # else # define CF_RETURNS_RETAINED # endif /* __has_feature(attribute_cf_returns_retained) */ # endif /* !CF_RETURNED_RETAINED */ static cups_array_t *appleMessageLoad(const char *locale) CF_RETURNS_RETAINED; # endif /* CUPS_BUNDLEDIR */ #endif /* __APPLE__ */ static cups_lang_t *cups_cache_lookup(const char *name, cups_encoding_t encoding); static int cups_message_compare(_cups_message_t *m1, _cups_message_t *m2); static void cups_message_free(_cups_message_t *m); static void cups_message_load(cups_lang_t *lang); static void cups_message_puts(cups_file_t *fp, const char *s); static int cups_read_strings(cups_file_t *fp, int flags, cups_array_t *a); static void cups_unquote(char *d, const char *s); #ifdef __APPLE__ /* * '_cupsAppleLanguage()' - Get the Apple language identifier associated with a * locale ID. */ const char * /* O - Language ID */ _cupsAppleLanguage(const char *locale, /* I - Locale ID */ char *language,/* I - Language ID buffer */ size_t langsize) /* I - Size of language ID buffer */ { int i; /* Looping var */ CFStringRef localeid, /* CF locale identifier */ langid; /* CF language identifier */ /* * Copy the locale name and convert, as needed, to the Apple-specific * locale identifier... */ switch (strlen(locale)) { default : /* * Invalid locale... */ strlcpy(language, "en", langsize); break; case 2 : strlcpy(language, locale, langsize); break; case 5 : strlcpy(language, locale, langsize); if (language[2] == '-') { /* * Convert ll-cc to ll_CC... */ language[2] = '_'; language[3] = (char)toupper(language[3] & 255); language[4] = (char)toupper(language[4] & 255); } break; } for (i = 0; i < (int)(sizeof(apple_language_locale) / sizeof(apple_language_locale[0])); i ++) if (!strcmp(locale, apple_language_locale[i].locale)) { strlcpy(language, apple_language_locale[i].language, sizeof(language)); break; } /* * Attempt to map the locale ID to a language ID... */ if ((localeid = CFStringCreateWithCString(kCFAllocatorDefault, language, kCFStringEncodingASCII)) != NULL) { if ((langid = CFLocaleCreateCanonicalLanguageIdentifierFromString( kCFAllocatorDefault, localeid)) != NULL) { CFStringGetCString(langid, language, (CFIndex)langsize, kCFStringEncodingASCII); CFRelease(langid); } CFRelease(localeid); } /* * Return what we got... */ return (language); } /* * '_cupsAppleLocale()' - Get the locale associated with an Apple language ID. */ const char * /* O - Locale */ _cupsAppleLocale(CFStringRef languageName, /* I - Apple language ID */ char *locale, /* I - Buffer for locale */ size_t localesize) /* I - Size of buffer */ { int i; /* Looping var */ CFStringRef localeName; /* Locale as a CF string */ #ifdef DEBUG char temp[1024]; /* Temporary string */ if (!CFStringGetCString(languageName, temp, (CFIndex)sizeof(temp), kCFStringEncodingASCII)) temp[0] = '\0'; DEBUG_printf(("_cupsAppleLocale(languageName=%p(%s), locale=%p, localsize=%d)", (void *)languageName, temp, (void *)locale, (int)localesize)); #endif /* DEBUG */ localeName = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorDefault, languageName); if (localeName) { /* * Copy the locale name and tweak as needed... */ if (!CFStringGetCString(localeName, locale, (CFIndex)localesize, kCFStringEncodingASCII)) *locale = '\0'; DEBUG_printf(("_cupsAppleLocale: locale=\"%s\"", locale)); CFRelease(localeName); /* * Map new language identifiers to locales... */ for (i = 0; i < (int)(sizeof(apple_language_locale) / sizeof(apple_language_locale[0])); i ++) { size_t len = strlen(apple_language_locale[i].language); if (!strcmp(locale, apple_language_locale[i].language) || (!strncmp(locale, apple_language_locale[i].language, len) && (locale[len] == '_' || locale[len] == '-'))) { DEBUG_printf(("_cupsAppleLocale: Updating locale to \"%s\".", apple_language_locale[i].locale)); strlcpy(locale, apple_language_locale[i].locale, localesize); break; } } } else { /* * Just try the Apple language name... */ if (!CFStringGetCString(languageName, locale, (CFIndex)localesize, kCFStringEncodingASCII)) *locale = '\0'; } if (!*locale) { DEBUG_puts("_cupsAppleLocale: Returning NULL."); return (NULL); } /* * Convert language subtag into region subtag... */ if (locale[2] == '-') locale[2] = '_'; else if (locale[3] == '-') locale[3] = '_'; if (!strchr(locale, '.')) strlcat(locale, ".UTF-8", localesize); DEBUG_printf(("_cupsAppleLocale: Returning \"%s\".", locale)); return (locale); } #endif /* __APPLE__ */ /* * '_cupsEncodingName()' - Return the character encoding name string * for the given encoding enumeration. */ const char * /* O - Character encoding */ _cupsEncodingName( cups_encoding_t encoding) /* I - Encoding value */ { if (encoding < CUPS_US_ASCII || encoding >= (cups_encoding_t)(sizeof(lang_encodings) / sizeof(lang_encodings[0]))) { DEBUG_printf(("1_cupsEncodingName(encoding=%d) = out of range (\"%s\")", encoding, lang_encodings[0])); return (lang_encodings[0]); } else { DEBUG_printf(("1_cupsEncodingName(encoding=%d) = \"%s\"", encoding, lang_encodings[encoding])); return (lang_encodings[encoding]); } } /* * 'cupsLangDefault()' - Return the default language. */ cups_lang_t * /* O - Language data */ cupsLangDefault(void) { return (cupsLangGet(NULL)); } /* * 'cupsLangEncoding()' - Return the character encoding (us-ascii, etc.) * for the given language. */ const char * /* O - Character encoding */ cupsLangEncoding(cups_lang_t *lang) /* I - Language data */ { if (lang == NULL) return ((char*)lang_encodings[0]); else return ((char*)lang_encodings[lang->encoding]); } /* * 'cupsLangFlush()' - Flush all language data out of the cache. */ void cupsLangFlush(void) { cups_lang_t *lang, /* Current language */ *next; /* Next language */ /* * Free all languages in the cache... */ _cupsMutexLock(&lang_mutex); for (lang = lang_cache; lang != NULL; lang = next) { /* * Free all messages... */ _cupsMessageFree(lang->strings); /* * Then free the language structure itself... */ next = lang->next; free(lang); } lang_cache = NULL; _cupsMutexUnlock(&lang_mutex); } /* * 'cupsLangFree()' - Free language data. * * This does not actually free anything; use @link cupsLangFlush@ for that. */ void cupsLangFree(cups_lang_t *lang) /* I - Language to free */ { _cupsMutexLock(&lang_mutex); if (lang != NULL && lang->used > 0) lang->used --; _cupsMutexUnlock(&lang_mutex); } /* * 'cupsLangGet()' - Get a language. */ cups_lang_t * /* O - Language data */ cupsLangGet(const char *language) /* I - Language or locale */ { int i; /* Looping var */ #ifndef __APPLE__ char locale[255]; /* Copy of locale name */ #endif /* !__APPLE__ */ char langname[16], /* Requested language name */ country[16], /* Country code */ charset[16], /* Character set */ *csptr, /* Pointer to CODESET string */ *ptr, /* Pointer into language/charset */ real[48]; /* Real language name */ cups_encoding_t encoding; /* Encoding to use */ cups_lang_t *lang; /* Current language... */ static const char * const locale_encodings[] = { /* Locale charset names */ "ASCII", "ISO88591", "ISO88592", "ISO88593", "ISO88594", "ISO88595", "ISO88596", "ISO88597", "ISO88598", "ISO88599", "ISO885910", "UTF8", "ISO885913", "ISO885914", "ISO885915", "CP874", "CP1250", "CP1251", "CP1252", "CP1253", "CP1254", "CP1255", "CP1256", "CP1257", "CP1258", "KOI8R", "KOI8U", "ISO885911", "ISO885916", "MACROMAN", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "CP932", "CP936", "CP949", "CP950", "CP1361", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "EUCCN", "EUCJP", "EUCKR", "EUCTW", "SHIFT_JISX0213" }; DEBUG_printf(("2cupsLangGet(language=\"%s\")", language)); #ifdef __APPLE__ /* * Set the character set to UTF-8... */ strlcpy(charset, "UTF8", sizeof(charset)); /* * Apple's setlocale doesn't give us the user's localization * preference so we have to look it up this way... */ if (!language) { if (!getenv("SOFTWARE") || (language = getenv("LANG")) == NULL) language = appleLangDefault(); DEBUG_printf(("4cupsLangGet: language=\"%s\"", language)); } #else /* * Set the charset to "unknown"... */ charset[0] = '\0'; /* * Use setlocale() to determine the currently set locale, and then * fallback to environment variables to avoid setting the locale, * since setlocale() is not thread-safe! */ if (!language) { /* * First see if the locale has been set; if it is still "C" or * "POSIX", use the environment to get the default... */ # ifdef LC_MESSAGES ptr = setlocale(LC_MESSAGES, NULL); # else ptr = setlocale(LC_ALL, NULL); # endif /* LC_MESSAGES */ DEBUG_printf(("4cupsLangGet: current locale is \"%s\"", ptr)); if (!ptr || !strcmp(ptr, "C") || !strcmp(ptr, "POSIX")) { /* * Get the character set from the LC_CTYPE locale setting... */ if ((ptr = getenv("LC_CTYPE")) == NULL) if ((ptr = getenv("LC_ALL")) == NULL) if ((ptr = getenv("LANG")) == NULL) ptr = "en_US"; if ((csptr = strchr(ptr, '.')) != NULL) { /* * Extract the character set from the environment... */ for (ptr = charset, csptr ++; *csptr; csptr ++) if (ptr < (charset + sizeof(charset) - 1) && _cups_isalnum(*csptr)) *ptr++ = *csptr; *ptr = '\0'; } /* * Get the locale for messages from the LC_MESSAGES locale setting... */ if ((ptr = getenv("LC_MESSAGES")) == NULL) if ((ptr = getenv("LC_ALL")) == NULL) if ((ptr = getenv("LANG")) == NULL) ptr = "en_US"; } if (ptr) { strlcpy(locale, ptr, sizeof(locale)); language = locale; /* * CUPS STR #2575: Map "nb" to "no" for back-compatibility... */ if (!strncmp(locale, "nb", 2)) locale[1] = 'o'; DEBUG_printf(("4cupsLangGet: new language value is \"%s\"", language)); } } #endif /* __APPLE__ */ /* * If "language" is NULL at this point, then chances are we are using * a language that is not installed for the base OS. */ if (!language) { /* * Switch to the POSIX ("C") locale... */ language = "C"; } #ifdef CODESET /* * On systems that support the nl_langinfo(CODESET) call, use * this value as the character set... */ if (!charset[0] && (csptr = nl_langinfo(CODESET)) != NULL) { /* * Copy all of the letters and numbers in the CODESET string... */ for (ptr = charset; *csptr; csptr ++) if (_cups_isalnum(*csptr) && ptr < (charset + sizeof(charset) - 1)) *ptr++ = *csptr; *ptr = '\0'; DEBUG_printf(("4cupsLangGet: charset set to \"%s\" via " "nl_langinfo(CODESET)...", charset)); } #endif /* CODESET */ /* * If we don't have a character set by now, default to UTF-8... */ if (!charset[0]) strlcpy(charset, "UTF8", sizeof(charset)); /* * Parse the language string passed in to a locale string. "C" is the * standard POSIX locale and is copied unchanged. Otherwise the * language string is converted from ll-cc[.charset] (language-country) * to ll_CC[.CHARSET] to match the file naming convention used by all * POSIX-compliant operating systems. Invalid language names are mapped * to the POSIX locale. */ country[0] = '\0'; if (language == NULL || !language[0] || !strcmp(language, "POSIX")) strlcpy(langname, "C", sizeof(langname)); else { /* * Copy the parts of the locale string over safely... */ for (ptr = langname; *language; language ++) if (*language == '_' || *language == '-' || *language == '.') break; else if (ptr < (langname + sizeof(langname) - 1)) *ptr++ = (char)tolower(*language & 255); *ptr = '\0'; if (*language == '_' || *language == '-') { /* * Copy the country code... */ for (language ++, ptr = country; *language; language ++) if (*language == '.') break; else if (ptr < (country + sizeof(country) - 1)) *ptr++ = (char)toupper(*language & 255); *ptr = '\0'; /* * Map Chinese region codes to legacy country codes. */ if (!strcmp(language, "zh") && !strcmp(country, "HANS")) strlcpy(country, "CN", sizeof(country)); if (!strcmp(language, "zh") && !strcmp(country, "HANT")) strlcpy(country, "TW", sizeof(country)); } if (*language == '.' && !charset[0]) { /* * Copy the encoding... */ for (language ++, ptr = charset; *language; language ++) if (_cups_isalnum(*language) && ptr < (charset + sizeof(charset) - 1)) *ptr++ = (char)toupper(*language & 255); *ptr = '\0'; } /* * Force a POSIX locale for an invalid language name... */ if (strlen(langname) != 2 && strlen(langname) != 3) { strlcpy(langname, "C", sizeof(langname)); country[0] = '\0'; charset[0] = '\0'; } } DEBUG_printf(("4cupsLangGet: langname=\"%s\", country=\"%s\", charset=\"%s\"", langname, country, charset)); /* * Figure out the desired encoding... */ encoding = CUPS_AUTO_ENCODING; if (charset[0]) { for (i = 0; i < (int)(sizeof(locale_encodings) / sizeof(locale_encodings[0])); i ++) if (!_cups_strcasecmp(charset, locale_encodings[i])) { encoding = (cups_encoding_t)i; break; } if (encoding == CUPS_AUTO_ENCODING) { /* * Map alternate names for various character sets... */ if (!_cups_strcasecmp(charset, "iso-2022-jp") || !_cups_strcasecmp(charset, "sjis")) encoding = CUPS_WINDOWS_932; else if (!_cups_strcasecmp(charset, "iso-2022-cn")) encoding = CUPS_WINDOWS_936; else if (!_cups_strcasecmp(charset, "iso-2022-kr")) encoding = CUPS_WINDOWS_949; else if (!_cups_strcasecmp(charset, "big5")) encoding = CUPS_WINDOWS_950; } } DEBUG_printf(("4cupsLangGet: encoding=%d(%s)", encoding, encoding == CUPS_AUTO_ENCODING ? "auto" : lang_encodings[encoding])); /* * See if we already have this language/country loaded... */ if (country[0]) snprintf(real, sizeof(real), "%s_%s", langname, country); else strlcpy(real, langname, sizeof(real)); _cupsMutexLock(&lang_mutex); if ((lang = cups_cache_lookup(real, encoding)) != NULL) { _cupsMutexUnlock(&lang_mutex); DEBUG_printf(("3cupsLangGet: Using cached copy of \"%s\"...", real)); return (lang); } /* * See if there is a free language available; if so, use that * record... */ for (lang = lang_cache; lang != NULL; lang = lang->next) if (lang->used == 0) break; if (lang == NULL) { /* * Allocate memory for the language and add it to the cache. */ if ((lang = calloc(sizeof(cups_lang_t), 1)) == NULL) { _cupsMutexUnlock(&lang_mutex); return (NULL); } lang->next = lang_cache; lang_cache = lang; } else { /* * Free all old strings as needed... */ _cupsMessageFree(lang->strings); lang->strings = NULL; } /* * Then assign the language and encoding fields... */ lang->used ++; strlcpy(lang->language, real, sizeof(lang->language)); if (encoding != CUPS_AUTO_ENCODING) lang->encoding = encoding; else lang->encoding = CUPS_UTF8; /* * Return... */ _cupsMutexUnlock(&lang_mutex); return (lang); } /* * '_cupsLangString()' - Get a message string. * * The returned string is UTF-8 encoded; use cupsUTF8ToCharset() to * convert the string to the language encoding. */ const char * /* O - Localized message */ _cupsLangString(cups_lang_t *lang, /* I - Language */ const char *message) /* I - Message */ { const char *s; /* Localized message */ DEBUG_printf(("_cupsLangString(lang=%p, message=\"%s\")", (void *)lang, message)); /* * Range check input... */ if (!lang || !message || !*message) return (message); _cupsMutexLock(&lang_mutex); /* * Load the message catalog if needed... */ if (!lang->strings) cups_message_load(lang); s = _cupsMessageLookup(lang->strings, message); _cupsMutexUnlock(&lang_mutex); return (s); } /* * '_cupsMessageFree()' - Free a messages array. */ void _cupsMessageFree(cups_array_t *a) /* I - Message array */ { #if defined(__APPLE__) && defined(CUPS_BUNDLEDIR) /* * Release the cups.strings dictionary as needed... */ if (cupsArrayUserData(a)) CFRelease((CFDictionaryRef)cupsArrayUserData(a)); #endif /* __APPLE__ && CUPS_BUNDLEDIR */ /* * Free the array... */ cupsArrayDelete(a); } /* * '_cupsMessageLoad()' - Load a .po or .strings file into a messages array. */ cups_array_t * /* O - New message array */ _cupsMessageLoad(const char *filename, /* I - Message catalog to load */ int flags) /* I - Load flags */ { cups_file_t *fp; /* Message file */ cups_array_t *a; /* Message array */ _cups_message_t *m; /* Current message */ char s[4096], /* String buffer */ *ptr, /* Pointer into buffer */ *temp; /* New string */ size_t length, /* Length of combined strings */ ptrlen; /* Length of string */ DEBUG_printf(("4_cupsMessageLoad(filename=\"%s\")", filename)); /* * Create an array to hold the messages... */ if ((a = _cupsMessageNew(NULL)) == NULL) { DEBUG_puts("5_cupsMessageLoad: Unable to allocate array!"); return (NULL); } /* * Open the message catalog file... */ if ((fp = cupsFileOpen(filename, "r")) == NULL) { DEBUG_printf(("5_cupsMessageLoad: Unable to open file: %s", strerror(errno))); return (a); } if (flags & _CUPS_MESSAGE_STRINGS) { while (cups_read_strings(fp, flags, a)); } else { /* * Read messages from the catalog file until EOF... * * The format is the GNU gettext .po format, which is fairly simple: * * msgid "some text" * msgstr "localized text" * * The ID and localized text can span multiple lines using the form: * * msgid "" * "some long text" * msgstr "" * "localized text spanning " * "multiple lines" */ m = NULL; while (cupsFileGets(fp, s, sizeof(s)) != NULL) { /* * Skip blank and comment lines... */ if (s[0] == '#' || !s[0]) continue; /* * Strip the trailing quote... */ if ((ptr = strrchr(s, '\"')) == NULL) continue; *ptr = '\0'; /* * Find start of value... */ if ((ptr = strchr(s, '\"')) == NULL) continue; ptr ++; /* * Unquote the text... */ if (flags & _CUPS_MESSAGE_UNQUOTE) cups_unquote(ptr, ptr); /* * Create or add to a message... */ if (!strncmp(s, "msgid", 5)) { /* * Add previous message as needed... */ if (m) { if (m->str && m->str[0]) { cupsArrayAdd(a, m); } else { /* * Translation is empty, don't add it... (STR #4033) */ free(m->msg); if (m->str) free(m->str); free(m); } } /* * Create a new message with the given msgid string... */ if ((m = (_cups_message_t *)calloc(1, sizeof(_cups_message_t))) == NULL) break; if ((m->msg = strdup(ptr)) == NULL) { free(m); m = NULL; break; } } else if (s[0] == '\"' && m) { /* * Append to current string... */ length = strlen(m->str ? m->str : m->msg); ptrlen = strlen(ptr); if ((temp = realloc(m->str ? m->str : m->msg, length + ptrlen + 1)) == NULL) { if (m->str) free(m->str); free(m->msg); free(m); m = NULL; break; } if (m->str) { /* * Copy the new portion to the end of the msgstr string - safe * to use memcpy because the buffer is allocated to the correct * size... */ m->str = temp; memcpy(m->str + length, ptr, ptrlen + 1); } else { /* * Copy the new portion to the end of the msgid string - safe * to use memcpy because the buffer is allocated to the correct * size... */ m->msg = temp; memcpy(m->msg + length, ptr, ptrlen + 1); } } else if (!strncmp(s, "msgstr", 6) && m) { /* * Set the string... */ if ((m->str = strdup(ptr)) == NULL) { free(m->msg); free(m); m = NULL; break; } } } /* * Add the last message string to the array as needed... */ if (m) { if (m->str && m->str[0]) { cupsArrayAdd(a, m); } else { /* * Translation is empty, don't add it... (STR #4033) */ free(m->msg); if (m->str) free(m->str); free(m); } } } /* * Close the message catalog file and return the new array... */ cupsFileClose(fp); DEBUG_printf(("5_cupsMessageLoad: Returning %d messages...", cupsArrayCount(a))); return (a); } /* * '_cupsMessageLookup()' - Lookup a message string. */ const char * /* O - Localized message */ _cupsMessageLookup(cups_array_t *a, /* I - Message array */ const char *m) /* I - Message */ { _cups_message_t key, /* Search key */ *match; /* Matching message */ DEBUG_printf(("_cupsMessageLookup(a=%p, m=\"%s\")", (void *)a, m)); /* * Lookup the message string; if it doesn't exist in the catalog, * then return the message that was passed to us... */ key.msg = (char *)m; match = (_cups_message_t *)cupsArrayFind(a, &key); #if defined(__APPLE__) && defined(CUPS_BUNDLEDIR) if (!match && cupsArrayUserData(a)) { /* * Try looking the string up in the cups.strings dictionary... */ CFDictionaryRef dict; /* cups.strings dictionary */ CFStringRef cfm, /* Message as a CF string */ cfstr; /* Localized text as a CF string */ dict = (CFDictionaryRef)cupsArrayUserData(a); cfm = CFStringCreateWithCString(kCFAllocatorDefault, m, kCFStringEncodingUTF8); match = calloc(1, sizeof(_cups_message_t)); match->msg = strdup(m); cfstr = cfm ? CFDictionaryGetValue(dict, cfm) : NULL; if (cfstr) { char buffer[1024]; /* Message buffer */ CFStringGetCString(cfstr, buffer, sizeof(buffer), kCFStringEncodingUTF8); match->str = strdup(buffer); DEBUG_printf(("1_cupsMessageLookup: Found \"%s\" as \"%s\"...", m, buffer)); } else { match->str = strdup(m); DEBUG_printf(("1_cupsMessageLookup: Did not find \"%s\"...", m)); } cupsArrayAdd(a, match); if (cfm) CFRelease(cfm); } #endif /* __APPLE__ && CUPS_BUNDLEDIR */ if (match && match->str) return (match->str); else return (m); } /* * '_cupsMessageNew()' - Make a new message catalog array. */ cups_array_t * /* O - Array */ _cupsMessageNew(void *context) /* I - User data */ { return (cupsArrayNew3((cups_array_func_t)cups_message_compare, context, (cups_ahash_func_t)NULL, 0, (cups_acopy_func_t)NULL, (cups_afree_func_t)cups_message_free)); } /* * '_cupsMessageSave()' - Save a message catalog array. */ int /* O - 0 on success, -1 on failure */ _cupsMessageSave(const char *filename,/* I - Output filename */ int flags, /* I - Format flags */ cups_array_t *a) /* I - Message array */ { cups_file_t *fp; /* Output file */ _cups_message_t *m; /* Current message */ /* * Output message catalog file... */ if ((fp = cupsFileOpen(filename, "w")) == NULL) return (-1); /* * Write each message... */ if (flags & _CUPS_MESSAGE_STRINGS) { for (m = (_cups_message_t *)cupsArrayFirst(a); m; m = (_cups_message_t *)cupsArrayNext(a)) { cupsFilePuts(fp, "\""); cups_message_puts(fp, m->msg); cupsFilePuts(fp, "\" = \""); cups_message_puts(fp, m->str); cupsFilePuts(fp, "\";\n"); } } else { for (m = (_cups_message_t *)cupsArrayFirst(a); m; m = (_cups_message_t *)cupsArrayNext(a)) { cupsFilePuts(fp, "msgid \""); cups_message_puts(fp, m->msg); cupsFilePuts(fp, "\"\nmsgstr \""); cups_message_puts(fp, m->str); cupsFilePuts(fp, "\"\n"); } } return (cupsFileClose(fp)); } #ifdef __APPLE__ /* * 'appleLangDefault()' - Get the default locale string. */ static const char * /* O - Locale string */ appleLangDefault(void) { CFBundleRef bundle; /* Main bundle (if any) */ CFArrayRef bundleList; /* List of localizations in bundle */ CFPropertyListRef localizationList = NULL; /* List of localization data */ CFStringRef languageName; /* Current name */ char *lang; /* LANG environment variable */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ DEBUG_puts("2appleLangDefault()"); /* * Only do the lookup and translation the first time. */ if (!cg->language[0]) { if (getenv("SOFTWARE") != NULL && (lang = getenv("LANG")) != NULL) { DEBUG_printf(("3appleLangDefault: Using LANG=%s", lang)); strlcpy(cg->language, lang, sizeof(cg->language)); return (cg->language); } else if ((bundle = CFBundleGetMainBundle()) != NULL && (bundleList = CFBundleCopyBundleLocalizations(bundle)) != NULL) { CFURLRef resources = CFBundleCopyResourcesDirectoryURL(bundle); DEBUG_puts("3appleLangDefault: Getting localizationList from bundle."); if (resources) { CFStringRef cfpath = CFURLCopyPath(resources); char path[1024]; if (cfpath) { /* * See if we have an Info.plist file in the bundle... */ CFStringGetCString(cfpath, path, sizeof(path), kCFStringEncodingUTF8); DEBUG_printf(("3appleLangDefault: Got a resource URL (\"%s\")", path)); strlcat(path, "Contents/Info.plist", sizeof(path)); if (!access(path, R_OK)) localizationList = CFBundleCopyPreferredLocalizationsFromArray(bundleList); else DEBUG_puts("3appleLangDefault: No Info.plist, ignoring resource URL..."); CFRelease(cfpath); } CFRelease(resources); } else DEBUG_puts("3appleLangDefault: No resource URL."); CFRelease(bundleList); } if (!localizationList) { DEBUG_puts("3appleLangDefault: Getting localizationList from preferences."); localizationList = CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication); } if (localizationList) { #ifdef DEBUG if (CFGetTypeID(localizationList) == CFArrayGetTypeID()) DEBUG_printf(("3appleLangDefault: Got localizationList, %d entries.", (int)CFArrayGetCount(localizationList))); else DEBUG_puts("3appleLangDefault: Got localizationList but not an array."); #endif /* DEBUG */ if (CFGetTypeID(localizationList) == CFArrayGetTypeID() && CFArrayGetCount(localizationList) > 0) { languageName = CFArrayGetValueAtIndex(localizationList, 0); if (languageName && CFGetTypeID(languageName) == CFStringGetTypeID()) { if (_cupsAppleLocale(languageName, cg->language, sizeof(cg->language))) DEBUG_printf(("3appleLangDefault: cg->language=\"%s\"", cg->language)); else DEBUG_puts("3appleLangDefault: Unable to get locale."); } } CFRelease(localizationList); } /* * If we didn't find the language, default to en_US... */ if (!cg->language[0]) { DEBUG_puts("3appleLangDefault: Defaulting to en_US."); strlcpy(cg->language, "en_US.UTF-8", sizeof(cg->language)); } } else DEBUG_printf(("3appleLangDefault: Using previous locale \"%s\".", cg->language)); /* * Return the cached locale... */ return (cg->language); } # ifdef CUPS_BUNDLEDIR /* * 'appleMessageLoad()' - Load a message catalog from a localizable bundle. */ static cups_array_t * /* O - Message catalog */ appleMessageLoad(const char *locale) /* I - Locale ID */ { char filename[1024], /* Path to cups.strings file */ applelang[256], /* Apple language ID */ baselang[4]; /* Base language */ CFURLRef url; /* URL to cups.strings file */ CFReadStreamRef stream = NULL; /* File stream */ CFPropertyListRef plist = NULL; /* Localization file */ #ifdef DEBUG const char *cups_strings = getenv("CUPS_STRINGS"); /* Test strings file */ CFErrorRef error = NULL; /* Error when opening file */ #endif /* DEBUG */ DEBUG_printf(("appleMessageLoad(locale=\"%s\")", locale)); /* * Load the cups.strings file... */ #ifdef DEBUG if (cups_strings) { DEBUG_puts("1appleMessageLoad: Using debug CUPS_STRINGS file."); strlcpy(filename, cups_strings, sizeof(filename)); } else #endif /* DEBUG */ snprintf(filename, sizeof(filename), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", _cupsAppleLanguage(locale, applelang, sizeof(applelang))); if (access(filename, 0)) { /* * * * Try with original locale string... */ DEBUG_printf(("1appleMessageLoad: \"%s\": %s", filename, strerror(errno))); snprintf(filename, sizeof(filename), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", locale); } if (access(filename, 0)) { /* * * * Try with just the language code... */ DEBUG_printf(("1appleMessageLoad: \"%s\": %s", filename, strerror(errno))); strlcpy(baselang, locale, sizeof(baselang)); if (baselang[3] == '-' || baselang[3] == '_') baselang[3] = '\0'; snprintf(filename, sizeof(filename), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", baselang); } if (access(filename, 0)) { /* * Try alternate lproj directory names... */ DEBUG_printf(("1appleMessageLoad: \"%s\": %s", filename, strerror(errno))); if (!strncmp(locale, "en", 2)) locale = "English"; else if (!strncmp(locale, "nb", 2)) locale = "no"; else if (!strncmp(locale, "nl", 2)) locale = "Dutch"; else if (!strncmp(locale, "fr", 2)) locale = "French"; else if (!strncmp(locale, "de", 2)) locale = "German"; else if (!strncmp(locale, "it", 2)) locale = "Italian"; else if (!strncmp(locale, "ja", 2)) locale = "Japanese"; else if (!strncmp(locale, "es", 2)) locale = "Spanish"; else if (!strcmp(locale, "zh_HK") || !strncasecmp(locale, "zh-Hant", 7) || !strncasecmp(locale, "zh_Hant", 7)) { /* * * * * Try zh_TW first, then zh... Sigh... */ if (!access(CUPS_BUNDLEDIR "/Resources/zh_TW.lproj/cups.strings", 0)) locale = "zh_TW"; else locale = "zh"; } else if (strstr(locale, "_") != NULL || strstr(locale, "-") != NULL) { /* * Drop country code, just try language... */ strlcpy(baselang, locale, sizeof(baselang)); if (baselang[2] == '-' || baselang[2] == '_') baselang[2] = '\0'; locale = baselang; } snprintf(filename, sizeof(filename), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", locale); } DEBUG_printf(("1appleMessageLoad: filename=\"%s\"", filename)); url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)filename, (CFIndex)strlen(filename), false); if (url) { stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url); if (stream) { /* * Read the property list containing the localization data. * * NOTE: This code currently generates a clang "potential leak" * warning, but the object is released in _cupsMessageFree(). */ CFReadStreamOpen(stream); #ifdef DEBUG plist = CFPropertyListCreateWithStream(kCFAllocatorDefault, stream, 0, kCFPropertyListImmutable, NULL, &error); if (error) { CFStringRef msg = CFErrorCopyDescription(error); /* Error message */ CFStringGetCString(msg, filename, sizeof(filename), kCFStringEncodingUTF8); DEBUG_printf(("1appleMessageLoad: %s", filename)); CFRelease(msg); CFRelease(error); } #else plist = CFPropertyListCreateWithStream(kCFAllocatorDefault, stream, 0, kCFPropertyListImmutable, NULL, NULL); #endif /* DEBUG */ if (plist && CFGetTypeID(plist) != CFDictionaryGetTypeID()) { CFRelease(plist); plist = NULL; } CFRelease(stream); } CFRelease(url); } DEBUG_printf(("1appleMessageLoad: url=%p, stream=%p, plist=%p", url, stream, plist)); /* * Create and return an empty array to act as a cache for messages, passing the * plist as the user data. */ return (_cupsMessageNew((void *)plist)); } # endif /* CUPS_BUNDLEDIR */ #endif /* __APPLE__ */ /* * 'cups_cache_lookup()' - Lookup a language in the cache... */ static cups_lang_t * /* O - Language data or NULL */ cups_cache_lookup( const char *name, /* I - Name of locale */ cups_encoding_t encoding) /* I - Encoding of locale */ { cups_lang_t *lang; /* Current language */ DEBUG_printf(("7cups_cache_lookup(name=\"%s\", encoding=%d(%s))", name, encoding, encoding == CUPS_AUTO_ENCODING ? "auto" : lang_encodings[encoding])); /* * Loop through the cache and return a match if found... */ for (lang = lang_cache; lang != NULL; lang = lang->next) { DEBUG_printf(("9cups_cache_lookup: lang=%p, language=\"%s\", " "encoding=%d(%s)", (void *)lang, lang->language, lang->encoding, lang_encodings[lang->encoding])); if (!strcmp(lang->language, name) && (encoding == CUPS_AUTO_ENCODING || encoding == lang->encoding)) { lang->used ++; DEBUG_puts("8cups_cache_lookup: returning match!"); return (lang); } } DEBUG_puts("8cups_cache_lookup: returning NULL!"); return (NULL); } /* * 'cups_message_compare()' - Compare two messages. */ static int /* O - Result of comparison */ cups_message_compare( _cups_message_t *m1, /* I - First message */ _cups_message_t *m2) /* I - Second message */ { return (strcmp(m1->msg, m2->msg)); } /* * 'cups_message_free()' - Free a message. */ static void cups_message_free(_cups_message_t *m) /* I - Message */ { if (m->msg) free(m->msg); if (m->str) free(m->str); free(m); } /* * 'cups_message_load()' - Load the message catalog for a language. */ static void cups_message_load(cups_lang_t *lang) /* I - Language */ { #if defined(__APPLE__) && defined(CUPS_BUNDLEDIR) lang->strings = appleMessageLoad(lang->language); #else char filename[1024]; /* Filename for language locale file */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ snprintf(filename, sizeof(filename), "%s/%s/cups_%s.po", cg->localedir, lang->language, lang->language); if (strchr(lang->language, '_') && access(filename, 0)) { /* * Country localization not available, look for generic localization... */ snprintf(filename, sizeof(filename), "%s/%.2s/cups_%.2s.po", cg->localedir, lang->language, lang->language); if (access(filename, 0)) { /* * No generic localization, so use POSIX... */ DEBUG_printf(("4cups_message_load: access(\"%s\", 0): %s", filename, strerror(errno))); snprintf(filename, sizeof(filename), "%s/C/cups_C.po", cg->localedir); } } /* * Read the strings from the file... */ lang->strings = _cupsMessageLoad(filename, _CUPS_MESSAGE_UNQUOTE); #endif /* __APPLE__ && CUPS_BUNDLEDIR */ } /* * 'cups_message_puts()' - Write a message string with quoting. */ static void cups_message_puts(cups_file_t *fp, /* I - File to write to */ const char *s) /* I - String to write */ { const char *start, /* Start of substring */ *ptr; /* Pointer into string */ for (start = s, ptr = s; *ptr; ptr ++) { if (strchr("\\\"\n\t", *ptr)) { if (ptr > start) { cupsFileWrite(fp, start, (size_t)(ptr - start)); start = ptr + 1; } if (*ptr == '\\') cupsFileWrite(fp, "\\\\", 2); else if (*ptr == '\"') cupsFileWrite(fp, "\\\"", 2); else if (*ptr == '\n') cupsFileWrite(fp, "\\n", 2); else /* if (*ptr == '\t') */ cupsFileWrite(fp, "\\t", 2); } } if (ptr > start) cupsFileWrite(fp, start, (size_t)(ptr - start)); } /* * 'cups_read_strings()' - Read a pair of strings from a .strings file. */ static int /* O - 1 on success, 0 on failure */ cups_read_strings(cups_file_t *fp, /* I - .strings file */ int flags, /* I - CUPS_MESSAGE_xxx flags */ cups_array_t *a) /* I - Message catalog array */ { char buffer[8192], /* Line buffer */ *bufptr, /* Pointer into buffer */ *msg, /* Pointer to start of message */ *str; /* Pointer to start of translation string */ _cups_message_t *m; /* New message */ while (cupsFileGets(fp, buffer, sizeof(buffer))) { /* * Skip any line (comments, blanks, etc.) that isn't: * * "message" = "translation"; */ for (bufptr = buffer; *bufptr && isspace(*bufptr & 255); bufptr ++); if (*bufptr != '\"') continue; /* * Find the end of the message... */ bufptr ++; for (msg = bufptr; *bufptr && *bufptr != '\"'; bufptr ++) if (*bufptr == '\\' && bufptr[1]) bufptr ++; if (!*bufptr) continue; *bufptr++ = '\0'; if (flags & _CUPS_MESSAGE_UNQUOTE) cups_unquote(msg, msg); /* * Find the start of the translation... */ while (*bufptr && isspace(*bufptr & 255)) bufptr ++; if (*bufptr != '=') continue; bufptr ++; while (*bufptr && isspace(*bufptr & 255)) bufptr ++; if (*bufptr != '\"') continue; /* * Find the end of the translation... */ bufptr ++; for (str = bufptr; *bufptr && *bufptr != '\"'; bufptr ++) if (*bufptr == '\\' && bufptr[1]) bufptr ++; if (!*bufptr) continue; *bufptr++ = '\0'; if (flags & _CUPS_MESSAGE_UNQUOTE) cups_unquote(str, str); /* * If we get this far we have a valid pair of strings, add them... */ if ((m = malloc(sizeof(_cups_message_t))) == NULL) break; m->msg = strdup(msg); m->str = strdup(str); if (m->msg && m->str) { cupsArrayAdd(a, m); } else { if (m->msg) free(m->msg); if (m->str) free(m->str); free(m); break; } return (1); } /* * No more strings... */ return (0); } /* * 'cups_unquote()' - Unquote characters in strings... */ static void cups_unquote(char *d, /* O - Unquoted string */ const char *s) /* I - Original string */ { while (*s) { if (*s == '\\') { s ++; if (isdigit(*s)) { *d = 0; while (isdigit(*s)) { *d = *d * 8 + *s - '0'; s ++; } d ++; } else { if (*s == 'n') *d ++ = '\n'; else if (*s == 'r') *d ++ = '\r'; else if (*s == 't') *d ++ = '\t'; else *d++ = *s; s ++; } } else *d++ = *s++; } *d = '\0'; } ippsample/cups/ipp-vars.c0000644000175000017500000001267613240604116014432 0ustar tilltill/* * IPP data file parsing functions. * * Copyright © 2007-2018 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ /* * Include necessary headers... */ #include #include "ipp-private.h" #include "string-private.h" /* * '_ippVarsDeinit()' - Free all memory associated with the IPP variables. */ void _ippVarsDeinit(_ipp_vars_t *v) /* I - IPP variables */ { if (v->uri) { free(v->uri); v->uri = NULL; } cupsFreeOptions(v->num_vars, v->vars); v->num_vars = 0; v->vars = NULL; } /* * '_ippVarsExpand()' - Expand variables in the source string. */ void _ippVarsExpand(_ipp_vars_t *v, /* I - IPP variables */ char *dst, /* I - Destination buffer */ const char *src, /* I - Source string */ size_t dstsize) /* I - Destination buffer size */ { char *dstptr, /* Pointer into destination */ *dstend, /* End of destination */ temp[256], /* Temporary string */ *tempptr; /* Pointer into temporary string */ const char *value; /* Value to substitute */ dstptr = dst; dstend = dst + dstsize - 1; while (*src && dstptr < dstend) { if (*src == '$') { /* * Substitute a string/number... */ if (!strncmp(src, "$$", 2)) { value = "$"; src += 2; } else if (!strncmp(src, "$ENV[", 5)) { strlcpy(temp, src + 5, sizeof(temp)); for (tempptr = temp; *tempptr; tempptr ++) if (*tempptr == ']') break; if (*tempptr) *tempptr++ = '\0'; value = getenv(temp); src += tempptr - temp + 5; } else { if (src[1] == '{') { src += 2; strlcpy(temp, src, sizeof(temp)); if ((tempptr = strchr(temp, '}')) != NULL) *tempptr = '\0'; else tempptr = temp + strlen(temp); } else { strlcpy(temp, src + 1, sizeof(temp)); for (tempptr = temp; *tempptr; tempptr ++) if (!isalnum(*tempptr & 255) && *tempptr != '-' && *tempptr != '_') break; if (*tempptr) *tempptr = '\0'; } value = _ippVarsGet(v, temp); src += tempptr - temp + 1; } if (value) { strlcpy(dstptr, value, (size_t)(dstend - dstptr + 1)); dstptr += strlen(dstptr); } } else *dstptr++ = *src++; } *dstptr = '\0'; } /* * '_ippVarsGet()' - Get a variable string. */ const char * /* O - Value or @code NULL@ if not set */ _ippVarsGet(_ipp_vars_t *v, /* I - IPP variables */ const char *name) /* I - Variable name */ { if (!strcmp(name, "uri")) return (v->uri); else if (!strcmp(name, "uriuser") || !strcmp(name, "username")) return (v->username[0] ? v->username : NULL); else if (!strcmp(name, "scheme") || !strcmp(name, "method")) return (v->scheme); else if (!strcmp(name, "hostname")) return (v->host); else if (!strcmp(name, "port")) return (v->portstr); else if (!strcmp(name, "resource")) return (v->resource); else if (!strcmp(name, "user")) return (cupsUser()); else return (cupsGetOption(name, v->num_vars, v->vars)); } /* * '_ippVarsInit()' - Initialize . */ void _ippVarsInit(_ipp_vars_t *v, /* I - IPP variables */ _ipp_fattr_cb_t attrcb, /* I - Attribute (filter) callback */ _ipp_ferror_cb_t errorcb, /* I - Error callback */ _ipp_ftoken_cb_t tokencb) /* I - Token callback */ { memset(v, 0, sizeof(_ipp_vars_t)); v->attrcb = attrcb; v->errorcb = errorcb; v->tokencb = tokencb; } /* * '_ippVarsPasswordCB()' - Password callback using the IPP variables. */ const char * /* O - Password string or @code NULL@ */ _ippVarsPasswordCB( const char *prompt, /* I - Prompt string (not used) */ http_t *http, /* I - HTTP connection (not used) */ const char *method, /* I - HTTP method (not used) */ const char *resource, /* I - Resource path (not used) */ void *user_data) /* I - IPP variables */ { _ipp_vars_t *v = (_ipp_vars_t *)user_data; /* I - IPP variables */ (void)prompt; (void)http; (void)method; (void)resource; if (v->username[0] && v->password && v->password_tries < 3) { v->password_tries ++; cupsSetUser(v->username); return (v->password); } else { return (NULL); } } /* * '_ippVarsSet()' - Set an IPP variable. */ int /* O - 1 on success, 0 on failure */ _ippVarsSet(_ipp_vars_t *v, /* I - IPP variables */ const char *name, /* I - Variable name */ const char *value) /* I - Variable value */ { if (!strcmp(name, "uri")) { char uri[1024]; /* New printer URI */ http_uri_status_t uri_status; /* URI status */ if ((uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, value, v->scheme, sizeof(v->scheme), v->username, sizeof(v->username), v->host, sizeof(v->host), &(v->port), v->resource, sizeof(v->resource))) < HTTP_URI_STATUS_OK) return (0); if (v->username[0]) { if ((v->password = strchr(v->username, ':')) != NULL) *(v->password)++ = '\0'; } snprintf(v->portstr, sizeof(v->portstr), "%d", v->port); if (v->uri) free(v->uri); httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), v->scheme, NULL, v->host, v->port, v->resource); v->uri = strdup(uri); return (v->uri != NULL); } else { v->num_vars = cupsAddOption(name, value, v->num_vars, &v->vars); return (1); } } ippsample/cups/dest-job.c0000644000175000017500000002657413240604116014402 0ustar tilltill/* * Destination job support for CUPS. * * Copyright 2012-2017 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" /* * 'cupsCancelDestJob()' - Cancel a job on a destination. * * The "job_id" is the number returned by cupsCreateDestJob. * * Returns @code IPP_STATUS_OK@ on success and * @code IPP_STATUS_ERROR_NOT_AUTHORIZED@ or * @code IPP_STATUS_ERROR_FORBIDDEN@ on failure. * * @since CUPS 1.6/macOS 10.8@ */ ipp_status_t /* O - Status of cancel operation */ cupsCancelDestJob(http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ int job_id) /* I - Job ID */ { cups_dinfo_t *info; /* Destination information */ if ((info = cupsCopyDestInfo(http, dest)) != NULL) { ipp_t *request; /* Cancel-Job request */ request = ippNewRequest(IPP_OP_CANCEL_JOB); ippSetVersion(request, info->version / 10, info->version % 10); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, info->uri); ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippDelete(cupsDoRequest(http, request, info->resource)); cupsFreeDestInfo(info); } return (cupsLastError()); } /* * 'cupsCloseDestJob()' - Close a job and start printing. * * Use when the last call to cupsStartDocument passed 0 for "last_document". * "job_id" is the job ID returned by cupsCreateDestJob. Returns @code IPP_STATUS_OK@ * on success. * * @since CUPS 1.6/macOS 10.8@ */ ipp_status_t /* O - IPP status code */ cupsCloseDestJob( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *info, /* I - Destination information */ int job_id) /* I - Job ID */ { int i; /* Looping var */ ipp_t *request = NULL;/* Close-Job/Send-Document request */ ipp_attribute_t *attr; /* operations-supported attribute */ DEBUG_printf(("cupsCloseDestJob(http=%p, dest=%p(%s/%s), info=%p, job_id=%d)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info, job_id)); /* * Get the default connection as needed... */ if (!http) http = _cupsConnect(); /* * Range check input... */ if (!http || !dest || !info || job_id <= 0) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); DEBUG_puts("1cupsCloseDestJob: Bad arguments."); return (IPP_STATUS_ERROR_INTERNAL); } /* * Build a Close-Job or empty Send-Document request... */ if ((attr = ippFindAttribute(info->attrs, "operations-supported", IPP_TAG_ENUM)) != NULL) { for (i = 0; i < attr->num_values; i ++) if (attr->values[i].integer == IPP_OP_CLOSE_JOB) { request = ippNewRequest(IPP_OP_CLOSE_JOB); break; } } if (!request) request = ippNewRequest(IPP_OP_SEND_DOCUMENT); if (!request) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0); DEBUG_puts("1cupsCloseDestJob: Unable to create Close-Job/Send-Document " "request."); return (IPP_STATUS_ERROR_INTERNAL); } ippSetVersion(request, info->version / 10, info->version % 10); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, info->uri); ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); if (ippGetOperation(request) == IPP_OP_SEND_DOCUMENT) ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1); /* * Send the request and return the status... */ ippDelete(cupsDoRequest(http, request, info->resource)); DEBUG_printf(("1cupsCloseDestJob: %s (%s)", ippErrorString(cupsLastError()), cupsLastErrorString())); return (cupsLastError()); } /* * 'cupsCreateDestJob()' - Create a job on a destination. * * Returns @code IPP_STATUS_OK@ or @code IPP_STATUS_OK_SUBST@ on success, saving the job ID * in the variable pointed to by "job_id". * * @since CUPS 1.6/macOS 10.8@ */ ipp_status_t /* O - IPP status code */ cupsCreateDestJob( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *info, /* I - Destination information */ int *job_id, /* O - Job ID or 0 on error */ const char *title, /* I - Job name */ int num_options, /* I - Number of job options */ cups_option_t *options) /* I - Job options */ { ipp_t *request, /* Create-Job request */ *response; /* Create-Job response */ ipp_attribute_t *attr; /* job-id attribute */ DEBUG_printf(("cupsCreateDestJob(http=%p, dest=%p(%s/%s), info=%p, " "job_id=%p, title=\"%s\", num_options=%d, options=%p)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info, (void *)job_id, title, num_options, (void *)options)); /* * Get the default connection as needed... */ if (!http) http = _cupsConnect(); /* * Range check input... */ if (job_id) *job_id = 0; if (!http || !dest || !info || !job_id) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); DEBUG_puts("1cupsCreateDestJob: Bad arguments."); return (IPP_STATUS_ERROR_INTERNAL); } /* * Build a Create-Job request... */ if ((request = ippNewRequest(IPP_OP_CREATE_JOB)) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0); DEBUG_puts("1cupsCreateDestJob: Unable to create Create-Job request."); return (IPP_STATUS_ERROR_INTERNAL); } ippSetVersion(request, info->version / 10, info->version % 10); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, info->uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); if (title) ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, title); cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION); cupsEncodeOptions2(request, num_options, options, IPP_TAG_JOB); cupsEncodeOptions2(request, num_options, options, IPP_TAG_SUBSCRIPTION); /* * Send the request and get the job-id... */ response = cupsDoRequest(http, request, info->resource); if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL) { *job_id = attr->values[0].integer; DEBUG_printf(("1cupsCreateDestJob: job-id=%d", *job_id)); } ippDelete(response); /* * Return the status code from the Create-Job request... */ DEBUG_printf(("1cupsCreateDestJob: %s (%s)", ippErrorString(cupsLastError()), cupsLastErrorString())); return (cupsLastError()); } /* * 'cupsFinishDestDocument()' - Finish the current document. * * Returns @code IPP_STATUS_OK@ or @code IPP_STATUS_OK_SUBST@ on success. * * @since CUPS 1.6/macOS 10.8@ */ ipp_status_t /* O - Status of document submission */ cupsFinishDestDocument( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *info) /* I - Destination information */ { DEBUG_printf(("cupsFinishDestDocument(http=%p, dest=%p(%s/%s), info=%p)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info)); /* * Get the default connection as needed... */ if (!http) http = _cupsConnect(); /* * Range check input... */ if (!http || !dest || !info) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); DEBUG_puts("1cupsFinishDestDocument: Bad arguments."); return (IPP_STATUS_ERROR_INTERNAL); } /* * Get the response at the end of the document and return it... */ ippDelete(cupsGetResponse(http, info->resource)); DEBUG_printf(("1cupsFinishDestDocument: %s (%s)", ippErrorString(cupsLastError()), cupsLastErrorString())); return (cupsLastError()); } /* * 'cupsStartDestDocument()' - Start a new document. * * "job_id" is the job ID returned by cupsCreateDestJob. "docname" is the name * of the document/file being printed, "format" is the MIME media type for the * document (see CUPS_FORMAT_xxx constants), and "num_options" and "options" * are the options do be applied to the document. "last_document" should be 1 * if this is the last document to be submitted in the job. Returns * @code HTTP_CONTINUE@ on success. * * @since CUPS 1.6/macOS 10.8@ */ http_status_t /* O - Status of document creation */ cupsStartDestDocument( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *info, /* I - Destination information */ int job_id, /* I - Job ID */ const char *docname, /* I - Document name */ const char *format, /* I - Document format */ int num_options, /* I - Number of document options */ cups_option_t *options, /* I - Document options */ int last_document) /* I - 1 if this is the last document */ { ipp_t *request; /* Send-Document request */ http_status_t status; /* HTTP status */ DEBUG_printf(("cupsStartDestDocument(http=%p, dest=%p(%s/%s), info=%p, job_id=%d, docname=\"%s\", format=\"%s\", num_options=%d, options=%p, last_document=%d)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info, job_id, docname, format, num_options, (void *)options, last_document)); /* * Get the default connection as needed... */ if (!http) http = _cupsConnect(); /* * Range check input... */ if (!http || !dest || !info || job_id <= 0) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); DEBUG_puts("1cupsStartDestDocument: Bad arguments."); return (HTTP_STATUS_ERROR); } /* * Create a Send-Document request... */ if ((request = ippNewRequest(IPP_OP_SEND_DOCUMENT)) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0); DEBUG_puts("1cupsStartDestDocument: Unable to create Send-Document " "request."); return (HTTP_STATUS_ERROR); } ippSetVersion(request, info->version / 10, info->version % 10); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, info->uri); ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job_id); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); if (docname) ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name", NULL, docname); if (format) ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, format); ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", (char)last_document); cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION); cupsEncodeOptions2(request, num_options, options, IPP_TAG_DOCUMENT); /* * Send and delete the request, then return the status... */ status = cupsSendRequest(http, request, info->resource, CUPS_LENGTH_VARIABLE); ippDelete(request); return (status); } ippsample/cups/file-private.h0000644000175000017500000000643013240604116015254 0ustar tilltill/* * Private file definitions for CUPS. * * Since stdio files max out at 256 files on many systems, we have to * write similar functions without this limit. At the same time, using * our own file functions allows us to provide transparent support of * different line endings, gzip'd print files, PPD files, etc. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_FILE_PRIVATE_H_ # define _CUPS_FILE_PRIVATE_H_ /* * Include necessary headers... */ # include "cups-private.h" # include # include # include # include # ifdef HAVE_LIBZ # include # endif /* HAVE_LIBZ */ # ifdef WIN32 # include # include # endif /* WIN32 */ /* * Some operating systems support large files via open flag O_LARGEFILE... */ # ifndef O_LARGEFILE # define O_LARGEFILE 0 # endif /* !O_LARGEFILE */ /* * Some operating systems don't define O_BINARY, which is used by Microsoft * and IBM to flag binary files... */ # ifndef O_BINARY # define O_BINARY 0 # endif /* !O_BINARY */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Types and structures... */ typedef enum /**** _cupsFileCheck return values ****/ { _CUPS_FILE_CHECK_OK = 0, /* Everything OK */ _CUPS_FILE_CHECK_MISSING = 1, /* File is missing */ _CUPS_FILE_CHECK_PERMISSIONS = 2, /* File (or parent dir) has bad perms */ _CUPS_FILE_CHECK_WRONG_TYPE = 3, /* File has wrong type */ _CUPS_FILE_CHECK_RELATIVE_PATH = 4 /* File contains a relative path */ } _cups_fc_result_t; typedef enum /**** _cupsFileCheck file type values ****/ { _CUPS_FILE_CHECK_FILE = 0, /* Check the file and parent directory */ _CUPS_FILE_CHECK_PROGRAM = 1, /* Check the program and parent directory */ _CUPS_FILE_CHECK_FILE_ONLY = 2, /* Check the file only */ _CUPS_FILE_CHECK_DIRECTORY = 3 /* Check the directory */ } _cups_fc_filetype_t; typedef void (*_cups_fc_func_t)(void *context, _cups_fc_result_t result, const char *message); struct _cups_file_s /**** CUPS file structure... ****/ { int fd; /* File descriptor */ char mode, /* Mode ('r' or 'w') */ compressed, /* Compression used? */ is_stdio, /* stdin/out/err? */ eof, /* End of file? */ buf[4096], /* Buffer */ *ptr, /* Pointer into buffer */ *end; /* End of buffer data */ off_t pos, /* Position in file */ bufpos; /* File position for start of buffer */ #ifdef HAVE_LIBZ z_stream stream; /* (De)compression stream */ Bytef cbuf[4096]; /* (De)compression buffer */ uLong crc; /* (De)compression CRC */ #endif /* HAVE_LIBZ */ char *printf_buffer; /* cupsFilePrintf buffer */ size_t printf_size; /* Size of cupsFilePrintf buffer */ }; /* * Prototypes... */ extern _cups_fc_result_t _cupsFileCheck(const char *filename, _cups_fc_filetype_t filetype, int dorootchecks, _cups_fc_func_t cb, void *context); extern void _cupsFileCheckFilter(void *context, _cups_fc_result_t result, const char *message); # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_FILE_PRIVATE_H_ */ ippsample/cups/file.c0000644000175000017500000015636413240604116013613 0ustar tilltill/* * File functions for CUPS. * * Since stdio files max out at 256 files on many systems, we have to * write similar functions without this limit. At the same time, using * our own file functions allows us to provide transparent support of * different line endings, gzip'd print files, PPD files, etc. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "file-private.h" #include #include /* * Local functions... */ #ifdef HAVE_LIBZ static ssize_t cups_compress(cups_file_t *fp, const char *buf, size_t bytes); #endif /* HAVE_LIBZ */ static ssize_t cups_fill(cups_file_t *fp); static int cups_open(const char *filename, int mode); static ssize_t cups_read(cups_file_t *fp, char *buf, size_t bytes); static ssize_t cups_write(cups_file_t *fp, const char *buf, size_t bytes); #ifndef WIN32 /* * '_cupsFileCheck()' - Check the permissions of the given filename. */ _cups_fc_result_t /* O - Check result */ _cupsFileCheck( const char *filename, /* I - Filename to check */ _cups_fc_filetype_t filetype, /* I - Type of file checks? */ int dorootchecks, /* I - Check for root permissions? */ _cups_fc_func_t cb, /* I - Callback function */ void *context) /* I - Context pointer for callback */ { struct stat fileinfo; /* File information */ char message[1024], /* Message string */ temp[1024], /* Parent directory filename */ *ptr; /* Pointer into parent directory */ _cups_fc_result_t result; /* Check result */ /* * Does the filename contain a relative path ("../")? */ if (strstr(filename, "../")) { /* * Yes, fail it! */ result = _CUPS_FILE_CHECK_RELATIVE_PATH; goto finishup; } /* * Does the program even exist and is it accessible? */ if (stat(filename, &fileinfo)) { /* * Nope... */ result = _CUPS_FILE_CHECK_MISSING; goto finishup; } /* * Check the execute bit... */ result = _CUPS_FILE_CHECK_OK; switch (filetype) { case _CUPS_FILE_CHECK_DIRECTORY : if (!S_ISDIR(fileinfo.st_mode)) result = _CUPS_FILE_CHECK_WRONG_TYPE; break; default : if (!S_ISREG(fileinfo.st_mode)) result = _CUPS_FILE_CHECK_WRONG_TYPE; break; } if (result) goto finishup; /* * Are we doing root checks? */ if (!dorootchecks) { /* * Nope, so anything (else) goes... */ goto finishup; } /* * Verify permission of the file itself: * * 1. Must be owned by root * 2. Must not be writable by group * 3. Must not be setuid * 4. Must not be writable by others */ if (fileinfo.st_uid || /* 1. Must be owned by root */ (fileinfo.st_mode & S_IWGRP) || /* 2. Must not be writable by group */ (fileinfo.st_mode & S_ISUID) || /* 3. Must not be setuid */ (fileinfo.st_mode & S_IWOTH)) /* 4. Must not be writable by others */ { result = _CUPS_FILE_CHECK_PERMISSIONS; goto finishup; } if (filetype == _CUPS_FILE_CHECK_DIRECTORY || filetype == _CUPS_FILE_CHECK_FILE_ONLY) goto finishup; /* * Now check the containing directory... */ strlcpy(temp, filename, sizeof(temp)); if ((ptr = strrchr(temp, '/')) != NULL) { if (ptr == temp) ptr[1] = '\0'; else *ptr = '\0'; } if (stat(temp, &fileinfo)) { /* * Doesn't exist?!? */ result = _CUPS_FILE_CHECK_MISSING; filetype = _CUPS_FILE_CHECK_DIRECTORY; filename = temp; goto finishup; } if (fileinfo.st_uid || /* 1. Must be owned by root */ (fileinfo.st_mode & S_IWGRP) || /* 2. Must not be writable by group */ (fileinfo.st_mode & S_ISUID) || /* 3. Must not be setuid */ (fileinfo.st_mode & S_IWOTH)) /* 4. Must not be writable by others */ { result = _CUPS_FILE_CHECK_PERMISSIONS; filetype = _CUPS_FILE_CHECK_DIRECTORY; filename = temp; } /* * Common return point... */ finishup: if (cb) { cups_lang_t *lang = cupsLangDefault(); /* Localization information */ switch (result) { case _CUPS_FILE_CHECK_OK : if (filetype == _CUPS_FILE_CHECK_DIRECTORY) snprintf(message, sizeof(message), _cupsLangString(lang, _("Directory \"%s\" permissions OK " "(0%o/uid=%d/gid=%d).")), filename, fileinfo.st_mode, (int)fileinfo.st_uid, (int)fileinfo.st_gid); else snprintf(message, sizeof(message), _cupsLangString(lang, _("File \"%s\" permissions OK " "(0%o/uid=%d/gid=%d).")), filename, fileinfo.st_mode, (int)fileinfo.st_uid, (int)fileinfo.st_gid); break; case _CUPS_FILE_CHECK_MISSING : if (filetype == _CUPS_FILE_CHECK_DIRECTORY) snprintf(message, sizeof(message), _cupsLangString(lang, _("Directory \"%s\" not available: " "%s")), filename, strerror(errno)); else snprintf(message, sizeof(message), _cupsLangString(lang, _("File \"%s\" not available: %s")), filename, strerror(errno)); break; case _CUPS_FILE_CHECK_PERMISSIONS : if (filetype == _CUPS_FILE_CHECK_DIRECTORY) snprintf(message, sizeof(message), _cupsLangString(lang, _("Directory \"%s\" has insecure " "permissions " "(0%o/uid=%d/gid=%d).")), filename, fileinfo.st_mode, (int)fileinfo.st_uid, (int)fileinfo.st_gid); else snprintf(message, sizeof(message), _cupsLangString(lang, _("File \"%s\" has insecure " "permissions " "(0%o/uid=%d/gid=%d).")), filename, fileinfo.st_mode, (int)fileinfo.st_uid, (int)fileinfo.st_gid); break; case _CUPS_FILE_CHECK_WRONG_TYPE : if (filetype == _CUPS_FILE_CHECK_DIRECTORY) snprintf(message, sizeof(message), _cupsLangString(lang, _("Directory \"%s\" is a file.")), filename); else snprintf(message, sizeof(message), _cupsLangString(lang, _("File \"%s\" is a directory.")), filename); break; case _CUPS_FILE_CHECK_RELATIVE_PATH : if (filetype == _CUPS_FILE_CHECK_DIRECTORY) snprintf(message, sizeof(message), _cupsLangString(lang, _("Directory \"%s\" contains a " "relative path.")), filename); else snprintf(message, sizeof(message), _cupsLangString(lang, _("File \"%s\" contains a relative " "path.")), filename); break; } (*cb)(context, result, message); } return (result); } /* * '_cupsFileCheckFilter()' - Report file check results as CUPS filter messages. */ void _cupsFileCheckFilter( void *context, /* I - Context pointer (unused) */ _cups_fc_result_t result, /* I - Result code */ const char *message) /* I - Message text */ { const char *prefix; /* Messaging prefix */ (void)context; switch (result) { default : case _CUPS_FILE_CHECK_OK : prefix = "DEBUG2"; break; case _CUPS_FILE_CHECK_MISSING : case _CUPS_FILE_CHECK_WRONG_TYPE : prefix = "ERROR"; fputs("STATE: +cups-missing-filter-warning\n", stderr); break; case _CUPS_FILE_CHECK_PERMISSIONS : case _CUPS_FILE_CHECK_RELATIVE_PATH : prefix = "ERROR"; fputs("STATE: +cups-insecure-filter-warning\n", stderr); break; } fprintf(stderr, "%s: %s\n", prefix, message); } #endif /* !WIN32 */ /* * 'cupsFileClose()' - Close a CUPS file. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 0 on success, -1 on error */ cupsFileClose(cups_file_t *fp) /* I - CUPS file */ { int fd; /* File descriptor */ char mode; /* Open mode */ int status; /* Return status */ DEBUG_printf(("cupsFileClose(fp=%p)", (void *)fp)); /* * Range check... */ if (!fp) return (-1); /* * Flush pending write data... */ if (fp->mode == 'w') status = cupsFileFlush(fp); else status = 0; #ifdef HAVE_LIBZ if (fp->compressed && status >= 0) { if (fp->mode == 'r') { /* * Free decompression data... */ inflateEnd(&fp->stream); } else { /* * Flush any remaining compressed data... */ unsigned char trailer[8]; /* Trailer CRC and length */ int done; /* Done writing... */ fp->stream.avail_in = 0; for (done = 0;;) { if (fp->stream.next_out > fp->cbuf) { if (cups_write(fp, (char *)fp->cbuf, (size_t)(fp->stream.next_out - fp->cbuf)) < 0) status = -1; fp->stream.next_out = fp->cbuf; fp->stream.avail_out = sizeof(fp->cbuf); } if (done || status < 0) break; done = deflate(&fp->stream, Z_FINISH) == Z_STREAM_END && fp->stream.next_out == fp->cbuf; } /* * Write the CRC and length... */ trailer[0] = (unsigned char)fp->crc; trailer[1] = (unsigned char)(fp->crc >> 8); trailer[2] = (unsigned char)(fp->crc >> 16); trailer[3] = (unsigned char)(fp->crc >> 24); trailer[4] = (unsigned char)fp->pos; trailer[5] = (unsigned char)(fp->pos >> 8); trailer[6] = (unsigned char)(fp->pos >> 16); trailer[7] = (unsigned char)(fp->pos >> 24); if (cups_write(fp, (char *)trailer, 8) < 0) status = -1; /* * Free all memory used by the compression stream... */ deflateEnd(&(fp->stream)); } } #endif /* HAVE_LIBZ */ /* * If this is one of the cupsFileStdin/out/err files, return now and don't * actually free memory or close (these last the life of the process...) */ if (fp->is_stdio) return (status); /* * Save the file descriptor we used and free memory... */ fd = fp->fd; mode = fp->mode; if (fp->printf_buffer) free(fp->printf_buffer); free(fp); /* * Close the file, returning the close status... */ if (mode == 's') { if (httpAddrClose(NULL, fd) < 0) status = -1; } else if (close(fd) < 0) status = -1; return (status); } /* * 'cupsFileCompression()' - Return whether a file is compressed. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - @code CUPS_FILE_NONE@ or @code CUPS_FILE_GZIP@ */ cupsFileCompression(cups_file_t *fp) /* I - CUPS file */ { return (fp ? fp->compressed : CUPS_FILE_NONE); } /* * 'cupsFileEOF()' - Return the end-of-file status. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 1 on end of file, 0 otherwise */ cupsFileEOF(cups_file_t *fp) /* I - CUPS file */ { return (fp ? fp->eof : 1); } /* * 'cupsFileFind()' - Find a file using the specified path. * * This function allows the paths in the path string to be separated by * colons (UNIX standard) or semicolons (Windows standard) and stores the * result in the buffer supplied. If the file cannot be found in any of * the supplied paths, @code NULL@ is returned. A @code NULL@ path only * matches the current directory. * * @since CUPS 1.2/macOS 10.5@ */ const char * /* O - Full path to file or @code NULL@ if not found */ cupsFileFind(const char *filename, /* I - File to find */ const char *path, /* I - Colon/semicolon-separated path */ int executable, /* I - 1 = executable files, 0 = any file/dir */ char *buffer, /* I - Filename buffer */ int bufsize) /* I - Size of filename buffer */ { char *bufptr, /* Current position in buffer */ *bufend; /* End of buffer */ /* * Range check input... */ DEBUG_printf(("cupsFileFind(filename=\"%s\", path=\"%s\", executable=%d, buffer=%p, bufsize=%d)", filename, path, executable, (void *)buffer, bufsize)); if (!filename || !buffer || bufsize < 2) return (NULL); if (!path) { /* * No path, so check current directory... */ if (!access(filename, 0)) { strlcpy(buffer, filename, (size_t)bufsize); return (buffer); } else return (NULL); } /* * Now check each path and return the first match... */ bufend = buffer + bufsize - 1; bufptr = buffer; while (*path) { #ifdef WIN32 if (*path == ';' || (*path == ':' && ((bufptr - buffer) > 1 || !isalpha(buffer[0] & 255)))) #else if (*path == ';' || *path == ':') #endif /* WIN32 */ { if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend) *bufptr++ = '/'; strlcpy(bufptr, filename, (size_t)(bufend - bufptr)); #ifdef WIN32 if (!access(buffer, 0)) #else if (!access(buffer, executable ? X_OK : 0)) #endif /* WIN32 */ { DEBUG_printf(("1cupsFileFind: Returning \"%s\"", buffer)); return (buffer); } bufptr = buffer; } else if (bufptr < bufend) *bufptr++ = *path; path ++; } /* * Check the last path... */ if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend) *bufptr++ = '/'; strlcpy(bufptr, filename, (size_t)(bufend - bufptr)); if (!access(buffer, 0)) { DEBUG_printf(("1cupsFileFind: Returning \"%s\"", buffer)); return (buffer); } else { DEBUG_puts("1cupsFileFind: Returning NULL"); return (NULL); } } /* * 'cupsFileFlush()' - Flush pending output. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 0 on success, -1 on error */ cupsFileFlush(cups_file_t *fp) /* I - CUPS file */ { ssize_t bytes; /* Bytes to write */ DEBUG_printf(("cupsFileFlush(fp=%p)", (void *)fp)); /* * Range check input... */ if (!fp || fp->mode != 'w') { DEBUG_puts("1cupsFileFlush: Attempt to flush a read-only file..."); return (-1); } bytes = (ssize_t)(fp->ptr - fp->buf); DEBUG_printf(("2cupsFileFlush: Flushing " CUPS_LLFMT " bytes...", CUPS_LLCAST bytes)); if (bytes > 0) { #ifdef HAVE_LIBZ if (fp->compressed) bytes = cups_compress(fp, fp->buf, (size_t)bytes); else #endif /* HAVE_LIBZ */ bytes = cups_write(fp, fp->buf, (size_t)bytes); if (bytes < 0) return (-1); fp->ptr = fp->buf; } return (0); } /* * 'cupsFileGetChar()' - Get a single character from a file. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - Character or -1 on end of file */ cupsFileGetChar(cups_file_t *fp) /* I - CUPS file */ { /* * Range check input... */ DEBUG_printf(("4cupsFileGetChar(fp=%p)", (void *)fp)); if (!fp || (fp->mode != 'r' && fp->mode != 's')) { DEBUG_puts("5cupsFileGetChar: Bad arguments!"); return (-1); } /* * If the input buffer is empty, try to read more data... */ DEBUG_printf(("5cupsFileGetChar: fp->eof=%d, fp->ptr=%p, fp->end=%p", fp->eof, (void *)fp->ptr, (void *)fp->end)); if (fp->ptr >= fp->end) if (cups_fill(fp) <= 0) { DEBUG_puts("5cupsFileGetChar: Unable to fill buffer!"); return (-1); } /* * Return the next character in the buffer... */ DEBUG_printf(("5cupsFileGetChar: Returning %d...", *(fp->ptr) & 255)); fp->pos ++; DEBUG_printf(("6cupsFileGetChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); return (*(fp->ptr)++ & 255); } /* * 'cupsFileGetConf()' - Get a line from a configuration file. * * @since CUPS 1.2/macOS 10.5@ */ char * /* O - Line read or @code NULL@ on end of file or error */ cupsFileGetConf(cups_file_t *fp, /* I - CUPS file */ char *buf, /* O - String buffer */ size_t buflen, /* I - Size of string buffer */ char **value, /* O - Pointer to value */ int *linenum) /* IO - Current line number */ { char *ptr; /* Pointer into line */ /* * Range check input... */ DEBUG_printf(("2cupsFileGetConf(fp=%p, buf=%p, buflen=" CUPS_LLFMT ", value=%p, linenum=%p)", (void *)fp, (void *)buf, CUPS_LLCAST buflen, (void *)value, (void *)linenum)); if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2 || !value) { if (value) *value = NULL; return (NULL); } /* * Read the next non-comment line... */ *value = NULL; while (cupsFileGets(fp, buf, buflen)) { (*linenum) ++; /* * Strip any comments... */ if ((ptr = strchr(buf, '#')) != NULL) { if (ptr > buf && ptr[-1] == '\\') { // Unquote the #... _cups_strcpy(ptr - 1, ptr); } else { // Strip the comment and any trailing whitespace... while (ptr > buf) { if (!_cups_isspace(ptr[-1])) break; ptr --; } *ptr = '\0'; } } /* * Strip leading whitespace... */ for (ptr = buf; _cups_isspace(*ptr); ptr ++); if (ptr > buf) _cups_strcpy(buf, ptr); /* * See if there is anything left... */ if (buf[0]) { /* * Yes, grab any value and return... */ for (ptr = buf; *ptr; ptr ++) if (_cups_isspace(*ptr)) break; if (*ptr) { /* * Have a value, skip any other spaces... */ while (_cups_isspace(*ptr)) *ptr++ = '\0'; if (*ptr) *value = ptr; /* * Strip trailing whitespace and > for lines that begin with <... */ ptr += strlen(ptr) - 1; if (buf[0] == '<' && *ptr == '>') *ptr-- = '\0'; else if (buf[0] == '<' && *ptr != '>') { /* * Syntax error... */ *value = NULL; return (buf); } while (ptr > *value && _cups_isspace(*ptr)) *ptr-- = '\0'; } /* * Return the line... */ return (buf); } } return (NULL); } /* * 'cupsFileGetLine()' - Get a CR and/or LF-terminated line that may * contain binary data. * * This function differs from @link cupsFileGets@ in that the trailing CR * and LF are preserved, as is any binary data on the line. The buffer is * nul-terminated, however you should use the returned length to determine * the number of bytes on the line. * * @since CUPS 1.2/macOS 10.5@ */ size_t /* O - Number of bytes on line or 0 on end of file */ cupsFileGetLine(cups_file_t *fp, /* I - File to read from */ char *buf, /* I - Buffer */ size_t buflen) /* I - Size of buffer */ { int ch; /* Character from file */ char *ptr, /* Current position in line buffer */ *end; /* End of line buffer */ /* * Range check input... */ DEBUG_printf(("2cupsFileGetLine(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST buflen)); if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 3) return (0); /* * Now loop until we have a valid line... */ for (ptr = buf, end = buf + buflen - 2; ptr < end ;) { if (fp->ptr >= fp->end) if (cups_fill(fp) <= 0) break; *ptr++ = ch = *(fp->ptr)++; fp->pos ++; if (ch == '\r') { /* * Check for CR LF... */ if (fp->ptr >= fp->end) if (cups_fill(fp) <= 0) break; if (*(fp->ptr) == '\n') { *ptr++ = *(fp->ptr)++; fp->pos ++; } break; } else if (ch == '\n') { /* * Line feed ends a line... */ break; } } *ptr = '\0'; DEBUG_printf(("4cupsFileGetLine: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); return ((size_t)(ptr - buf)); } /* * 'cupsFileGets()' - Get a CR and/or LF-terminated line. * * @since CUPS 1.2/macOS 10.5@ */ char * /* O - Line read or @code NULL@ on end of file or error */ cupsFileGets(cups_file_t *fp, /* I - CUPS file */ char *buf, /* O - String buffer */ size_t buflen) /* I - Size of string buffer */ { int ch; /* Character from file */ char *ptr, /* Current position in line buffer */ *end; /* End of line buffer */ /* * Range check input... */ DEBUG_printf(("2cupsFileGets(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST buflen)); if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2) return (NULL); /* * Now loop until we have a valid line... */ for (ptr = buf, end = buf + buflen - 1; ptr < end ;) { if (fp->ptr >= fp->end) if (cups_fill(fp) <= 0) { if (ptr == buf) return (NULL); else break; } ch = *(fp->ptr)++; fp->pos ++; if (ch == '\r') { /* * Check for CR LF... */ if (fp->ptr >= fp->end) if (cups_fill(fp) <= 0) break; if (*(fp->ptr) == '\n') { fp->ptr ++; fp->pos ++; } break; } else if (ch == '\n') { /* * Line feed ends a line... */ break; } else *ptr++ = (char)ch; } *ptr = '\0'; DEBUG_printf(("4cupsFileGets: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); return (buf); } /* * 'cupsFileLock()' - Temporarily lock access to a file. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 0 on success, -1 on error */ cupsFileLock(cups_file_t *fp, /* I - CUPS file */ int block) /* I - 1 to wait for the lock, 0 to fail right away */ { /* * Range check... */ if (!fp || fp->mode == 's') return (-1); /* * Try the lock... */ #ifdef WIN32 return (_locking(fp->fd, block ? _LK_LOCK : _LK_NBLCK, 0)); #else return (lockf(fp->fd, block ? F_LOCK : F_TLOCK, 0)); #endif /* WIN32 */ } /* * 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - File descriptor */ cupsFileNumber(cups_file_t *fp) /* I - CUPS file */ { if (fp) return (fp->fd); else return (-1); } /* * 'cupsFileOpen()' - Open a CUPS file. * * The "mode" parameter can be "r" to read, "w" to write, overwriting any * existing file, "a" to append to an existing file or create a new file, * or "s" to open a socket connection. * * When opening for writing ("w"), an optional number from 1 to 9 can be * supplied which enables Flate compression of the file. Compression is * not supported for the "a" (append) mode. * * When opening a socket connection, the filename is a string of the form * "address:port" or "hostname:port". The socket will make an IPv4 or IPv6 * connection as needed, generally preferring IPv6 connections when there is * a choice. * * @since CUPS 1.2/macOS 10.5@ */ cups_file_t * /* O - CUPS file or @code NULL@ if the file or socket cannot be opened */ cupsFileOpen(const char *filename, /* I - Name of file */ const char *mode) /* I - Open mode */ { cups_file_t *fp; /* New CUPS file */ int fd; /* File descriptor */ char hostname[1024], /* Hostname */ *portname; /* Port "name" (number or service) */ http_addrlist_t *addrlist; /* Host address list */ DEBUG_printf(("cupsFileOpen(filename=\"%s\", mode=\"%s\")", filename, mode)); /* * Range check input... */ if (!filename || !mode || (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') || (*mode == 'a' && isdigit(mode[1] & 255))) return (NULL); /* * Open the file... */ switch (*mode) { case 'a' : /* Append file */ fd = cups_open(filename, O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE | O_BINARY); break; case 'r' : /* Read file */ fd = open(filename, O_RDONLY | O_LARGEFILE | O_BINARY, 0); break; case 'w' : /* Write file */ fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY); if (fd < 0 && errno == ENOENT) { fd = cups_open(filename, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE | O_BINARY); if (fd < 0 && errno == EEXIST) fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY); } if (fd >= 0) #ifdef WIN32 _chsize(fd, 0); #else ftruncate(fd, 0); #endif /* WIN32 */ break; case 's' : /* Read/write socket */ strlcpy(hostname, filename, sizeof(hostname)); if ((portname = strrchr(hostname, ':')) != NULL) *portname++ = '\0'; else return (NULL); /* * Lookup the hostname and service... */ if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) return (NULL); /* * Connect to the server... */ if (!httpAddrConnect(addrlist, &fd)) { httpAddrFreeList(addrlist); return (NULL); } httpAddrFreeList(addrlist); break; default : /* Remove bogus compiler warning... */ return (NULL); } if (fd < 0) return (NULL); /* * Create the CUPS file structure... */ if ((fp = cupsFileOpenFd(fd, mode)) == NULL) { if (*mode == 's') httpAddrClose(NULL, fd); else close(fd); } /* * Return it... */ return (fp); } /* * 'cupsFileOpenFd()' - Open a CUPS file using a file descriptor. * * The "mode" parameter can be "r" to read, "w" to write, "a" to append, * or "s" to treat the file descriptor as a bidirectional socket connection. * * When opening for writing ("w"), an optional number from 1 to 9 can be * supplied which enables Flate compression of the file. Compression is * not supported for the "a" (append) mode. * * @since CUPS 1.2/macOS 10.5@ */ cups_file_t * /* O - CUPS file or @code NULL@ if the file could not be opened */ cupsFileOpenFd(int fd, /* I - File descriptor */ const char *mode) /* I - Open mode */ { cups_file_t *fp; /* New CUPS file */ DEBUG_printf(("cupsFileOpenFd(fd=%d, mode=\"%s\")", fd, mode)); /* * Range check input... */ if (fd < 0 || !mode || (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') || (*mode == 'a' && isdigit(mode[1] & 255))) return (NULL); /* * Allocate memory... */ if ((fp = calloc(1, sizeof(cups_file_t))) == NULL) return (NULL); /* * Open the file... */ fp->fd = fd; switch (*mode) { case 'a' : fp->pos = lseek(fd, 0, SEEK_END); case 'w' : fp->mode = 'w'; fp->ptr = fp->buf; fp->end = fp->buf + sizeof(fp->buf); #ifdef HAVE_LIBZ if (mode[1] >= '1' && mode[1] <= '9') { /* * Open a compressed stream, so write the standard gzip file * header... */ unsigned char header[10]; /* gzip file header */ time_t curtime; /* Current time */ curtime = time(NULL); header[0] = 0x1f; header[1] = 0x8b; header[2] = Z_DEFLATED; header[3] = 0; header[4] = (unsigned char)curtime; header[5] = (unsigned char)(curtime >> 8); header[6] = (unsigned char)(curtime >> 16); header[7] = (unsigned char)(curtime >> 24); header[8] = 0; header[9] = 0x03; cups_write(fp, (char *)header, 10); /* * Initialize the compressor... */ deflateInit2(&(fp->stream), mode[1] - '0', Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); fp->stream.next_out = fp->cbuf; fp->stream.avail_out = sizeof(fp->cbuf); fp->compressed = 1; fp->crc = crc32(0L, Z_NULL, 0); } #endif /* HAVE_LIBZ */ break; case 'r' : fp->mode = 'r'; break; case 's' : fp->mode = 's'; break; default : /* Remove bogus compiler warning... */ return (NULL); } /* * Don't pass this file to child processes... */ #ifndef WIN32 fcntl(fp->fd, F_SETFD, fcntl(fp->fd, F_GETFD) | FD_CLOEXEC); #endif /* !WIN32 */ return (fp); } /* * 'cupsFilePeekChar()' - Peek at the next character from a file. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - Character or -1 on end of file */ cupsFilePeekChar(cups_file_t *fp) /* I - CUPS file */ { /* * Range check input... */ if (!fp || (fp->mode != 'r' && fp->mode != 's')) return (-1); /* * If the input buffer is empty, try to read more data... */ if (fp->ptr >= fp->end) if (cups_fill(fp) <= 0) return (-1); /* * Return the next character in the buffer... */ return (*(fp->ptr) & 255); } /* * 'cupsFilePrintf()' - Write a formatted string. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - Number of bytes written or -1 on error */ cupsFilePrintf(cups_file_t *fp, /* I - CUPS file */ const char *format, /* I - Printf-style format string */ ...) /* I - Additional args as necessary */ { va_list ap; /* Argument list */ ssize_t bytes; /* Formatted size */ DEBUG_printf(("2cupsFilePrintf(fp=%p, format=\"%s\", ...)", (void *)fp, format)); if (!fp || !format || (fp->mode != 'w' && fp->mode != 's')) return (-1); if (!fp->printf_buffer) { /* * Start with an 1k printf buffer... */ if ((fp->printf_buffer = malloc(1024)) == NULL) return (-1); fp->printf_size = 1024; } va_start(ap, format); bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap); va_end(ap); if (bytes >= (ssize_t)fp->printf_size) { /* * Expand the printf buffer... */ char *temp; /* Temporary buffer pointer */ if (bytes > 65535) return (-1); if ((temp = realloc(fp->printf_buffer, (size_t)(bytes + 1))) == NULL) return (-1); fp->printf_buffer = temp; fp->printf_size = (size_t)(bytes + 1); va_start(ap, format); bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap); va_end(ap); } if (fp->mode == 's') { if (cups_write(fp, fp->printf_buffer, (size_t)bytes) < 0) return (-1); fp->pos += bytes; DEBUG_printf(("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); return ((int)bytes); } if ((fp->ptr + bytes) > fp->end) if (cupsFileFlush(fp)) return (-1); fp->pos += bytes; DEBUG_printf(("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); if ((size_t)bytes > sizeof(fp->buf)) { #ifdef HAVE_LIBZ if (fp->compressed) return ((int)cups_compress(fp, fp->printf_buffer, (size_t)bytes)); else #endif /* HAVE_LIBZ */ return ((int)cups_write(fp, fp->printf_buffer, (size_t)bytes)); } else { memcpy(fp->ptr, fp->printf_buffer, (size_t)bytes); fp->ptr += bytes; if (fp->is_stdio && cupsFileFlush(fp)) return (-1); else return ((int)bytes); } } /* * 'cupsFilePutChar()' - Write a character. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 0 on success, -1 on error */ cupsFilePutChar(cups_file_t *fp, /* I - CUPS file */ int c) /* I - Character to write */ { /* * Range check input... */ if (!fp || (fp->mode != 'w' && fp->mode != 's')) return (-1); if (fp->mode == 's') { /* * Send character immediately over socket... */ char ch; /* Output character */ ch = (char)c; if (send(fp->fd, &ch, 1, 0) < 1) return (-1); } else { /* * Buffer it up... */ if (fp->ptr >= fp->end) if (cupsFileFlush(fp)) return (-1); *(fp->ptr) ++ = (char)c; } fp->pos ++; DEBUG_printf(("4cupsFilePutChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); return (0); } /* * 'cupsFilePutConf()' - Write a configuration line. * * This function handles any comment escaping of the value. * * @since CUPS 1.4/macOS 10.6@ */ ssize_t /* O - Number of bytes written or -1 on error */ cupsFilePutConf(cups_file_t *fp, /* I - CUPS file */ const char *directive, /* I - Directive */ const char *value) /* I - Value */ { ssize_t bytes, /* Number of bytes written */ temp; /* Temporary byte count */ const char *ptr; /* Pointer into value */ if (!fp || !directive || !*directive) return (-1); if ((bytes = cupsFilePuts(fp, directive)) < 0) return (-1); if (cupsFilePutChar(fp, ' ') < 0) return (-1); bytes ++; if (value && *value) { if ((ptr = strchr(value, '#')) != NULL) { /* * Need to quote the first # in the info string... */ if ((temp = cupsFileWrite(fp, value, (size_t)(ptr - value))) < 0) return (-1); bytes += temp; if (cupsFilePutChar(fp, '\\') < 0) return (-1); bytes ++; if ((temp = cupsFilePuts(fp, ptr)) < 0) return (-1); bytes += temp; } else if ((temp = cupsFilePuts(fp, value)) < 0) return (-1); else bytes += temp; } if (cupsFilePutChar(fp, '\n') < 0) return (-1); else return (bytes + 1); } /* * 'cupsFilePuts()' - Write a string. * * Like the @code fputs@ function, no newline is appended to the string. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - Number of bytes written or -1 on error */ cupsFilePuts(cups_file_t *fp, /* I - CUPS file */ const char *s) /* I - String to write */ { ssize_t bytes; /* Bytes to write */ /* * Range check input... */ if (!fp || !s || (fp->mode != 'w' && fp->mode != 's')) return (-1); /* * Write the string... */ bytes = (ssize_t)strlen(s); if (fp->mode == 's') { if (cups_write(fp, s, (size_t)bytes) < 0) return (-1); fp->pos += bytes; DEBUG_printf(("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); return ((int)bytes); } if ((fp->ptr + bytes) > fp->end) if (cupsFileFlush(fp)) return (-1); fp->pos += bytes; DEBUG_printf(("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); if ((size_t)bytes > sizeof(fp->buf)) { #ifdef HAVE_LIBZ if (fp->compressed) return ((int)cups_compress(fp, s, (size_t)bytes)); else #endif /* HAVE_LIBZ */ return ((int)cups_write(fp, s, (size_t)bytes)); } else { memcpy(fp->ptr, s, (size_t)bytes); fp->ptr += bytes; if (fp->is_stdio && cupsFileFlush(fp)) return (-1); else return ((int)bytes); } } /* * 'cupsFileRead()' - Read from a file. * * @since CUPS 1.2/macOS 10.5@ */ ssize_t /* O - Number of bytes read or -1 on error */ cupsFileRead(cups_file_t *fp, /* I - CUPS file */ char *buf, /* O - Buffer */ size_t bytes) /* I - Number of bytes to read */ { size_t total; /* Total bytes read */ ssize_t count; /* Bytes read */ DEBUG_printf(("2cupsFileRead(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes)); /* * Range check input... */ if (!fp || !buf || (fp->mode != 'r' && fp->mode != 's')) return (-1); if (bytes == 0) return (0); /* * Loop until all bytes are read... */ total = 0; while (bytes > 0) { if (fp->ptr >= fp->end) if (cups_fill(fp) <= 0) { DEBUG_printf(("4cupsFileRead: cups_fill() returned -1, total=" CUPS_LLFMT, CUPS_LLCAST total)); if (total > 0) return ((ssize_t)total); else return (-1); } count = (ssize_t)(fp->end - fp->ptr); if (count > (ssize_t)bytes) count = (ssize_t)bytes; memcpy(buf, fp->ptr,(size_t) count); fp->ptr += count; fp->pos += count; DEBUG_printf(("4cupsFileRead: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); /* * Update the counts for the last read... */ bytes -= (size_t)count; total += (size_t)count; buf += count; } /* * Return the total number of bytes read... */ DEBUG_printf(("3cupsFileRead: total=" CUPS_LLFMT, CUPS_LLCAST total)); return ((ssize_t)total); } /* * 'cupsFileRewind()' - Set the current file position to the beginning of the * file. * * @since CUPS 1.2/macOS 10.5@ */ off_t /* O - New file position or -1 on error */ cupsFileRewind(cups_file_t *fp) /* I - CUPS file */ { /* * Range check input... */ DEBUG_printf(("cupsFileRewind(fp=%p)", (void *)fp)); DEBUG_printf(("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); if (!fp || fp->mode != 'r') return (-1); /* * Handle special cases... */ if (fp->bufpos == 0) { /* * No seeking necessary... */ fp->pos = 0; if (fp->ptr) { fp->ptr = fp->buf; fp->eof = 0; } DEBUG_printf(("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); return (0); } /* * Otherwise, seek in the file and cleanup any compression buffers... */ #ifdef HAVE_LIBZ if (fp->compressed) { inflateEnd(&fp->stream); fp->compressed = 0; } #endif /* HAVE_LIBZ */ if (lseek(fp->fd, 0, SEEK_SET)) { DEBUG_printf(("1cupsFileRewind: lseek failed: %s", strerror(errno))); return (-1); } fp->bufpos = 0; fp->pos = 0; fp->ptr = NULL; fp->end = NULL; fp->eof = 0; DEBUG_printf(("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); return (0); } /* * 'cupsFileSeek()' - Seek in a file. * * @since CUPS 1.2/macOS 10.5@ */ off_t /* O - New file position or -1 on error */ cupsFileSeek(cups_file_t *fp, /* I - CUPS file */ off_t pos) /* I - Position in file */ { ssize_t bytes; /* Number bytes in buffer */ DEBUG_printf(("cupsFileSeek(fp=%p, pos=" CUPS_LLFMT ")", (void *)fp, CUPS_LLCAST pos)); DEBUG_printf(("2cupsFileSeek: fp->pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); DEBUG_printf(("2cupsFileSeek: fp->ptr=%p, fp->end=%p", (void *)fp->ptr, (void *)fp->end)); /* * Range check input... */ if (!fp || pos < 0 || fp->mode != 'r') return (-1); /* * Handle special cases... */ if (pos == 0) return (cupsFileRewind(fp)); if (fp->ptr) { bytes = (ssize_t)(fp->end - fp->buf); DEBUG_printf(("2cupsFileSeek: bytes=" CUPS_LLFMT, CUPS_LLCAST bytes)); if (pos >= fp->bufpos && pos < (fp->bufpos + bytes)) { /* * No seeking necessary... */ fp->pos = pos; fp->ptr = fp->buf + pos - fp->bufpos; fp->eof = 0; return (pos); } } #ifdef HAVE_LIBZ if (!fp->compressed && !fp->ptr) { /* * Preload a buffer to determine whether the file is compressed... */ if (cups_fill(fp) <= 0) return (-1); } #endif /* HAVE_LIBZ */ /* * Seek forwards or backwards... */ fp->eof = 0; if (pos < fp->bufpos) { /* * Need to seek backwards... */ DEBUG_puts("2cupsFileSeek: SEEK BACKWARDS"); #ifdef HAVE_LIBZ if (fp->compressed) { inflateEnd(&fp->stream); lseek(fp->fd, 0, SEEK_SET); fp->bufpos = 0; fp->pos = 0; fp->ptr = NULL; fp->end = NULL; while ((bytes = cups_fill(fp)) > 0) if (pos >= fp->bufpos && pos < (fp->bufpos + bytes)) break; if (bytes <= 0) return (-1); fp->ptr = fp->buf + pos - fp->bufpos; fp->pos = pos; } else #endif /* HAVE_LIBZ */ { fp->bufpos = lseek(fp->fd, pos, SEEK_SET); fp->pos = fp->bufpos; fp->ptr = NULL; fp->end = NULL; DEBUG_printf(("2cupsFileSeek: lseek() returned " CUPS_LLFMT, CUPS_LLCAST fp->pos)); } } else { /* * Need to seek forwards... */ DEBUG_puts("2cupsFileSeek: SEEK FORWARDS"); #ifdef HAVE_LIBZ if (fp->compressed) { while ((bytes = cups_fill(fp)) > 0) { if (pos >= fp->bufpos && pos < (fp->bufpos + bytes)) break; } if (bytes <= 0) return (-1); fp->ptr = fp->buf + pos - fp->bufpos; fp->pos = pos; } else #endif /* HAVE_LIBZ */ { fp->bufpos = lseek(fp->fd, pos, SEEK_SET); fp->pos = fp->bufpos; fp->ptr = NULL; fp->end = NULL; DEBUG_printf(("2cupsFileSeek: lseek() returned " CUPS_LLFMT, CUPS_LLCAST fp->pos)); } } DEBUG_printf(("2cupsFileSeek: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); return (fp->pos); } /* * 'cupsFileStderr()' - Return a CUPS file associated with stderr. * * @since CUPS 1.2/macOS 10.5@ */ cups_file_t * /* O - CUPS file */ cupsFileStderr(void) { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */ /* * Open file descriptor 2 as needed... */ if (!cg->stdio_files[2]) { /* * Flush any pending output on the stdio file... */ fflush(stderr); /* * Open file descriptor 2... */ if ((cg->stdio_files[2] = cupsFileOpenFd(2, "w")) != NULL) cg->stdio_files[2]->is_stdio = 1; } return (cg->stdio_files[2]); } /* * 'cupsFileStdin()' - Return a CUPS file associated with stdin. * * @since CUPS 1.2/macOS 10.5@ */ cups_file_t * /* O - CUPS file */ cupsFileStdin(void) { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */ /* * Open file descriptor 0 as needed... */ if (!cg->stdio_files[0]) { /* * Open file descriptor 0... */ if ((cg->stdio_files[0] = cupsFileOpenFd(0, "r")) != NULL) cg->stdio_files[0]->is_stdio = 1; } return (cg->stdio_files[0]); } /* * 'cupsFileStdout()' - Return a CUPS file associated with stdout. * * @since CUPS 1.2/macOS 10.5@ */ cups_file_t * /* O - CUPS file */ cupsFileStdout(void) { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */ /* * Open file descriptor 1 as needed... */ if (!cg->stdio_files[1]) { /* * Flush any pending output on the stdio file... */ fflush(stdout); /* * Open file descriptor 1... */ if ((cg->stdio_files[1] = cupsFileOpenFd(1, "w")) != NULL) cg->stdio_files[1]->is_stdio = 1; } return (cg->stdio_files[1]); } /* * 'cupsFileTell()' - Return the current file position. * * @since CUPS 1.2/macOS 10.5@ */ off_t /* O - File position */ cupsFileTell(cups_file_t *fp) /* I - CUPS file */ { DEBUG_printf(("2cupsFileTell(fp=%p)", (void *)fp)); DEBUG_printf(("3cupsFileTell: pos=" CUPS_LLFMT, CUPS_LLCAST (fp ? fp->pos : -1))); return (fp ? fp->pos : 0); } /* * 'cupsFileUnlock()' - Unlock access to a file. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 0 on success, -1 on error */ cupsFileUnlock(cups_file_t *fp) /* I - CUPS file */ { /* * Range check... */ DEBUG_printf(("cupsFileUnlock(fp=%p)", (void *)fp)); if (!fp || fp->mode == 's') return (-1); /* * Unlock... */ #ifdef WIN32 return (_locking(fp->fd, _LK_UNLCK, 0)); #else return (lockf(fp->fd, F_ULOCK, 0)); #endif /* WIN32 */ } /* * 'cupsFileWrite()' - Write to a file. * * @since CUPS 1.2/macOS 10.5@ */ ssize_t /* O - Number of bytes written or -1 on error */ cupsFileWrite(cups_file_t *fp, /* I - CUPS file */ const char *buf, /* I - Buffer */ size_t bytes) /* I - Number of bytes to write */ { /* * Range check input... */ DEBUG_printf(("2cupsFileWrite(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes)); if (!fp || !buf || (fp->mode != 'w' && fp->mode != 's')) return (-1); if (bytes == 0) return (0); /* * Write the buffer... */ if (fp->mode == 's') { if (cups_write(fp, buf, bytes) < 0) return (-1); fp->pos += (off_t)bytes; DEBUG_printf(("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); return ((ssize_t)bytes); } if ((fp->ptr + bytes) > fp->end) if (cupsFileFlush(fp)) return (-1); fp->pos += (off_t)bytes; DEBUG_printf(("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); if (bytes > sizeof(fp->buf)) { #ifdef HAVE_LIBZ if (fp->compressed) return (cups_compress(fp, buf, bytes)); else #endif /* HAVE_LIBZ */ return (cups_write(fp, buf, bytes)); } else { memcpy(fp->ptr, buf, bytes); fp->ptr += bytes; return ((ssize_t)bytes); } } #ifdef HAVE_LIBZ /* * 'cups_compress()' - Compress a buffer of data. */ static ssize_t /* O - Number of bytes written or -1 */ cups_compress(cups_file_t *fp, /* I - CUPS file */ const char *buf, /* I - Buffer */ size_t bytes) /* I - Number bytes */ { DEBUG_printf(("7cups_compress(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes)); /* * Update the CRC... */ fp->crc = crc32(fp->crc, (const Bytef *)buf, (uInt)bytes); /* * Deflate the bytes... */ fp->stream.next_in = (Bytef *)buf; fp->stream.avail_in = (uInt)bytes; while (fp->stream.avail_in > 0) { /* * Flush the current buffer... */ DEBUG_printf(("9cups_compress: avail_in=%d, avail_out=%d", fp->stream.avail_in, fp->stream.avail_out)); if (fp->stream.avail_out < (uInt)(sizeof(fp->cbuf) / 8)) { if (cups_write(fp, (char *)fp->cbuf, (size_t)(fp->stream.next_out - fp->cbuf)) < 0) return (-1); fp->stream.next_out = fp->cbuf; fp->stream.avail_out = sizeof(fp->cbuf); } deflate(&(fp->stream), Z_NO_FLUSH); } return ((ssize_t)bytes); } #endif /* HAVE_LIBZ */ /* * 'cups_fill()' - Fill the input buffer. */ static ssize_t /* O - Number of bytes or -1 */ cups_fill(cups_file_t *fp) /* I - CUPS file */ { ssize_t bytes; /* Number of bytes read */ #ifdef HAVE_LIBZ int status; /* Decompression status */ const unsigned char *ptr, /* Pointer into buffer */ *end; /* End of buffer */ #endif /* HAVE_LIBZ */ DEBUG_printf(("7cups_fill(fp=%p)", (void *)fp)); DEBUG_printf(("9cups_fill: fp->ptr=%p, fp->end=%p, fp->buf=%p, fp->bufpos=" CUPS_LLFMT ", fp->eof=%d", (void *)fp->ptr, (void *)fp->end, (void *)fp->buf, CUPS_LLCAST fp->bufpos, fp->eof)); if (fp->ptr && fp->end) fp->bufpos += fp->end - fp->buf; #ifdef HAVE_LIBZ DEBUG_printf(("9cups_fill: fp->compressed=%d", fp->compressed)); while (!fp->ptr || fp->compressed) { /* * Check to see if we have read any data yet; if not, see if we have a * compressed file... */ if (!fp->ptr) { /* * Reset the file position in case we are seeking... */ fp->compressed = 0; /* * Read the first bytes in the file to determine if we have a gzip'd * file... */ if ((bytes = cups_read(fp, (char *)fp->buf, sizeof(fp->buf))) < 0) { /* * Can't read from file! */ DEBUG_printf(("9cups_fill: cups_read() returned " CUPS_LLFMT, CUPS_LLCAST bytes)); fp->eof = 1; return (-1); } if (bytes < 10 || fp->buf[0] != 0x1f || (fp->buf[1] & 255) != 0x8b || fp->buf[2] != 8 || (fp->buf[3] & 0xe0) != 0) { /* * Not a gzip'd file! */ fp->ptr = fp->buf; fp->end = fp->buf + bytes; DEBUG_printf(("9cups_fill: Returning " CUPS_LLFMT, CUPS_LLCAST bytes)); return (bytes); } /* * Parse header junk: extra data, original name, and comment... */ ptr = (unsigned char *)fp->buf + 10; end = (unsigned char *)fp->buf + bytes; if (fp->buf[3] & 0x04) { /* * Skip extra data... */ if ((ptr + 2) > end) { /* * Can't read from file! */ DEBUG_puts("9cups_fill: Extra gzip header data missing, returning -1."); fp->eof = 1; errno = EIO; return (-1); } bytes = ((unsigned char)ptr[1] << 8) | (unsigned char)ptr[0]; ptr += 2 + bytes; if (ptr > end) { /* * Can't read from file! */ DEBUG_puts("9cups_fill: Extra gzip header data does not fit in initial buffer, returning -1."); fp->eof = 1; errno = EIO; return (-1); } } if (fp->buf[3] & 0x08) { /* * Skip original name data... */ while (ptr < end && *ptr) ptr ++; if (ptr < end) ptr ++; else { /* * Can't read from file! */ DEBUG_puts("9cups_fill: Original filename in gzip header data does not fit in initial buffer, returning -1."); fp->eof = 1; errno = EIO; return (-1); } } if (fp->buf[3] & 0x10) { /* * Skip comment data... */ while (ptr < end && *ptr) ptr ++; if (ptr < end) ptr ++; else { /* * Can't read from file! */ DEBUG_puts("9cups_fill: Comment in gzip header data does not fit in initial buffer, returning -1."); fp->eof = 1; errno = EIO; return (-1); } } if (fp->buf[3] & 0x02) { /* * Skip header CRC data... */ ptr += 2; if (ptr > end) { /* * Can't read from file! */ DEBUG_puts("9cups_fill: Header CRC in gzip header data does not fit in initial buffer, returning -1."); fp->eof = 1; errno = EIO; return (-1); } } /* * Copy the flate-compressed data to the compression buffer... */ if ((bytes = end - ptr) > 0) memcpy(fp->cbuf, ptr, (size_t)bytes); /* * Setup the decompressor data... */ fp->stream.zalloc = (alloc_func)0; fp->stream.zfree = (free_func)0; fp->stream.opaque = (voidpf)0; fp->stream.next_in = (Bytef *)fp->cbuf; fp->stream.next_out = NULL; fp->stream.avail_in = (uInt)bytes; fp->stream.avail_out = 0; fp->crc = crc32(0L, Z_NULL, 0); if ((status = inflateInit2(&(fp->stream), -15)) != Z_OK) { DEBUG_printf(("9cups_fill: inflateInit2 returned %d, returning -1.", status)); fp->eof = 1; errno = EIO; return (-1); } fp->compressed = 1; } if (fp->compressed) { /* * If we have reached end-of-file, return immediately... */ if (fp->eof) { DEBUG_puts("9cups_fill: EOF, returning 0."); return (0); } /* * Fill the decompression buffer as needed... */ if (fp->stream.avail_in == 0) { if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) <= 0) { DEBUG_printf(("9cups_fill: cups_read error, returning %d.", (int)bytes)); fp->eof = 1; return (bytes); } fp->stream.next_in = fp->cbuf; fp->stream.avail_in = (uInt)bytes; } /* * Decompress data from the buffer... */ fp->stream.next_out = (Bytef *)fp->buf; fp->stream.avail_out = sizeof(fp->buf); status = inflate(&(fp->stream), Z_NO_FLUSH); if (fp->stream.next_out > (Bytef *)fp->buf) fp->crc = crc32(fp->crc, (Bytef *)fp->buf, (uInt)(fp->stream.next_out - (Bytef *)fp->buf)); if (status == Z_STREAM_END) { /* * Read the CRC and length... */ unsigned char trailer[8]; /* Trailer bytes */ uLong tcrc; /* Trailer CRC */ ssize_t tbytes = 0; /* Number of bytes */ if (fp->stream.avail_in > 0) { if (fp->stream.avail_in > sizeof(trailer)) tbytes = (ssize_t)sizeof(trailer); else tbytes = (ssize_t)fp->stream.avail_in; memcpy(trailer, fp->stream.next_in, (size_t)tbytes); fp->stream.next_in += tbytes; fp->stream.avail_in -= (size_t)tbytes; } if (tbytes < (ssize_t)sizeof(trailer)) { if (read(fp->fd, trailer + tbytes, sizeof(trailer) - (size_t)tbytes) < ((ssize_t)sizeof(trailer) - tbytes)) { /* * Can't get it, so mark end-of-file... */ DEBUG_puts("9cups_fill: Unable to read gzip CRC trailer, returning -1."); fp->eof = 1; errno = EIO; return (-1); } } tcrc = ((((((uLong)trailer[3] << 8) | (uLong)trailer[2]) << 8) | (uLong)trailer[1]) << 8) | (uLong)trailer[0]; if (tcrc != fp->crc) { /* * Bad CRC, mark end-of-file... */ DEBUG_printf(("9cups_fill: tcrc=%08x != fp->crc=%08x, returning -1.", (unsigned int)tcrc, (unsigned int)fp->crc)); fp->eof = 1; errno = EIO; return (-1); } /* * Otherwise, reset the compressed flag so that we re-read the * file header... */ inflateEnd(&fp->stream); fp->compressed = 0; } else if (status < Z_OK) { DEBUG_printf(("9cups_fill: inflate returned %d, returning -1.", status)); fp->eof = 1; errno = EIO; return (-1); } bytes = (ssize_t)sizeof(fp->buf) - (ssize_t)fp->stream.avail_out; /* * Return the decompressed data... */ fp->ptr = fp->buf; fp->end = fp->buf + bytes; if (bytes) { DEBUG_printf(("9cups_fill: Returning %d.", (int)bytes)); return (bytes); } } } #endif /* HAVE_LIBZ */ /* * Read a buffer's full of data... */ if ((bytes = cups_read(fp, fp->buf, sizeof(fp->buf))) <= 0) { /* * Can't read from file! */ fp->eof = 1; fp->ptr = fp->buf; fp->end = fp->buf; } else { /* * Return the bytes we read... */ fp->eof = 0; fp->ptr = fp->buf; fp->end = fp->buf + bytes; } DEBUG_printf(("9cups_fill: Not gzip, returning %d.", (int)bytes)); return (bytes); } /* * 'cups_open()' - Safely open a file for writing. * * We don't allow appending to directories or files that are hard-linked or * symlinked. */ static int /* O - File descriptor or -1 otherwise */ cups_open(const char *filename, /* I - Filename */ int mode) /* I - Open mode */ { int fd; /* File descriptor */ struct stat fileinfo; /* File information */ #ifndef WIN32 struct stat linkinfo; /* Link information */ #endif /* !WIN32 */ /* * Open the file... */ if ((fd = open(filename, mode, 0666)) < 0) return (-1); /* * Then verify that the file descriptor doesn't point to a directory or hard- * linked file. */ if (fstat(fd, &fileinfo)) { close(fd); return (-1); } if (fileinfo.st_nlink != 1) { close(fd); errno = EPERM; return (-1); } #ifdef WIN32 if (fileinfo.st_mode & _S_IFDIR) #else if (S_ISDIR(fileinfo.st_mode)) #endif /* WIN32 */ { close(fd); errno = EISDIR; return (-1); } #ifndef WIN32 /* * Then use lstat to determine whether the filename is a symlink... */ if (lstat(filename, &linkinfo)) { close(fd); return (-1); } if (S_ISLNK(linkinfo.st_mode) || fileinfo.st_dev != linkinfo.st_dev || fileinfo.st_ino != linkinfo.st_ino || #ifdef HAVE_ST_GEN fileinfo.st_gen != linkinfo.st_gen || #endif /* HAVE_ST_GEN */ fileinfo.st_nlink != linkinfo.st_nlink || fileinfo.st_mode != linkinfo.st_mode) { /* * Yes, don't allow! */ close(fd); errno = EPERM; return (-1); } #endif /* !WIN32 */ return (fd); } /* * 'cups_read()' - Read from a file descriptor. */ static ssize_t /* O - Number of bytes read or -1 */ cups_read(cups_file_t *fp, /* I - CUPS file */ char *buf, /* I - Buffer */ size_t bytes) /* I - Number bytes */ { ssize_t total; /* Total bytes read */ DEBUG_printf(("7cups_read(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes)); /* * Loop until we read at least 0 bytes... */ for (;;) { #ifdef WIN32 if (fp->mode == 's') total = (ssize_t)recv(fp->fd, buf, (unsigned)bytes, 0); else total = (ssize_t)read(fp->fd, buf, (unsigned)bytes); #else if (fp->mode == 's') total = recv(fp->fd, buf, bytes, 0); else total = read(fp->fd, buf, bytes); #endif /* WIN32 */ DEBUG_printf(("9cups_read: total=" CUPS_LLFMT, CUPS_LLCAST total)); if (total >= 0) break; /* * Reads can be interrupted by signals and unavailable resources... */ if (errno == EAGAIN || errno == EINTR) continue; else return (-1); } /* * Return the total number of bytes read... */ return (total); } /* * 'cups_write()' - Write to a file descriptor. */ static ssize_t /* O - Number of bytes written or -1 */ cups_write(cups_file_t *fp, /* I - CUPS file */ const char *buf, /* I - Buffer */ size_t bytes) /* I - Number bytes */ { size_t total; /* Total bytes written */ ssize_t count; /* Count this time */ DEBUG_printf(("7cups_write(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes)); /* * Loop until all bytes are written... */ total = 0; while (bytes > 0) { #ifdef WIN32 if (fp->mode == 's') count = (ssize_t)send(fp->fd, buf, (unsigned)bytes, 0); else count = (ssize_t)write(fp->fd, buf, (unsigned)bytes); #else if (fp->mode == 's') count = send(fp->fd, buf, bytes, 0); else count = write(fp->fd, buf, bytes); #endif /* WIN32 */ DEBUG_printf(("9cups_write: count=" CUPS_LLFMT, CUPS_LLCAST count)); if (count < 0) { /* * Writes can be interrupted by signals and unavailable resources... */ if (errno == EAGAIN || errno == EINTR) continue; else return (-1); } /* * Update the counts for the last write call... */ bytes -= (size_t)count; total += (size_t)count; buf += count; } /* * Return the total number of bytes written... */ return ((ssize_t)total); } ippsample/cups/ipp-support.c0000644000175000017500000021361013240604116015162 0ustar tilltill/* * Internet Printing Protocol support functions for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" /* * Local globals... */ static const char * const ipp_states[] = { "IPP_STATE_ERROR", "IPP_STATE_IDLE", "IPP_STATE_HEADER", "IPP_STATE_ATTRIBUTE", "IPP_STATE_DATA" }; static const char * const ipp_status_oks[] = /* "OK" status codes */ { /* (name) = abandoned standard value */ "successful-ok", "successful-ok-ignored-or-substituted-attributes", "successful-ok-conflicting-attributes", "successful-ok-ignored-subscriptions", "(successful-ok-ignored-notifications)", "successful-ok-too-many-events", "(successful-ok-but-cancel-subscription)", "successful-ok-events-complete" }, * const ipp_status_400s[] = /* Client errors */ { /* (name) = abandoned standard value */ "client-error-bad-request", "client-error-forbidden", "client-error-not-authenticated", "client-error-not-authorized", "client-error-not-possible", "client-error-timeout", "client-error-not-found", "client-error-gone", "client-error-request-entity-too-large", "client-error-request-value-too-long", "client-error-document-format-not-supported", "client-error-attributes-or-values-not-supported", "client-error-uri-scheme-not-supported", "client-error-charset-not-supported", "client-error-conflicting-attributes", "client-error-compression-not-supported", "client-error-compression-error", "client-error-document-format-error", "client-error-document-access-error", "client-error-attributes-not-settable", "client-error-ignored-all-subscriptions", "client-error-too-many-subscriptions", "(client-error-ignored-all-notifications)", "(client-error-client-print-support-file-not-found)", "client-error-document-password-error", "client-error-document-permission-error", "client-error-document-security-error", "client-error-document-unprintable-error", "client-error-account-info-needed", "client-error-account-closed", "client-error-account-limit-reached", "client-error-account-authorization-failed", "client-error-not-fetchable" }, * const ipp_status_480s[] = /* Vendor client errors */ { /* 0x0480 - 0x048F */ "0x0480", "0x0481", "0x0482", "0x0483", "0x0484", "0x0485", "0x0486", "0x0487", "0x0488", "0x0489", "0x048A", "0x048B", "0x048C", "0x048D", "0x048E", "0x048F", /* 0x0490 - 0x049F */ "0x0490", "0x0491", "0x0492", "0x0493", "0x0494", "0x0495", "0x0496", "0x0497", "0x0498", "0x0499", "0x049A", "0x049B", "cups-error-account-info-needed", "cups-error-account-closed", "cups-error-account-limit-reached", "cups-error-account-authorization-failed" }, * const ipp_status_500s[] = /* Server errors */ { "server-error-internal-error", "server-error-operation-not-supported", "server-error-service-unavailable", "server-error-version-not-supported", "server-error-device-error", "server-error-temporary-error", "server-error-not-accepting-jobs", "server-error-busy", "server-error-job-canceled", "server-error-multiple-document-jobs-not-supported", "server-error-printer-is-deactivated", "server-error-too-many-jobs", "server-error-too-many-documents" }, * const ipp_status_1000s[] = /* CUPS internal */ { "cups-authentication-canceled", "cups-pki-error", "cups-upgrade-required" }; static const char * const ipp_std_ops[] = { /* 0x0000 - 0x000f */ "0x0000", "0x0001", "Print-Job", "Print-URI", "Validate-Job", "Create-Job", "Send-Document", "Send-URI", "Cancel-Job", "Get-Job-Attributes", "Get-Jobs", "Get-Printer-Attributes", "Hold-Job", "Release-Job", "Restart-Job", "0x000f", /* 0x0010 - 0x001f */ "Pause-Printer", "Resume-Printer", "Purge-Jobs", "Set-Printer-Attributes", "Set-Job-Attributes", "Get-Printer-Supported-Values", "Create-Printer-Subscriptions", "Create-Job-Subscriptions", "Get-Subscription-Attributes", "Get-Subscriptions", "Renew-Subscription", "Cancel-Subscription", "Get-Notifications", "(Send-Notifications)", "(Get-Resource-Attributes)", "(Get-Resource-Data)", /* 0x0020 - 0x002f */ "(Get-Resources)", "(Get-Printer-Support-Files)", "Enable-Printer", "Disable-Printer", "Pause-Printer-After-Current-Job", "Hold-New-Jobs", "Release-Held-New-Jobs", "Deactivate-Printer", "Activate-Printer", "Restart-Printer", "Shutdown-Printer", "Startup-Printer", "Reprocess-Job", "Cancel-Current-Job", "Suspend-Current-Job", "Resume-Job", /* 0x0030 - 0x003f */ "Promote-Job", "Schedule-Job-After", "0x0032", "Cancel-Document", "Get-Document-Attributes", "Get-Documents", "Delete-Document", "Set-Document-Attributes", "Cancel-Jobs", "Cancel-My-Jobs", "Resubmit-Job", "Close-Job", "Identify-Printer", "Validate-Document", "Add-Document-Images", "Acknowledge-Document", /* 0x0040 - 0x004f */ "Acknowledge-Identify-Printer", "Acknowledge-Job", "Fetch-Document", "Fetch-Job", "Get-Output-Device-Attributes", "Update-Active-Jobs", "Deregister-Output-Device", "Update-Document-Status", "Update-Job-Status", "Update-Output-Device-Attributes", "Get-Next-Document-Data", "Allocate-Printer-Resources", "Create-Printer", "Deallocate-Printer-Resources", "Delete-Printer", "Get-Printers", /* 0x0050 - 0x005f */ "Shutdown-One-Printer", "Startup-One-Printer", "Cancel-Resource", "Create-Resource", "Install-Resource", "Send-Resource-Data", "Set-Resource-Attributes", "Create-Resource-Subscriptions", "Create-System-Subscriptions", "Disable-All-Printers", "Enable-All-Printers", "Get-System-Attributes", "Get-System-Supported-Values", "Pause-All-Printers", "Pause-All-Printers-After-Current-Job", "Register-Output-Device", /* 0x0060 - 0x0064 */ "Restart-System", "Resume-All-Printers", "Set-System-Attributes", "Shutdown-All-Printers", "Startup-All-Printers" }, * const ipp_cups_ops[] = { "CUPS-Get-Default", "CUPS-Get-Printers", "CUPS-Add-Modify-Printer", "CUPS-Delete-Printer", "CUPS-Get-Classes", "CUPS-Add-Modify-Class", "CUPS-Delete-Class", "CUPS-Accept-Jobs", "CUPS-Reject-Jobs", "CUPS-Set-Default", "CUPS-Get-Devices", "CUPS-Get-PPDs", "CUPS-Move-Job", "CUPS-Authenticate-Job", "CUPS-Get-PPD" }, * const ipp_cups_ops2[] = { "CUPS-Get-Document", "CUPS-Create-Local-Printer" }, * const ipp_tag_names[] = { /* Value/group tag names */ "zero", /* 0x00 */ "operation-attributes-tag", /* 0x01 */ "job-attributes-tag", /* 0x02 */ "end-of-attributes-tag", /* 0x03 */ "printer-attributes-tag", /* 0x04 */ "unsupported-attributes-tag", /* 0x05 */ "subscription-attributes-tag", /* 0x06 */ "event-notification-attributes-tag", /* 0x07 */ "(resource-attributes-tag)", /* 0x08 */ "document-attributes-tag", /* 0x09 */ "0x0a", /* 0x0a */ "0x0b", /* 0x0b */ "0x0c", /* 0x0c */ "0x0d", /* 0x0d */ "0x0e", /* 0x0e */ "0x0f", /* 0x0f */ "unsupported", /* 0x10 */ "default", /* 0x11 */ "unknown", /* 0x12 */ "no-value", /* 0x13 */ "0x14", /* 0x14 */ "not-settable", /* 0x15 */ "delete-attribute", /* 0x16 */ "admin-define", /* 0x17 */ "0x18", /* 0x18 */ "0x19", /* 0x19 */ "0x1a", /* 0x1a */ "0x1b", /* 0x1b */ "0x1c", /* 0x1c */ "0x1d", /* 0x1d */ "0x1e", /* 0x1e */ "0x1f", /* 0x1f */ "0x20", /* 0x20 */ "integer", /* 0x21 */ "boolean", /* 0x22 */ "enum", /* 0x23 */ "0x24", /* 0x24 */ "0x25", /* 0x25 */ "0x26", /* 0x26 */ "0x27", /* 0x27 */ "0x28", /* 0x28 */ "0x29", /* 0x29 */ "0x2a", /* 0x2a */ "0x2b", /* 0x2b */ "0x2c", /* 0x2c */ "0x2d", /* 0x2d */ "0x2e", /* 0x2e */ "0x2f", /* 0x2f */ "octetString", /* 0x30 */ "dateTime", /* 0x31 */ "resolution", /* 0x32 */ "rangeOfInteger", /* 0x33 */ "collection", /* 0x34 */ "textWithLanguage", /* 0x35 */ "nameWithLanguage", /* 0x36 */ "endCollection", /* 0x37 */ "0x38", /* 0x38 */ "0x39", /* 0x39 */ "0x3a", /* 0x3a */ "0x3b", /* 0x3b */ "0x3c", /* 0x3c */ "0x3d", /* 0x3d */ "0x3e", /* 0x3e */ "0x3f", /* 0x3f */ "0x40", /* 0x40 */ "textWithoutLanguage",/* 0x41 */ "nameWithoutLanguage",/* 0x42 */ "0x43", /* 0x43 */ "keyword", /* 0x44 */ "uri", /* 0x45 */ "uriScheme", /* 0x46 */ "charset", /* 0x47 */ "naturalLanguage", /* 0x48 */ "mimeMediaType", /* 0x49 */ "memberAttrName" /* 0x4a */ }; static const char * const ipp_document_states[] = { /* document-state-enums */ "pending", "4", "processing", "processing-stopped", /* IPPSIX */ "canceled", "aborted", "completed" }, * const ipp_finishings[] = { /* finishings enums */ "none", "staple", "punch", "cover", "bind", "saddle-stitch", "edge-stitch", "fold", "trim", "bale", "booklet-maker", "jog-offset", "coat", /* Finishings 2.0 */ "laminate", /* Finishings 2.0 */ "17", "18", "19", "staple-top-left", "staple-bottom-left", "staple-top-right", "staple-bottom-right", "edge-stitch-left", "edge-stitch-top", "edge-stitch-right", "edge-stitch-bottom", "staple-dual-left", "staple-dual-top", "staple-dual-right", "staple-dual-bottom", "staple-triple-left", /* Finishings 2.0 */ "staple-triple-top", /* Finishings 2.0 */ "staple-triple-right",/* Finishings 2.0 */ "staple-triple-bottom",/* Finishings 2.0 */ "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "bind-left", "bind-top", "bind-right", "bind-bottom", "54", "55", "56", "57", "58", "59", "trim-after-pages", "trim-after-documents", "trim-after-copies", "trim-after-job", "64", "65", "66", "67", "68", "69", "punch-top-left", /* Finishings 2.0 */ "punch-bottom-left", /* Finishings 2.0 */ "punch-top-right", /* Finishings 2.0 */ "punch-bottom-right", /* Finishings 2.0 */ "punch-dual-left", /* Finishings 2.0 */ "punch-dual-top", /* Finishings 2.0 */ "punch-dual-right", /* Finishings 2.0 */ "punch-dual-bottom", /* Finishings 2.0 */ "punch-triple-left", /* Finishings 2.0 */ "punch-triple-top", /* Finishings 2.0 */ "punch-triple-right", /* Finishings 2.0 */ "punch-triple-bottom",/* Finishings 2.0 */ "punch-quad-left", /* Finishings 2.0 */ "punch-quad-top", /* Finishings 2.0 */ "punch-quad-right", /* Finishings 2.0 */ "punch-quad-bottom", /* Finishings 2.0 */ "punch-multiple-left",/* Finishings 2.1/Canon */ "punch-multiple-top", /* Finishings 2.1/Canon */ "punch-multiple-right",/* Finishings 2.1/Canon */ "punch-multiple-bottom",/* Finishings 2.1/Canon */ "fold-accordian", /* Finishings 2.0 */ "fold-double-gate", /* Finishings 2.0 */ "fold-gate", /* Finishings 2.0 */ "fold-half", /* Finishings 2.0 */ "fold-half-z", /* Finishings 2.0 */ "fold-left-gate", /* Finishings 2.0 */ "fold-letter", /* Finishings 2.0 */ "fold-parallel", /* Finishings 2.0 */ "fold-poster", /* Finishings 2.0 */ "fold-right-gate", /* Finishings 2.0 */ "fold-z", /* Finishings 2.0 */ "fold-engineering-z" /* Finishings 2.1 */ }, * const ipp_finishings_vendor[] = { /* 0x40000000 to 0x4000000F */ "0x40000000", "0x40000001", "0x40000002", "0x40000003", "0x40000004", "0x40000005", "0x40000006", "0x40000007", "0x40000008", "0x40000009", "0x4000000A", "0x4000000B", "0x4000000C", "0x4000000D", "0x4000000E", "0x4000000F", /* 0x40000010 to 0x4000001F */ "0x40000010", "0x40000011", "0x40000012", "0x40000013", "0x40000014", "0x40000015", "0x40000016", "0x40000017", "0x40000018", "0x40000019", "0x4000001A", "0x4000001B", "0x4000001C", "0x4000001D", "0x4000001E", "0x4000001F", /* 0x40000020 to 0x4000002F */ "0x40000020", "0x40000021", "0x40000022", "0x40000023", "0x40000024", "0x40000025", "0x40000026", "0x40000027", "0x40000028", "0x40000029", "0x4000002A", "0x4000002B", "0x4000002C", "0x4000002D", "0x4000002E", "0x4000002F", /* 0x40000030 to 0x4000003F */ "0x40000030", "0x40000031", "0x40000032", "0x40000033", "0x40000034", "0x40000035", "0x40000036", "0x40000037", "0x40000038", "0x40000039", "0x4000003A", "0x4000003B", "0x4000003C", "0x4000003D", "0x4000003E", "0x4000003F", /* 0x40000040 - 0x4000004F */ "0x40000040", "0x40000041", "0x40000042", "0x40000043", "0x40000044", "0x40000045", "cups-punch-top-left", "cups-punch-bottom-left", "cups-punch-top-right", "cups-punch-bottom-right", "cups-punch-dual-left", "cups-punch-dual-top", "cups-punch-dual-right", "cups-punch-dual-bottom", "cups-punch-triple-left", "cups-punch-triple-top", /* 0x40000050 - 0x4000005F */ "cups-punch-triple-right", "cups-punch-triple-bottom", "cups-punch-quad-left", "cups-punch-quad-top", "cups-punch-quad-right", "cups-punch-quad-bottom", "0x40000056", "0x40000057", "0x40000058", "0x40000059", "cups-fold-accordian", "cups-fold-double-gate", "cups-fold-gate", "cups-fold-half", "cups-fold-half-z", "cups-fold-left-gate", /* 0x40000060 - 0x40000064 */ "cups-fold-letter", "cups-fold-parallel", "cups-fold-poster", "cups-fold-right-gate", "cups-fold-z" }, * const ipp_job_collation_types[] = { /* job-collation-type enums */ "uncollated-sheets", "collated-documents", "uncollated-documents" }, * const ipp_job_states[] = { /* job-state enums */ "pending", "pending-held", "processing", "processing-stopped", "canceled", "aborted", "completed" }, * const ipp_orientation_requesteds[] = { /* orientation-requested enums */ "portrait", "landscape", "reverse-landscape", "reverse-portrait", "none" }, * const ipp_print_qualities[] = { /* print-quality enums */ "draft", "normal", "high" }, * const ipp_printer_states[] = { /* printer-state enums */ "idle", "processing", "stopped", }; /* * Local functions... */ static size_t ipp_col_string(ipp_t *col, char *buffer, size_t bufsize); /* * 'ippAttributeString()' - Convert the attribute's value to a string. * * Returns the number of bytes that would be written, not including the * trailing nul. The buffer pointer can be NULL to get the required length, * just like (v)snprintf. * * @since CUPS 1.6/macOS 10.8@ */ size_t /* O - Number of bytes less nul */ ippAttributeString( ipp_attribute_t *attr, /* I - Attribute */ char *buffer, /* I - String buffer or NULL */ size_t bufsize) /* I - Size of string buffer */ { int i; /* Looping var */ char *bufptr, /* Pointer into buffer */ *bufend, /* End of buffer */ temp[256]; /* Temporary string */ const char *ptr, /* Pointer into string */ *end; /* Pointer to end of string */ _ipp_value_t *val; /* Current value */ if (!attr || !attr->name) { if (buffer) *buffer = '\0'; return (0); } bufptr = buffer; if (buffer) bufend = buffer + bufsize - 1; else bufend = NULL; for (i = attr->num_values, val = attr->values; i > 0; i --, val ++) { if (val > attr->values) { if (buffer && bufptr < bufend) *bufptr++ = ','; else bufptr ++; } switch (attr->value_tag & ~IPP_TAG_CUPS_CONST) { case IPP_TAG_ENUM : ptr = ippEnumString(attr->name, val->integer); if (buffer && bufptr < bufend) strlcpy(bufptr, ptr, (size_t)(bufend - bufptr + 1)); bufptr += strlen(ptr); break; case IPP_TAG_INTEGER : if (buffer && bufptr < bufend) bufptr += snprintf(bufptr, (size_t)(bufend - bufptr + 1), "%d", val->integer); else bufptr += snprintf(temp, sizeof(temp), "%d", val->integer); break; case IPP_TAG_BOOLEAN : if (buffer && bufptr < bufend) strlcpy(bufptr, val->boolean ? "true" : "false", (size_t)(bufend - bufptr + 1)); bufptr += val->boolean ? 4 : 5; break; case IPP_TAG_RANGE : if (buffer && bufptr < bufend) bufptr += snprintf(bufptr, (size_t)(bufend - bufptr + 1), "%d-%d", val->range.lower, val->range.upper); else bufptr += snprintf(temp, sizeof(temp), "%d-%d", val->range.lower, val->range.upper); break; case IPP_TAG_RESOLUTION : if (val->resolution.xres == val->resolution.yres) { if (buffer && bufptr < bufend) bufptr += snprintf(bufptr, (size_t)(bufend - bufptr + 1), "%d%s", val->resolution.xres, val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); else bufptr += snprintf(temp, sizeof(temp), "%d%s", val->resolution.xres, val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); } else if (buffer && bufptr < bufend) bufptr += snprintf(bufptr, (size_t)(bufend - bufptr + 1), "%dx%d%s", val->resolution.xres, val->resolution.yres, val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); else bufptr += snprintf(temp, sizeof(temp), "%dx%d%s", val->resolution.xres, val->resolution.yres, val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); break; case IPP_TAG_DATE : { unsigned year; /* Year */ year = ((unsigned)val->date[0] << 8) + (unsigned)val->date[1]; if (val->date[9] == 0 && val->date[10] == 0) snprintf(temp, sizeof(temp), "%04u-%02u-%02uT%02u:%02u:%02uZ", year, val->date[2], val->date[3], val->date[4], val->date[5], val->date[6]); else snprintf(temp, sizeof(temp), "%04u-%02u-%02uT%02u:%02u:%02u%c%02u%02u", year, val->date[2], val->date[3], val->date[4], val->date[5], val->date[6], val->date[8], val->date[9], val->date[10]); if (buffer && bufptr < bufend) strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1)); bufptr += strlen(temp); } break; case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : case IPP_TAG_CHARSET : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_MIMETYPE : case IPP_TAG_LANGUAGE : case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : if (!val->string.text) break; for (ptr = val->string.text; *ptr; ptr ++) { if (*ptr == '\\' || *ptr == '\"' || *ptr == '[') { if (buffer && bufptr < bufend) *bufptr = '\\'; bufptr ++; } if (buffer && bufptr < bufend) *bufptr = *ptr; bufptr ++; } if (val->string.language) { /* * Add "[language]" to end of string... */ if (buffer && bufptr < bufend) *bufptr = '['; bufptr ++; if (buffer && bufptr < bufend) strlcpy(bufptr, val->string.language, (size_t)(bufend - bufptr)); bufptr += strlen(val->string.language); if (buffer && bufptr < bufend) *bufptr = ']'; bufptr ++; } break; case IPP_TAG_BEGIN_COLLECTION : if (buffer && bufptr < bufend) bufptr += ipp_col_string(val->collection, bufptr, (size_t)(bufend - bufptr + 1)); else bufptr += ipp_col_string(val->collection, NULL, 0); break; case IPP_TAG_STRING : for (ptr = val->unknown.data, end = ptr + val->unknown.length; ptr < end; ptr ++) { if (*ptr == '\\' || _cups_isspace(*ptr)) { if (buffer && bufptr < bufend) *bufptr = '\\'; bufptr ++; if (buffer && bufptr < bufend) *bufptr = *ptr; bufptr ++; } else if (!isprint(*ptr & 255)) { if (buffer && bufptr < bufend) bufptr += snprintf(bufptr, (size_t)(bufend - bufptr + 1), "\\%03o", *ptr & 255); else bufptr += snprintf(temp, sizeof(temp), "\\%03o", *ptr & 255); } else { if (buffer && bufptr < bufend) *bufptr = *ptr; bufptr ++; } } break; default : ptr = ippTagString(attr->value_tag); if (buffer && bufptr < bufend) strlcpy(bufptr, ptr, (size_t)(bufend - bufptr + 1)); bufptr += strlen(ptr); break; } } if (buffer && bufptr < bufend) *bufptr = '\0'; else if (bufend) *bufend = '\0'; return ((size_t)(bufptr - buffer)); } /* * 'ippCreateRequestedArray()' - Create a CUPS array of attribute names from the * given requested-attributes attribute. * * This function creates a (sorted) CUPS array of attribute names matching the * list of "requested-attribute" values supplied in an IPP request. All IANA- * registered values are supported in addition to the CUPS IPP extension * attributes. * * The @code request@ parameter specifies the request message that was read from * the client. * * @code NULL@ is returned if all attributes should be returned. Otherwise, the * result is a sorted array of attribute names, where @code cupsArrayFind(array, * "attribute-name")@ will return a non-NULL pointer. The array must be freed * using the @code cupsArrayDelete@ function. * * @since CUPS 1.7/macOS 10.9@ */ cups_array_t * /* O - CUPS array or @code NULL@ if all */ ippCreateRequestedArray(ipp_t *request) /* I - IPP request */ { int i, j, /* Looping vars */ count, /* Number of values */ added; /* Was name added? */ ipp_attribute_t *requested; /* requested-attributes attribute */ cups_array_t *ra; /* Requested attributes array */ const char *value; /* Current value */ /* The following lists come from the current IANA IPP registry of attributes */ static const char * const document_description[] = { /* document-description group */ "compression", "copies-actual", "cover-back-actual", "cover-front-actual", "current-page-order", "date-time-at-completed", "date-time-at-creation", "date-time-at-processing", "detailed-status-messages", "document-access-errors", "document-charset", "document-digital-signature", "document-format", "document-format-details", "document-format-detected", "document-format-version", "document-format-version-detected", "document-job-id", "document-job-uri", "document-message", "document-metadata", "document-name", "document-natural-language", "document-number", "document-printer-uri", "document-state", "document-state-message", "document-state-reasons", "document-uri", "document-uuid", "errors-count", "finishings-actual", "finishings-col-actual", "force-front-side-actual", "imposition-template-actual", "impressions", "impressions-completed", "impressions-completed-current-copy", "insert-sheet-actual", "k-octets", "k-octets-processed", "last-document", "materials-col-actual", /* IPP 3D */ "media-actual", "media-col-actual", "media-input-tray-check-actual", "media-sheets", "media-sheets-completed", "more-info", "multiple-object-handling-actual", /* IPP 3D */ "number-up-actual", "orientation-requested-actual", "output-bin-actual", "output-device-assigned", "overrides-actual", "page-delivery-actual", "page-order-received-actual", "page-ranges-actual", "pages", "pages-completed", "pages-completed-current-copy", "platform-temperature-actual", /* IPP 3D */ "presentation-direction-number-up-actual", "print-accuracy-actual", /* IPP 3D */ "print-base-actual", /* IPP 3D */ "print-color-mode-actual", "print-content-optimize-actual", "print-objects-actual", /* IPP 3D */ "print-quality-actual", "print-rendering-intent-actual", "print-scaling-actual", /* IPP Paid Printing */ "print-supports-actual", /* IPP 3D */ "printer-resolution-actual", "printer-up-time", "separator-sheets-actual", "sheet-completed-copy-number", "sides-actual", "time-at-completed", "time-at-creation", "time-at-processing", "x-image-position-actual", "x-image-shift-actual", "x-side1-image-shift-actual", "x-side2-image-shift-actual", "y-image-position-actual", "y-image-shift-actual", "y-side1-image-shift-actual", "y-side2-image-shift-actual" }; static const char * const document_template[] = { /* document-template group */ "copies", "copies-default", "copies-supported", "cover-back", "cover-back-default", "cover-back-supported", "cover-front", "cover-front-default", "cover-front-supported", "feed-orientation", "feed-orientation-default", "feed-orientation-supported", "finishings", "finishings-col", "finishings-col-database", "finishings-col-default", "finishings-col-ready", "finishings-col-supported", "finishings-default", "finishings-ready", "finishings-supported", "font-name-requested", "font-name-requested-default", "font-name-requested-supported", "font-size-requested", "font-size-requested-default", "font-size-requested-supported", "force-front-side", "force-front-side-default", "force-front-side-supported", "imposition-template", "imposition-template-default", "imposition-template-supported", "insert-after-page-number-supported", "insert-count-supported", "insert-sheet", "insert-sheet-default", "insert-sheet-supported", "material-amount-units-supported", /* IPP 3D */ "material-diameter-supported", /* IPP 3D */ "material-purpose-supported", /* IPP 3D */ "material-rate-supported", /* IPP 3D */ "material-rate-units-supported", /* IPP 3D */ "material-shell-thickness-supported",/* IPP 3D */ "material-temperature-supported", /* IPP 3D */ "material-type-supported", /* IPP 3D */ "materials-col", /* IPP 3D */ "materials-col-database", /* IPP 3D */ "materials-col-default", /* IPP 3D */ "materials-col-ready", /* IPP 3D */ "materials-col-supported", /* IPP 3D */ "max-materials-col-supported", /* IPP 3D */ "max-stitching-locations-supported", "media", "media-back-coating-supported", "media-bottom-margin-supported", "media-col", "media-col-default", "media-col-ready", "media-col-supported", "media-color-supported", "media-default", "media-front-coating-supported", "media-grain-supported", "media-hole-count-supported", "media-info-supported", "media-input-tray-check", "media-input-tray-check-default", "media-input-tray-check-supported", "media-key-supported", "media-left-margin-supported", "media-order-count-supported", "media-pre-printed-supported", "media-ready", "media-recycled-supported", "media-right-margin-supported", "media-size-supported", "media-source-supported", "media-supported", "media-thickness-supported", "media-top-margin-supported", "media-type-supported", "media-weight-metric-supported", "multiple-document-handling", "multiple-document-handling-default", "multiple-document-handling-supported", "multiple-object-handling", /* IPP 3D */ "multiple-object-handling-default", /* IPP 3D */ "multiple-object-handling-supported",/* IPP 3D */ "number-up", "number-up-default", "number-up-supported", "orientation-requested", "orientation-requested-default", "orientation-requested-supported", "output-mode", /* CUPS extension */ "output-mode-default", /* CUPS extension */ "output-mode-supported", /* CUPS extension */ "overrides", "overrides-supported", "page-delivery", "page-delivery-default", "page-delivery-supported", "page-order-received", "page-order-received-default", "page-order-received-supported", "page-ranges", "page-ranges-supported", "pages-per-subset", "pages-per-subset-supported", "pdl-init-file", "pdl-init-file-default", "pdl-init-file-entry-supported", "pdl-init-file-location-supported", "pdl-init-file-name-subdirectory-supported", "pdl-init-file-name-supported", "pdl-init-file-supported", "platform-temperature", /* IPP 3D */ "platform-temperature-default", /* IPP 3D */ "platform-temperature-supported", /* IPP 3D */ "presentation-direction-number-up", "presentation-direction-number-up-default", "presentation-direction-number-up-supported", "print-accuracy", /* IPP 3D */ "print-accuracy-default", /* IPP 3D */ "print-accuracy-supported", /* IPP 3D */ "print-base", /* IPP 3D */ "print-base-default", /* IPP 3D */ "print-base-supported", /* IPP 3D */ "print-color-mode", "print-color-mode-default", "print-color-mode-supported", "print-content-optimize", "print-content-optimize-default", "print-content-optimize-supported", "print-objects", /* IPP 3D */ "print-objects-default", /* IPP 3D */ "print-objects-supported", /* IPP 3D */ "print-quality", "print-quality-default", "print-quality-supported", "print-rendering-intent", "print-rendering-intent-default", "print-rendering-intent-supported", "print-scaling", /* IPP Paid Printing */ "print-scaling-default", /* IPP Paid Printing */ "print-scaling-supported", /* IPP Paid Printing */ "print-supports", /* IPP 3D */ "print-supports-default", /* IPP 3D */ "print-supports-supported", /* IPP 3D */ "printer-resolution", "printer-resolution-default", "printer-resolution-supported", "separator-sheets", "separator-sheets-default", "separator-sheets-supported", "sheet-collate", "sheet-collate-default", "sheet-collate-supported", "sides", "sides-default", "sides-supported", "stitching-locations-supported", "stitching-offset-supported", "x-image-position", "x-image-position-default", "x-image-position-supported", "x-image-shift", "x-image-shift-default", "x-image-shift-supported", "x-side1-image-shift", "x-side1-image-shift-default", "x-side1-image-shift-supported", "x-side2-image-shift", "x-side2-image-shift-default", "x-side2-image-shift-supported", "y-image-position", "y-image-position-default", "y-image-position-supported", "y-image-shift", "y-image-shift-default", "y-image-shift-supported", "y-side1-image-shift", "y-side1-image-shift-default", "y-side1-image-shift-supported", "y-side2-image-shift", "y-side2-image-shift-default", "y-side2-image-shift-supported" }; static const char * const job_description[] = { /* job-description group */ "compression-supplied", "copies-actual", "cover-back-actual", "cover-front-actual", "current-page-order", "date-time-at-completed", "date-time-at-creation", "date-time-at-processing", "destination-statuses", "document-charset-supplied", "document-digital-signature-supplied", "document-format-details-supplied", "document-format-supplied", "document-message-supplied", "document-metadata", "document-name-supplied", "document-natural-language-supplied", "document-overrides-actual", "errors-count", "finishings-actual", "finishings-col-actual", "force-front-side-actual", "imposition-template-actual", "impressions-completed-current-copy", "insert-sheet-actual", "job-account-id-actual", "job-accounting-sheets-actual", "job-accounting-user-id-actual", "job-attribute-fidelity", "job-charge-info", /* CUPS extension */ "job-collation-type", "job-collation-type-actual", "job-copies-actual", "job-cover-back-actual", "job-cover-front-actual", "job-detailed-status-message", "job-document-access-errors", "job-error-sheet-actual", "job-finishings-actual", "job-finishings-col-actual", "job-hold-until-actual", "job-id", "job-impressions", "job-impressions-completed", "job-k-octets", "job-k-octets-processed", "job-mandatory-attributes", "job-media-progress", /* CUPS extension */ "job-media-sheets", "job-media-sheets-completed", "job-message-from-operator", "job-more-info", "job-name", "job-originating-host-name", /* CUPS extension */ "job-originating-user-name", "job-originating-user-uri", "job-pages", "job-pages-completed", "job-pages-completed-current-copy", "job-printer-state-message", /* CUPS extension */ "job-printer-state-reasons", /* CUPS extension */ "job-printer-up-time", "job-printer-uri", "job-priority-actual", "job-save-printer-make-and-model", "job-sheet-message-actual", "job-sheets-actual", "job-sheets-col-actual", "job-state", "job-state-message", "job-state-reasons", "job-uri", "job-uuid", "materials-col-actual", /* IPP 3D */ "media-actual", "media-col-actual", "media-check-input-tray-actual", "multiple-document-handling-actual", "multiple-object-handling-actual", /* IPP 3D */ "number-of-documents", "number-of-intervening-jobs", "number-up-actual", "orientation-requested-actual", "original-requesting-user-name", "output-bin-actual", "output-device-assigned", "overrides-actual", "page-delivery-actual", "page-order-received-actual", "page-ranges-actual", "platform-temperature-actual", /* IPP 3D */ "presentation-direction-number-up-actual", "print-accuracy-actual", /* IPP 3D */ "print-base-actual", /* IPP 3D */ "print-color-mode-actual", "print-content-optimize-actual", "print-objects-actual", /* IPP 3D */ "print-quality-actual", "print-rendering-intent-actual", "print-scaling-actual", /* IPP Paid Printing */ "print-supports-actual", /* IPP 3D */ "printer-resolution-actual", "separator-sheets-actual", "sheet-collate-actual", "sheet-completed-copy-number", "sheet-completed-document-number", "sides-actual", "time-at-completed", "time-at-creation", "time-at-processing", "warnings-count", "x-image-position-actual", "x-image-shift-actual", "x-side1-image-shift-actual", "x-side2-image-shift-actual", "y-image-position-actual", "y-image-shift-actual", "y-side1-image-shift-actual", "y-side2-image-shift-actual" }; static const char * const job_template[] = { /* job-template group */ "accuracy-units-supported", /* IPP 3D */ "confirmation-sheet-print", /* IPP FaxOut */ "confirmation-sheet-print-default", "copies", "copies-default", "copies-supported", "cover-back", "cover-back-default", "cover-back-supported", "cover-front", "cover-front-default", "cover-front-supported", "cover-sheet-info", /* IPP FaxOut */ "cover-sheet-info-default", "cover-sheet-info-supported", "destination-uri-schemes-supported",/* IPP FaxOut */ "destination-uris", /* IPP FaxOut */ "destination-uris-supported", "feed-orientation", "feed-orientation-default", "feed-orientation-supported", "finishings", "finishings-col", "finishings-col-database", "finishings-col-default", "finishings-col-ready", "finishings-col-supported", "finishings-default", "finishings-ready", "finishings-supported", "font-name-requested", "font-name-requested-default", "font-name-requested-supported", "font-size-requested", "font-size-requested-default", "font-size-requested-supported", "force-front-side", "force-front-side-default", "force-front-side-supported", "imposition-template", "imposition-template-default", "imposition-template-supported", "insert-after-page-number-supported", "insert-count-supported", "insert-sheet", "insert-sheet-default", "insert-sheet-supported", "job-account-id", "job-account-id-default", "job-account-id-supported", "job-accounting-sheets" "job-accounting-sheets-default" "job-accounting-sheets-supported" "job-accounting-user-id", "job-accounting-user-id-default", "job-accounting-user-id-supported", "job-copies", "job-copies-default", "job-copies-supported", "job-cover-back", "job-cover-back-default", "job-cover-back-supported", "job-cover-front", "job-cover-front-default", "job-cover-front-supported", "job-delay-output-until", "job-delay-output-until-default", "job-delay-output-until-supported", "job-delay-output-until-time", "job-delay-output-until-time-default", "job-delay-output-until-time-supported", "job-error-action", "job-error-action-default", "job-error-action-supported", "job-error-sheet", "job-error-sheet-default", "job-error-sheet-supported", "job-finishings", "job-finishings-col", "job-finishings-col-default", "job-finishings-col-supported", "job-finishings-default", "job-finishings-supported", "job-hold-until", "job-hold-until-default", "job-hold-until-supported", "job-hold-until-time", "job-hold-until-time-default", "job-hold-until-time-supported", "job-message-to-operator", "job-message-to-operator-default", "job-message-to-operator-supported", "job-phone-number", "job-phone-number-default", "job-phone-number-supported", "job-priority", "job-priority-default", "job-priority-supported", "job-recipient-name", "job-recipient-name-default", "job-recipient-name-supported", "job-save-disposition", "job-save-disposition-default", "job-save-disposition-supported", "job-sheets", "job-sheets-col", "job-sheets-col-default", "job-sheets-col-supported", "job-sheets-default", "job-sheets-supported", "logo-uri-schemes-supported", "material-amount-units-supported", /* IPP 3D */ "material-diameter-supported", /* IPP 3D */ "material-purpose-supported", /* IPP 3D */ "material-rate-supported", /* IPP 3D */ "material-rate-units-supported", /* IPP 3D */ "material-shell-thickness-supported",/* IPP 3D */ "material-temperature-supported", /* IPP 3D */ "material-type-supported", /* IPP 3D */ "materials-col", /* IPP 3D */ "materials-col-database", /* IPP 3D */ "materials-col-default", /* IPP 3D */ "materials-col-ready", /* IPP 3D */ "materials-col-supported", /* IPP 3D */ "max-materials-col-supported", /* IPP 3D */ "max-save-info-supported", "max-stitching-locations-supported", "media", "media-back-coating-supported", "media-bottom-margin-supported", "media-col", "media-col-default", "media-col-ready", "media-col-supported", "media-color-supported", "media-default", "media-front-coating-supported", "media-grain-supported", "media-hole-count-supported", "media-info-supported", "media-input-tray-check", "media-input-tray-check-default", "media-input-tray-check-supported", "media-key-supported", "media-left-margin-supported", "media-order-count-supported", "media-pre-printed-supported", "media-ready", "media-recycled-supported", "media-right-margin-supported", "media-size-supported", "media-source-supported", "media-supported", "media-thickness-supported", "media-top-margin-supported", "media-type-supported", "media-weight-metric-supported", "multiple-document-handling", "multiple-document-handling-default", "multiple-document-handling-supported", "multiple-object-handling", /* IPP 3D */ "multiple-object-handling-default", /* IPP 3D */ "multiple-object-handling-supported",/* IPP 3D */ "number-of-retries", /* IPP FaxOut */ "number-of-retries-default", "number-of-retries-supported", "number-up", "number-up-default", "number-up-supported", "orientation-requested", "orientation-requested-default", "orientation-requested-supported", "output-bin", "output-bin-default", "output-bin-supported", "output-device", "output-device-default", "output-device-supported", "output-mode", /* CUPS extension */ "output-mode-default", /* CUPS extension */ "output-mode-supported", /* CUPS extension */ "overrides", "overrides-supported", "page-delivery", "page-delivery-default", "page-delivery-supported", "page-order-received", "page-order-received-default", "page-order-received-supported", "page-ranges", "page-ranges-supported", "pages-per-subset", "pages-per-subset-supported", "pdl-init-file", "pdl-init-file-default", "pdl-init-file-entry-supported", "pdl-init-file-location-supported", "pdl-init-file-name-subdirectory-supported", "pdl-init-file-name-supported", "pdl-init-file-supported", "platform-temperature", /* IPP 3D */ "platform-temperature-default", /* IPP 3D */ "platform-temperature-supported", /* IPP 3D */ "presentation-direction-number-up", "presentation-direction-number-up-default", "presentation-direction-number-up-supported", "print-accuracy", /* IPP 3D */ "print-accuracy-default", /* IPP 3D */ "print-accuracy-supported", /* IPP 3D */ "print-base", /* IPP 3D */ "print-base-default", /* IPP 3D */ "print-base-supported", /* IPP 3D */ "print-color-mode", "print-color-mode-default", "print-color-mode-supported", "print-content-optimize", "print-content-optimize-default", "print-content-optimize-supported", "print-objects", /* IPP 3D */ "print-objects-default", /* IPP 3D */ "print-objects-supported", /* IPP 3D */ "print-quality", "print-quality-default", "print-quality-supported", "print-rendering-intent", "print-rendering-intent-default", "print-rendering-intent-supported", "print-scaling", /* IPP Paid Printing */ "print-scaling-default", /* IPP Paid Printing */ "print-scaling-supported", /* IPP Paid Printing */ "print-supports", /* IPP 3D */ "print-supports-default", /* IPP 3D */ "print-supports-supported", /* IPP 3D */ "printer-resolution", "printer-resolution-default", "printer-resolution-supported", "proof-print", "proof-print-default", "proof-print-supported", "retry-interval", /* IPP FaxOut */ "retry-interval-default", "retry-interval-supported", "retry-timeout", /* IPP FaxOut */ "retry-timeout-default", "retry-timeout-supported", "save-disposition-supported", "save-document-format-default", "save-document-format-supported", "save-location-default", "save-location-supported", "save-name-subdirectory-supported", "save-name-supported", "separator-sheets", "separator-sheets-default", "separator-sheets-supported", "sheet-collate", "sheet-collate-default", "sheet-collate-supported", "sides", "sides-default", "sides-supported", "stitching-locations-supported", "stitching-offset-supported", "x-image-position", "x-image-position-default", "x-image-position-supported", "x-image-shift", "x-image-shift-default", "x-image-shift-supported", "x-side1-image-shift", "x-side1-image-shift-default", "x-side1-image-shift-supported", "x-side2-image-shift", "x-side2-image-shift-default", "x-side2-image-shift-supported", "y-image-position", "y-image-position-default", "y-image-position-supported", "y-image-shift", "y-image-shift-default", "y-image-shift-supported", "y-side1-image-shift", "y-side1-image-shift-default", "y-side1-image-shift-supported", "y-side2-image-shift", "y-side2-image-shift-default", "y-side2-image-shift-supported" }; static const char * const printer_description[] = { /* printer-description group */ "auth-info-required", /* CUPS extension */ "charset-configured", "charset-supported", "color-supported", "compression-supported", "device-service-count", "device-uri", /* CUPS extension */ "device-uuid", "document-charset-default", "document-charset-supported", "document-creation-attributes-supported", "document-digital-signature-default", "document-digital-signature-supported", "document-format-default", "document-format-details-default", "document-format-details-supported", "document-format-supported", "document-format-varying-attributes", "document-format-version-default", "document-format-version-supported", "document-natural-language-default", "document-natural-language-supported", "document-password-supported", "generated-natural-language-supported", "identify-actions-default", "identify-actions-supported", "input-source-supported", "ipp-features-supported", "ipp-versions-supported", "ippget-event-life", "job-authorization-uri-supported", /* CUPS extension */ "job-constraints-supported", "job-creation-attributes-supported", "job-finishings-col-ready", "job-finishings-ready", "job-ids-supported", "job-impressions-supported", "job-k-limit", /* CUPS extension */ "job-k-octets-supported", "job-media-sheets-supported", "job-page-limit", /* CUPS extension */ "job-password-encryption-supported", "job-password-supported", "job-presets-supported", /* IPP Presets */ "job-quota-period", /* CUPS extension */ "job-resolvers-supported", "job-settable-attributes-supported", "job-spooling-supported", "job-triggers-supported", /* IPP Presets */ "jpeg-k-octets-supported", /* CUPS extension */ "jpeg-x-dimension-supported", /* CUPS extension */ "jpeg-y-dimension-supported", /* CUPS extension */ "landscape-orientation-requested-preferred", /* CUPS extension */ "marker-change-time", /* CUPS extension */ "marker-colors", /* CUPS extension */ "marker-high-levels", /* CUPS extension */ "marker-levels", /* CUPS extension */ "marker-low-levels", /* CUPS extension */ "marker-message", /* CUPS extension */ "marker-names", /* CUPS extension */ "marker-types", /* CUPS extension */ "member-names", /* CUPS extension */ "member-uris", /* CUPS extension */ "multiple-destination-uris-supported",/* IPP FaxOut */ "multiple-document-jobs-supported", "multiple-operation-time-out", "multiple-operation-time-out-action", "natural-language-configured", "operations-supported", "pages-per-minute", "pages-per-minute-color", "pdf-k-octets-supported", /* CUPS extension */ "pdf-features-supported", /* IPP 3D */ "pdf-versions-supported", /* CUPS extension */ "pdl-override-supported", "port-monitor", /* CUPS extension */ "port-monitor-supported", /* CUPS extension */ "preferred-attributes-supported", "printer-alert", "printer-alert-description", "printer-charge-info", "printer-charge-info-uri", "printer-commands", /* CUPS extension */ "printer-current-time", "printer-detailed-status-messages", "printer-device-id", "printer-dns-sd-name", /* CUPS extension */ "printer-driver-installer", "printer-fax-log-uri", /* IPP FaxOut */ "printer-fax-modem-info", /* IPP FaxOut */ "printer-fax-modem-name", /* IPP FaxOut */ "printer-fax-modem-number", /* IPP FaxOut */ "printer-firmware-name", /* PWG 5110.1 */ "printer-firmware-patches", /* PWG 5110.1 */ "printer-firmware-string-version", /* PWG 5110.1 */ "printer-firmware-version", /* PWG 5110.1 */ "printer-geo-location", "printer-get-attributes-supported", "printer-icc-profiles", "printer-icons", "printer-id", /* CUPS extension */ "printer-info", "printer-input-tray", /* IPP JPS3 */ "printer-is-accepting-jobs", "printer-is-shared", /* CUPS extension */ "printer-is-temporary", /* CUPS extension */ "printer-kind", /* IPP Paid Printing */ "printer-location", "printer-make-and-model", "printer-mandatory-job-attributes", "printer-message-date-time", "printer-message-from-operator", "printer-message-time", "printer-more-info", "printer-more-info-manufacturer", "printer-name", "printer-native-formats", "printer-organization", "printer-organizational-unit", "printer-output-tray", /* IPP JPS3 */ "printer-queue-id", /* CUPS extension */ "printer-settable-attributes-supported", "printer-state", "printer-state-change-date-time", "printer-state-change-time", "printer-state-message", "printer-state-reasons", "printer-supply", "printer-supply-description", "printer-supply-info-uri", "printer-type", /* CUPS extension */ "printer-up-time", "printer-uri-supported", "printer-uuid", "printer-xri-supported", "pwg-raster-document-resolution-supported", "pwg-raster-document-sheet-back", "pwg-raster-document-type-supported", "queued-job-count", "reference-uri-schemes-supported", "repertoire-supported", "requesting-user-name-allowed", /* CUPS extension */ "requesting-user-name-denied", /* CUPS extension */ "requesting-user-uri-supported", "subordinate-printers-supported", "urf-supported", /* CUPS extension */ "uri-authentication-supported", "uri-security-supported", "user-defined-value-supported", "which-jobs-supported", "xri-authentication-supported", "xri-security-supported", "xri-uri-scheme-supported" }; static const char * const subscription_description[] = { /* subscription-description group */ "notify-job-id", "notify-lease-expiration-time", "notify-printer-up-time", "notify-printer-uri", "notify-sequence-number", "notify-subscriber-user-name", "notify-subscriber-user-uri", "notify-subscription-id", "subscriptions-uuid" }; static const char * const subscription_template[] = { /* subscription-template group */ "notify-attributes", "notify-attributes-supported", "notify-charset", "notify-events", "notify-events-default", "notify-events-supported", "notify-lease-duration", "notify-lease-duration-default", "notify-lease-duration-supported", "notify-max-events-supported", "notify-natural-language", "notify-pull-method", "notify-pull-method-supported", "notify-recipient-uri", "notify-schemes-supported", "notify-time-interval", "notify-user-data" }; /* * Get the requested-attributes attribute... */ if ((requested = ippFindAttribute(request, "requested-attributes", IPP_TAG_KEYWORD)) == NULL) { /* * The Get-Jobs operation defaults to "job-id" and "job-uri", all others * default to "all"... */ if (ippGetOperation(request) == IPP_OP_GET_JOBS) { ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); cupsArrayAdd(ra, "job-id"); cupsArrayAdd(ra, "job-uri"); return (ra); } else return (NULL); } /* * If the attribute contains a single "all" keyword, return NULL... */ count = ippGetCount(requested); if (count == 1 && !strcmp(ippGetString(requested, 0, NULL), "all")) return (NULL); /* * Create an array using "strcmp" as the comparison function... */ ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); for (i = 0; i < count; i ++) { added = 0; value = ippGetString(requested, i, NULL); if (!strcmp(value, "document-description") || !strcmp(value, "all")) { for (j = 0; j < (int)(sizeof(document_description) / sizeof(document_description[0])); j ++) cupsArrayAdd(ra, (void *)document_description[j]); added = 1; } if (!strcmp(value, "document-template") || !strcmp(value, "all")) { for (j = 0; j < (int)(sizeof(document_template) / sizeof(document_template[0])); j ++) cupsArrayAdd(ra, (void *)document_template[j]); added = 1; } if (!strcmp(value, "job-description") || !strcmp(value, "all")) { for (j = 0; j < (int)(sizeof(job_description) / sizeof(job_description[0])); j ++) cupsArrayAdd(ra, (void *)job_description[j]); added = 1; } if (!strcmp(value, "job-template") || !strcmp(value, "all")) { for (j = 0; j < (int)(sizeof(job_template) / sizeof(job_template[0])); j ++) cupsArrayAdd(ra, (void *)job_template[j]); added = 1; } if (!strcmp(value, "printer-description") || !strcmp(value, "all")) { for (j = 0; j < (int)(sizeof(printer_description) / sizeof(printer_description[0])); j ++) cupsArrayAdd(ra, (void *)printer_description[j]); added = 1; } if (!strcmp(value, "subscription-description") || !strcmp(value, "all")) { for (j = 0; j < (int)(sizeof(subscription_description) / sizeof(subscription_description[0])); j ++) cupsArrayAdd(ra, (void *)subscription_description[j]); added = 1; } if (!strcmp(value, "subscription-template") || !strcmp(value, "all")) { for (j = 0; j < (int)(sizeof(subscription_template) / sizeof(subscription_template[0])); j ++) cupsArrayAdd(ra, (void *)subscription_template[j]); added = 1; } if (!added) cupsArrayAdd(ra, (void *)value); } return (ra); } /* * 'ippEnumString()' - Return a string corresponding to the enum value. */ const char * /* O - Enum string */ ippEnumString(const char *attrname, /* I - Attribute name */ int enumvalue) /* I - Enum value */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ /* * Check for standard enum values... */ if (!strcmp(attrname, "document-state") && enumvalue >= 3 && enumvalue < (3 + (int)(sizeof(ipp_document_states) / sizeof(ipp_document_states[0])))) return (ipp_document_states[enumvalue - 3]); else if (!strcmp(attrname, "finishings") || !strcmp(attrname, "finishings-actual") || !strcmp(attrname, "finishings-default") || !strcmp(attrname, "finishings-ready") || !strcmp(attrname, "finishings-supported") || !strcmp(attrname, "job-finishings") || !strcmp(attrname, "job-finishings-default") || !strcmp(attrname, "job-finishings-supported")) { if (enumvalue >= 3 && enumvalue < (3 + (int)(sizeof(ipp_finishings) / sizeof(ipp_finishings[0])))) return (ipp_finishings[enumvalue - 3]); else if (enumvalue >= 0x40000000 && enumvalue <= (0x40000000 + (int)(sizeof(ipp_finishings_vendor) / sizeof(ipp_finishings_vendor[0])))) return (ipp_finishings_vendor[enumvalue - 0x40000000]); } else if ((!strcmp(attrname, "job-collation-type") || !strcmp(attrname, "job-collation-type-actual")) && enumvalue >= 3 && enumvalue < (3 + (int)(sizeof(ipp_job_collation_types) / sizeof(ipp_job_collation_types[0])))) return (ipp_job_collation_types[enumvalue - 3]); else if (!strcmp(attrname, "job-state") && enumvalue >= IPP_JSTATE_PENDING && enumvalue <= IPP_JSTATE_COMPLETED) return (ipp_job_states[enumvalue - IPP_JSTATE_PENDING]); else if (!strcmp(attrname, "operations-supported")) return (ippOpString((ipp_op_t)enumvalue)); else if ((!strcmp(attrname, "orientation-requested") || !strcmp(attrname, "orientation-requested-actual") || !strcmp(attrname, "orientation-requested-default") || !strcmp(attrname, "orientation-requested-supported")) && enumvalue >= 3 && enumvalue < (3 + (int)(sizeof(ipp_orientation_requesteds) / sizeof(ipp_orientation_requesteds[0])))) return (ipp_orientation_requesteds[enumvalue - 3]); else if ((!strcmp(attrname, "print-quality") || !strcmp(attrname, "print-quality-actual") || !strcmp(attrname, "print-quality-default") || !strcmp(attrname, "print-quality-supported")) && enumvalue >= 3 && enumvalue < (3 + (int)(sizeof(ipp_print_qualities) / sizeof(ipp_print_qualities[0])))) return (ipp_print_qualities[enumvalue - 3]); else if (!strcmp(attrname, "printer-state") && enumvalue >= IPP_PSTATE_IDLE && enumvalue <= IPP_PSTATE_STOPPED) return (ipp_printer_states[enumvalue - IPP_PSTATE_IDLE]); /* * Not a standard enum value, just return the decimal equivalent... */ snprintf(cg->ipp_unknown, sizeof(cg->ipp_unknown), "%d", enumvalue); return (cg->ipp_unknown); } /* * 'ippEnumValue()' - Return the value associated with a given enum string. */ int /* O - Enum value or -1 if unknown */ ippEnumValue(const char *attrname, /* I - Attribute name */ const char *enumstring) /* I - Enum string */ { int i, /* Looping var */ num_strings; /* Number of strings to compare */ const char * const *strings; /* Strings to compare */ /* * If the string is just a number, return it... */ if (isdigit(*enumstring & 255)) return ((int)strtol(enumstring, NULL, 0)); /* * Otherwise look up the string... */ if (!strcmp(attrname, "document-state")) { num_strings = (int)(sizeof(ipp_document_states) / sizeof(ipp_document_states[0])); strings = ipp_document_states; } else if (!strcmp(attrname, "finishings") || !strcmp(attrname, "finishings-actual") || !strcmp(attrname, "finishings-default") || !strcmp(attrname, "finishings-ready") || !strcmp(attrname, "finishings-supported")) { for (i = 0; i < (int)(sizeof(ipp_finishings_vendor) / sizeof(ipp_finishings_vendor[0])); i ++) if (!strcmp(enumstring, ipp_finishings_vendor[i])) return (i + 0x40000000); num_strings = (int)(sizeof(ipp_finishings) / sizeof(ipp_finishings[0])); strings = ipp_finishings; } else if (!strcmp(attrname, "job-collation-type") || !strcmp(attrname, "job-collation-type-actual")) { num_strings = (int)(sizeof(ipp_job_collation_types) / sizeof(ipp_job_collation_types[0])); strings = ipp_job_collation_types; } else if (!strcmp(attrname, "job-state")) { num_strings = (int)(sizeof(ipp_job_states) / sizeof(ipp_job_states[0])); strings = ipp_job_states; } else if (!strcmp(attrname, "operations-supported")) return (ippOpValue(enumstring)); else if (!strcmp(attrname, "orientation-requested") || !strcmp(attrname, "orientation-requested-actual") || !strcmp(attrname, "orientation-requested-default") || !strcmp(attrname, "orientation-requested-supported")) { num_strings = (int)(sizeof(ipp_orientation_requesteds) / sizeof(ipp_orientation_requesteds[0])); strings = ipp_orientation_requesteds; } else if (!strcmp(attrname, "print-quality") || !strcmp(attrname, "print-quality-actual") || !strcmp(attrname, "print-quality-default") || !strcmp(attrname, "print-quality-supported")) { num_strings = (int)(sizeof(ipp_print_qualities) / sizeof(ipp_print_qualities[0])); strings = ipp_print_qualities; } else if (!strcmp(attrname, "printer-state")) { num_strings = (int)(sizeof(ipp_printer_states) / sizeof(ipp_printer_states[0])); strings = ipp_printer_states; } else return (-1); for (i = 0; i < num_strings; i ++) if (!strcmp(enumstring, strings[i])) return (i + 3); return (-1); } /* * 'ippErrorString()' - Return a name for the given status code. */ const char * /* O - Text string */ ippErrorString(ipp_status_t error) /* I - Error status */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ /* * See if the error code is a known value... */ if (error >= IPP_STATUS_OK && error <= IPP_STATUS_OK_EVENTS_COMPLETE) return (ipp_status_oks[error]); else if (error == IPP_STATUS_REDIRECTION_OTHER_SITE) return ("redirection-other-site"); else if (error == IPP_STATUS_CUPS_SEE_OTHER) return ("cups-see-other"); else if (error >= IPP_STATUS_ERROR_BAD_REQUEST && error <= IPP_STATUS_ERROR_ACCOUNT_AUTHORIZATION_FAILED) return (ipp_status_400s[error - IPP_STATUS_ERROR_BAD_REQUEST]); else if (error >= 0x480 && error <= IPP_STATUS_ERROR_CUPS_ACCOUNT_AUTHORIZATION_FAILED) return (ipp_status_480s[error - 0x0480]); else if (error >= IPP_STATUS_ERROR_INTERNAL && error <= IPP_STATUS_ERROR_TOO_MANY_DOCUMENTS) return (ipp_status_500s[error - IPP_STATUS_ERROR_INTERNAL]); else if (error >= IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED && error <= IPP_STATUS_ERROR_CUPS_UPGRADE_REQUIRED) return (ipp_status_1000s[error - IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED]); /* * No, build an "0xxxxx" error string... */ sprintf(cg->ipp_unknown, "0x%04x", error); return (cg->ipp_unknown); } /* * 'ippErrorValue()' - Return a status code for the given name. * * @since CUPS 1.2/macOS 10.5@ */ ipp_status_t /* O - IPP status code */ ippErrorValue(const char *name) /* I - Name */ { size_t i; /* Looping var */ for (i = 0; i < (sizeof(ipp_status_oks) / sizeof(ipp_status_oks[0])); i ++) if (!_cups_strcasecmp(name, ipp_status_oks[i])) return ((ipp_status_t)i); if (!_cups_strcasecmp(name, "redirection-other-site")) return (IPP_STATUS_REDIRECTION_OTHER_SITE); if (!_cups_strcasecmp(name, "cups-see-other")) return (IPP_STATUS_CUPS_SEE_OTHER); for (i = 0; i < (sizeof(ipp_status_400s) / sizeof(ipp_status_400s[0])); i ++) if (!_cups_strcasecmp(name, ipp_status_400s[i])) return ((ipp_status_t)(i + 0x400)); for (i = 0; i < (sizeof(ipp_status_480s) / sizeof(ipp_status_480s[0])); i ++) if (!_cups_strcasecmp(name, ipp_status_480s[i])) return ((ipp_status_t)(i + 0x480)); for (i = 0; i < (sizeof(ipp_status_500s) / sizeof(ipp_status_500s[0])); i ++) if (!_cups_strcasecmp(name, ipp_status_500s[i])) return ((ipp_status_t)(i + 0x500)); for (i = 0; i < (sizeof(ipp_status_1000s) / sizeof(ipp_status_1000s[0])); i ++) if (!_cups_strcasecmp(name, ipp_status_1000s[i])) return ((ipp_status_t)(i + 0x1000)); return ((ipp_status_t)-1); } /* * 'ippOpString()' - Return a name for the given operation id. * * @since CUPS 1.2/macOS 10.5@ */ const char * /* O - Name */ ippOpString(ipp_op_t op) /* I - Operation ID */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ /* * See if the operation ID is a known value... */ if (op >= IPP_OP_PRINT_JOB && op < (ipp_op_t)(sizeof(ipp_std_ops) / sizeof(ipp_std_ops[0]))) return (ipp_std_ops[op]); else if (op == IPP_OP_PRIVATE) return ("windows-ext"); else if (op >= IPP_OP_CUPS_GET_DEFAULT && op <= IPP_OP_CUPS_GET_PPD) return (ipp_cups_ops[op - IPP_OP_CUPS_GET_DEFAULT]); else if (op >= IPP_OP_CUPS_GET_DOCUMENT && op <= IPP_OP_CUPS_CREATE_LOCAL_PRINTER) return (ipp_cups_ops2[op - IPP_OP_CUPS_GET_DOCUMENT]); /* * No, build an "0xxxxx" operation string... */ sprintf(cg->ipp_unknown, "0x%04x", op); return (cg->ipp_unknown); } /* * 'ippOpValue()' - Return an operation id for the given name. * * @since CUPS 1.2/macOS 10.5@ */ ipp_op_t /* O - Operation ID */ ippOpValue(const char *name) /* I - Textual name */ { size_t i; /* Looping var */ if (!strncmp(name, "0x", 2)) return ((ipp_op_t)strtol(name + 2, NULL, 16)); for (i = 0; i < (sizeof(ipp_std_ops) / sizeof(ipp_std_ops[0])); i ++) if (!_cups_strcasecmp(name, ipp_std_ops[i])) return ((ipp_op_t)i); if (!_cups_strcasecmp(name, "windows-ext")) return (IPP_OP_PRIVATE); for (i = 0; i < (sizeof(ipp_cups_ops) / sizeof(ipp_cups_ops[0])); i ++) if (!_cups_strcasecmp(name, ipp_cups_ops[i])) return ((ipp_op_t)(i + 0x4001)); for (i = 0; i < (sizeof(ipp_cups_ops2) / sizeof(ipp_cups_ops2[0])); i ++) if (!_cups_strcasecmp(name, ipp_cups_ops2[i])) return ((ipp_op_t)(i + 0x4027)); if (!_cups_strcasecmp(name, "Create-Job-Subscription")) return (IPP_OP_CREATE_JOB_SUBSCRIPTIONS); if (!_cups_strcasecmp(name, "Create-Printer-Subscription")) return (IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS); if (!_cups_strcasecmp(name, "CUPS-Add-Class")) return (IPP_OP_CUPS_ADD_MODIFY_CLASS); if (!_cups_strcasecmp(name, "CUPS-Add-Printer")) return (IPP_OP_CUPS_ADD_MODIFY_PRINTER); return (IPP_OP_CUPS_INVALID); } /* * 'ippPort()' - Return the default IPP port number. */ int /* O - Port number */ ippPort(void) { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ DEBUG_puts("ippPort()"); if (!cg->ipp_port) _cupsSetDefaults(); DEBUG_printf(("1ippPort: Returning %d...", cg->ipp_port)); return (cg->ipp_port); } /* * 'ippSetPort()' - Set the default port number. */ void ippSetPort(int p) /* I - Port number to use */ { DEBUG_printf(("ippSetPort(p=%d)", p)); _cupsGlobals()->ipp_port = p; } /* * 'ippStateString()' - Return the name corresponding to a state value. * * @since CUPS 2.0/OS 10.10@ */ const char * /* O - State name */ ippStateString(ipp_state_t state) /* I - State value */ { if (state >= IPP_STATE_ERROR && state <= IPP_STATE_DATA) return (ipp_states[state - IPP_STATE_ERROR]); else return ("UNKNOWN"); } /* * 'ippTagString()' - Return the tag name corresponding to a tag value. * * The returned names are defined in RFC 8011 and the IANA IPP Registry. * * @since CUPS 1.4/macOS 10.6@ */ const char * /* O - Tag name */ ippTagString(ipp_tag_t tag) /* I - Tag value */ { tag &= IPP_TAG_CUPS_MASK; if (tag < (ipp_tag_t)(sizeof(ipp_tag_names) / sizeof(ipp_tag_names[0]))) return (ipp_tag_names[tag]); else return ("UNKNOWN"); } /* * 'ippTagValue()' - Return the tag value corresponding to a tag name. * * The tag names are defined in RFC 8011 and the IANA IPP Registry. * * @since CUPS 1.4/macOS 10.6@ */ ipp_tag_t /* O - Tag value */ ippTagValue(const char *name) /* I - Tag name */ { size_t i; /* Looping var */ for (i = 0; i < (sizeof(ipp_tag_names) / sizeof(ipp_tag_names[0])); i ++) if (!_cups_strcasecmp(name, ipp_tag_names[i])) return ((ipp_tag_t)i); if (!_cups_strcasecmp(name, "operation")) return (IPP_TAG_OPERATION); else if (!_cups_strcasecmp(name, "job")) return (IPP_TAG_JOB); else if (!_cups_strcasecmp(name, "printer")) return (IPP_TAG_PRINTER); else if (!_cups_strcasecmp(name, "unsupported")) return (IPP_TAG_UNSUPPORTED_GROUP); else if (!_cups_strcasecmp(name, "subscription")) return (IPP_TAG_SUBSCRIPTION); else if (!_cups_strcasecmp(name, "event")) return (IPP_TAG_EVENT_NOTIFICATION); else if (!_cups_strcasecmp(name, "language")) return (IPP_TAG_LANGUAGE); else if (!_cups_strcasecmp(name, "mimetype")) return (IPP_TAG_MIMETYPE); else if (!_cups_strcasecmp(name, "name")) return (IPP_TAG_NAME); else if (!_cups_strcasecmp(name, "text")) return (IPP_TAG_TEXT); else if (!_cups_strcasecmp(name, "begCollection")) return (IPP_TAG_BEGIN_COLLECTION); else return (IPP_TAG_ZERO); } /* * 'ipp_col_string()' - Convert a collection to a string. */ static size_t /* O - Number of bytes */ ipp_col_string(ipp_t *col, /* I - Collection attribute */ char *buffer, /* I - Buffer or NULL */ size_t bufsize) /* I - Size of buffer */ { char *bufptr, /* Position in buffer */ *bufend, /* End of buffer */ prefix = '{', /* Prefix character */ temp[256]; /* Temporary string */ ipp_attribute_t *attr; /* Current member attribute */ if (!col) { if (buffer) *buffer = '\0'; return (0); } bufptr = buffer; bufend = buffer + bufsize - 1; for (attr = col->attrs; attr; attr = attr->next) { if (!attr->name) continue; if (buffer && bufptr < bufend) *bufptr = prefix; bufptr ++; prefix = ' '; if (buffer && bufptr < bufend) bufptr += snprintf(bufptr, (size_t)(bufend - bufptr + 1), "%s=", attr->name); else bufptr += strlen(attr->name) + 1; if (buffer && bufptr < bufend) bufptr += ippAttributeString(attr, bufptr, (size_t)(bufend - bufptr + 1)); else bufptr += ippAttributeString(attr, temp, sizeof(temp)); } if (prefix == '{') { if (buffer && bufptr < bufend) *bufptr = prefix; bufptr ++; } if (buffer && bufptr < bufend) *bufptr = '}'; bufptr ++; return ((size_t)(bufptr - buffer)); } ippsample/cups/thread.c0000644000175000017500000002131613240604116014127 0ustar tilltill/* * Threading primitives for CUPS. * * Copyright 2009-2017 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #include "thread-private.h" #if defined(HAVE_PTHREAD_H) /* * '_cupsCondBroadcast()' - Wake up waiting threads. */ void _cupsCondBroadcast(_cups_cond_t *cond) /* I - Condition */ { pthread_cond_broadcast(cond); } /* * '_cupsCondInit()' - Initialize a condition variable. */ void _cupsCondInit(_cups_cond_t *cond) /* I - Condition */ { pthread_cond_init(cond, NULL); } /* * '_cupsCondWait()' - Wait for a condition with optional timeout. */ void _cupsCondWait(_cups_cond_t *cond, /* I - Condition */ _cups_mutex_t *mutex, /* I - Mutex */ double timeout) /* I - Timeout in seconds (0 or negative for none) */ { if (timeout > 0.0) { struct timespec abstime; /* Timeout */ abstime.tv_sec = (long)timeout; abstime.tv_nsec = (long)(1000000000 * (timeout - (long)timeout)); pthread_cond_timedwait(cond, mutex, &abstime); } else pthread_cond_wait(cond, mutex); } /* * '_cupsMutexInit()' - Initialize a mutex. */ void _cupsMutexInit(_cups_mutex_t *mutex) /* I - Mutex */ { pthread_mutex_init(mutex, NULL); } /* * '_cupsMutexLock()' - Lock a mutex. */ void _cupsMutexLock(_cups_mutex_t *mutex) /* I - Mutex */ { pthread_mutex_lock(mutex); } /* * '_cupsMutexUnlock()' - Unlock a mutex. */ void _cupsMutexUnlock(_cups_mutex_t *mutex) /* I - Mutex */ { pthread_mutex_unlock(mutex); } /* * '_cupsRWInit()' - Initialize a reader/writer lock. */ void _cupsRWInit(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */ { pthread_rwlock_init(rwlock, NULL); } /* * '_cupsRWLockRead()' - Acquire a reader/writer lock for reading. */ void _cupsRWLockRead(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */ { pthread_rwlock_rdlock(rwlock); } /* * '_cupsRWLockWrite()' - Acquire a reader/writer lock for writing. */ void _cupsRWLockWrite(_cups_rwlock_t *rwlock)/* I - Reader/writer lock */ { pthread_rwlock_wrlock(rwlock); } /* * '_cupsRWUnlock()' - Release a reader/writer lock. */ void _cupsRWUnlock(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */ { pthread_rwlock_unlock(rwlock); } /* * '_cupsThreadCancel()' - Cancel (kill) a thread. */ void _cupsThreadCancel(_cups_thread_t thread)/* I - Thread ID */ { pthread_cancel(thread); } /* * '_cupsThreadCreate()' - Create a thread. */ _cups_thread_t /* O - Thread ID */ _cupsThreadCreate( _cups_thread_func_t func, /* I - Entry point */ void *arg) /* I - Entry point context */ { pthread_t thread; if (pthread_create(&thread, NULL, (void *(*)(void *))func, arg)) return (0); else return (thread); } /* * '_cupsThreadDetach()' - Tell the OS that the thread is running independently. */ void _cupsThreadDetach(_cups_thread_t thread)/* I - Thread ID */ { pthread_detach(thread); } /* * '_cupsThreadWait()' - Wait for a thread to exit. */ void * /* O - Return value */ _cupsThreadWait(_cups_thread_t thread) /* I - Thread ID */ { void *ret; /* Return value */ if (pthread_join(thread, &ret)) return (NULL); else return (ret); } #elif defined(WIN32) # include /* * '_cupsCondBroadcast()' - Wake up waiting threads. */ void _cupsCondBroadcast(_cups_cond_t *cond) /* I - Condition */ { // TODO: Implement me } /* * '_cupsCondInit()' - Initialize a condition variable. */ void _cupsCondInit(_cups_cond_t *cond) /* I - Condition */ { // TODO: Implement me } /* * '_cupsCondWait()' - Wait for a condition with optional timeout. */ void _cupsCondWait(_cups_cond_t *cond, /* I - Condition */ _cups_mutex_t *mutex, /* I - Mutex */ double timeout) /* I - Timeout in seconds (0 or negative for none) */ { // TODO: Implement me } /* * '_cupsMutexInit()' - Initialize a mutex. */ void _cupsMutexInit(_cups_mutex_t *mutex) /* I - Mutex */ { InitializeCriticalSection(&mutex->m_criticalSection); mutex->m_init = 1; } /* * '_cupsMutexLock()' - Lock a mutex. */ void _cupsMutexLock(_cups_mutex_t *mutex) /* I - Mutex */ { if (!mutex->m_init) { _cupsGlobalLock(); if (!mutex->m_init) { InitializeCriticalSection(&mutex->m_criticalSection); mutex->m_init = 1; } _cupsGlobalUnlock(); } EnterCriticalSection(&mutex->m_criticalSection); } /* * '_cupsMutexUnlock()' - Unlock a mutex. */ void _cupsMutexUnlock(_cups_mutex_t *mutex) /* I - Mutex */ { LeaveCriticalSection(&mutex->m_criticalSection); } /* * '_cupsRWInit()' - Initialize a reader/writer lock. */ void _cupsRWInit(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */ { _cupsMutexInit((_cups_mutex_t *)rwlock); } /* * '_cupsRWLockRead()' - Acquire a reader/writer lock for reading. */ void _cupsRWLockRead(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */ { _cupsMutexLock((_cups_mutex_t *)rwlock); } /* * '_cupsRWLockWrite()' - Acquire a reader/writer lock for writing. */ void _cupsRWLockWrite(_cups_rwlock_t *rwlock)/* I - Reader/writer lock */ { _cupsMutexLock((_cups_mutex_t *)rwlock); } /* * '_cupsRWUnlock()' - Release a reader/writer lock. */ void _cupsRWUnlock(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */ { _cupsMutexUnlock((_cups_mutex_t *)rwlock); } /* * '_cupsThreadCancel()' - Cancel (kill) a thread. */ void _cupsThreadCancel(_cups_thread_t thread)/* I - Thread ID */ { // TODO: Implement me } /* * '_cupsThreadCreate()' - Create a thread. */ _cups_thread_t /* O - Thread ID */ _cupsThreadCreate( _cups_thread_func_t func, /* I - Entry point */ void *arg) /* I - Entry point context */ { return (_beginthreadex(NULL, 0, (LPTHREAD_START_ROUTINE)func, arg, 0, NULL)); } /* * '_cupsThreadDetach()' - Tell the OS that the thread is running independently. */ void _cupsThreadDetach(_cups_thread_t thread)/* I - Thread ID */ { // TODO: Implement me (void)thread; } /* * '_cupsThreadWait()' - Wait for a thread to exit. */ void * /* O - Return value */ _cupsThreadWait(_cups_thread_t thread) /* I - Thread ID */ { // TODO: Implement me (void)thread; return (NULL); } #else /* No threading */ /* * '_cupsCondBroadcast()' - Wake up waiting threads. */ void _cupsCondBroadcast(_cups_cond_t *cond) /* I - Condition */ { // TODO: Implement me } /* * '_cupsCondInit()' - Initialize a condition variable. */ void _cupsCondInit(_cups_cond_t *cond) /* I - Condition */ { // TODO: Implement me } /* * '_cupsCondWait()' - Wait for a condition with optional timeout. */ void _cupsCondWait(_cups_cond_t *cond, /* I - Condition */ _cups_mutex_t *mutex, /* I - Mutex */ double timeout) /* I - Timeout in seconds (0 or negative for none) */ { // TODO: Implement me } /* * '_cupsMutexInit()' - Initialize a mutex. */ void _cupsMutexInit(_cups_mutex_t *mutex) /* I - Mutex */ { (void)mutex; } /* * '_cupsMutexLock()' - Lock a mutex. */ void _cupsMutexLock(_cups_mutex_t *mutex) /* I - Mutex */ { (void)mutex; } /* * '_cupsMutexUnlock()' - Unlock a mutex. */ void _cupsMutexUnlock(_cups_mutex_t *mutex) /* I - Mutex */ { (void)mutex; } /* * '_cupsRWInit()' - Initialize a reader/writer lock. */ void _cupsRWInit(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */ { (void)rwlock; } /* * '_cupsRWLockRead()' - Acquire a reader/writer lock for reading. */ void _cupsRWLockRead(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */ { (void)rwlock; } /* * '_cupsRWLockWrite()' - Acquire a reader/writer lock for writing. */ void _cupsRWLockWrite(_cups_rwlock_t *rwlock)/* I - Reader/writer lock */ { (void)rwlock; } /* * '_cupsRWUnlock()' - Release a reader/writer lock. */ void _cupsRWUnlock(_cups_rwlock_t *rwlock) /* I - Reader/writer lock */ { (void)rwlock; } /* * '_cupsThreadCancel()' - Cancel (kill) a thread. */ void _cupsThreadCancel(_cups_thread_t thread)/* I - Thread ID */ { (void)thread; } /* * '_cupsThreadCreate()' - Create a thread. */ _cups_thread_t /* O - Thread ID */ _cupsThreadCreate( _cups_thread_func_t func, /* I - Entry point */ void *arg) /* I - Entry point context */ { fputs("DEBUG: CUPS was compiled without threading support, no thread created.\n", stderr); (void)func; (void)arg; return (0); } /* * '_cupsThreadDetach()' - Tell the OS that the thread is running independently. */ void _cupsThreadDetach(_cups_thread_t thread)/* I - Thread ID */ { (void)thread; } /* * '_cupsThreadWait()' - Wait for a thread to exit. */ void * /* O - Return value */ _cupsThreadWait(_cups_thread_t thread) /* I - Thread ID */ { (void)thread; return (NULL); } #endif /* HAVE_PTHREAD_H */ ippsample/cups/raster-private.h0000644000175000017500000000227213240604116015635 0ustar tilltill/* * Private image library definitions for CUPS. * * Copyright 2007-2015 by Apple Inc. * Copyright 1993-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_RASTER_PRIVATE_H_ # define _CUPS_RASTER_PRIVATE_H_ /* * Include necessary headers... */ # include "raster.h" # include # include # include # ifdef WIN32 # include # include /* for htonl() definition */ # else # include # include # endif /* WIN32 */ /* * min/max macros... */ # ifndef max # define max(a,b) ((a) > (b) ? (a) : (b)) # endif /* !max */ # ifndef min # define min(a,b) ((a) < (b) ? (a) : (b)) # endif /* !min */ /* * Prototypes... */ extern int _cupsRasterExecPS(cups_page_header2_t *h, int *preferred_bits, const char *code) __attribute__((nonnull(3))); extern void _cupsRasterAddError(const char *f, ...) __attribute__((__format__(__printf__, 1, 2))); extern void _cupsRasterClearError(void); #endif /* !_CUPS_RASTER_PRIVATE_H_ */ ippsample/cups/langprintf.c0000644000175000017500000001665213240604116015033 0ustar tilltill/* * Localized printf/puts functions for CUPS. * * Copyright 2007-2014 by Apple Inc. * Copyright 2002-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" /* * '_cupsLangPrintError()' - Print a message followed by a standard error. */ void _cupsLangPrintError(const char *prefix, /* I - Non-localized message prefix */ const char *message)/* I - Message */ { ssize_t bytes; /* Number of bytes formatted */ int last_errno; /* Last error */ char buffer[2048], /* Message buffer */ *bufptr, /* Pointer into buffer */ output[8192]; /* Output buffer */ _cups_globals_t *cg; /* Global data */ /* * Range check... */ if (!message) return; /* * Save the errno value... */ last_errno = errno; /* * Get the message catalog... */ cg = _cupsGlobals(); if (!cg->lang_default) cg->lang_default = cupsLangDefault(); /* * Format the message... */ if (prefix) { snprintf(buffer, sizeof(buffer), "%s:", prefix); bufptr = buffer + strlen(buffer); } else bufptr = buffer; snprintf(bufptr, sizeof(buffer) - (size_t)(bufptr - buffer), /* TRANSLATORS: Message is "subject: error" */ _cupsLangString(cg->lang_default, _("%s: %s")), _cupsLangString(cg->lang_default, message), strerror(last_errno)); strlcat(buffer, "\n", sizeof(buffer)); /* * Convert and write to stderr... */ bytes = cupsUTF8ToCharset(output, (cups_utf8_t *)buffer, sizeof(output), cg->lang_default->encoding); if (bytes > 0) fwrite(output, 1, (size_t)bytes, stderr); } /* * '_cupsLangPrintFilter()' - Print a formatted filter message string to a file. */ int /* O - Number of bytes written */ _cupsLangPrintFilter( FILE *fp, /* I - File to write to */ const char *prefix, /* I - Non-localized message prefix */ const char *message, /* I - Message string to use */ ...) /* I - Additional arguments as needed */ { ssize_t bytes; /* Number of bytes formatted */ char temp[2048], /* Temporary format buffer */ buffer[2048], /* Message buffer */ output[8192]; /* Output buffer */ va_list ap; /* Pointer to additional arguments */ _cups_globals_t *cg; /* Global data */ /* * Range check... */ if (!fp || !message) return (-1); cg = _cupsGlobals(); if (!cg->lang_default) cg->lang_default = cupsLangDefault(); /* * Format the string... */ va_start(ap, message); snprintf(temp, sizeof(temp), "%s: %s\n", prefix, _cupsLangString(cg->lang_default, message)); vsnprintf(buffer, sizeof(buffer), temp, ap); va_end(ap); /* * Transcode to the destination charset... */ bytes = cupsUTF8ToCharset(output, (cups_utf8_t *)buffer, sizeof(output), cg->lang_default->encoding); /* * Write the string and return the number of bytes written... */ if (bytes > 0) return ((int)fwrite(output, 1, (size_t)bytes, fp)); else return ((int)bytes); } /* * '_cupsLangPrintf()' - Print a formatted message string to a file. */ int /* O - Number of bytes written */ _cupsLangPrintf(FILE *fp, /* I - File to write to */ const char *message, /* I - Message string to use */ ...) /* I - Additional arguments as needed */ { ssize_t bytes; /* Number of bytes formatted */ char buffer[2048], /* Message buffer */ output[8192]; /* Output buffer */ va_list ap; /* Pointer to additional arguments */ _cups_globals_t *cg; /* Global data */ /* * Range check... */ if (!fp || !message) return (-1); cg = _cupsGlobals(); if (!cg->lang_default) cg->lang_default = cupsLangDefault(); /* * Format the string... */ va_start(ap, message); vsnprintf(buffer, sizeof(buffer) - 1, _cupsLangString(cg->lang_default, message), ap); va_end(ap); strlcat(buffer, "\n", sizeof(buffer)); /* * Transcode to the destination charset... */ bytes = cupsUTF8ToCharset(output, (cups_utf8_t *)buffer, sizeof(output), cg->lang_default->encoding); /* * Write the string and return the number of bytes written... */ if (bytes > 0) return ((int)fwrite(output, 1, (size_t)bytes, fp)); else return ((int)bytes); } /* * '_cupsLangPuts()' - Print a static message string to a file. */ int /* O - Number of bytes written */ _cupsLangPuts(FILE *fp, /* I - File to write to */ const char *message) /* I - Message string to use */ { ssize_t bytes; /* Number of bytes formatted */ char output[8192]; /* Message buffer */ _cups_globals_t *cg; /* Global data */ /* * Range check... */ if (!fp || !message) return (-1); cg = _cupsGlobals(); if (!cg->lang_default) cg->lang_default = cupsLangDefault(); /* * Transcode to the destination charset... */ bytes = cupsUTF8ToCharset(output, (cups_utf8_t *)_cupsLangString(cg->lang_default, message), sizeof(output) - 4, cg->lang_default->encoding); bytes += cupsUTF8ToCharset(output + bytes, (cups_utf8_t *)"\n", (int)(sizeof(output) - (size_t)bytes), cg->lang_default->encoding); /* * Write the string and return the number of bytes written... */ if (bytes > 0) return ((int)fwrite(output, 1, (size_t)bytes, fp)); else return ((int)bytes); } /* * '_cupsSetLocale()' - Set the current locale and transcode the command-line. */ void _cupsSetLocale(char *argv[]) /* IO - Command-line arguments */ { int i; /* Looping var */ char buffer[8192]; /* Command-line argument buffer */ _cups_globals_t *cg; /* Global data */ #ifdef LC_TIME const char *lc_time; /* Current LC_TIME value */ char new_lc_time[255], /* New LC_TIME value */ *charset; /* Pointer to character set */ #endif /* LC_TIME */ /* * Set the locale so that times, etc. are displayed properly. * * Unfortunately, while we need the localized time value, we *don't* * want to use the localized charset for the time value, so we need * to set LC_TIME to the locale name with .UTF-8 on the end (if * the locale includes a character set specifier...) */ setlocale(LC_ALL, ""); #ifdef LC_TIME if ((lc_time = setlocale(LC_TIME, NULL)) == NULL) lc_time = setlocale(LC_ALL, NULL); if (lc_time) { strlcpy(new_lc_time, lc_time, sizeof(new_lc_time)); if ((charset = strchr(new_lc_time, '.')) == NULL) charset = new_lc_time + strlen(new_lc_time); strlcpy(charset, ".UTF-8", sizeof(new_lc_time) - (size_t)(charset - new_lc_time)); } else strlcpy(new_lc_time, "C", sizeof(new_lc_time)); setlocale(LC_TIME, new_lc_time); #endif /* LC_TIME */ /* * Initialize the default language info... */ cg = _cupsGlobals(); if (!cg->lang_default) cg->lang_default = cupsLangDefault(); /* * Transcode the command-line arguments from the locale charset to * UTF-8... */ if (cg->lang_default->encoding != CUPS_US_ASCII && cg->lang_default->encoding != CUPS_UTF8) { for (i = 1; argv[i]; i ++) { /* * Try converting from the locale charset to UTF-8... */ if (cupsCharsetToUTF8((cups_utf8_t *)buffer, argv[i], sizeof(buffer), cg->lang_default->encoding) < 0) continue; /* * Save the new string if it differs from the original... */ if (strcmp(buffer, argv[i])) argv[i] = strdup(buffer); } } } ippsample/cups/dest.c0000644000175000017500000036066013240604116013627 0ustar tilltill/* * User-defined destination (and option) support for CUPS. * * Copyright © 2007-2018 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ /* * Include necessary headers... */ #include "cups-private.h" #include #ifdef HAVE_NOTIFY_H # include #endif /* HAVE_NOTIFY_H */ #ifdef HAVE_POLL # include #endif /* HAVE_POLL */ #ifdef HAVE_DNSSD # include #endif /* HAVE_DNSSD */ #ifdef HAVE_AVAHI # include # include # include # include # include # include #define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX #endif /* HAVE_AVAHI */ /* * Constants... */ #ifdef __APPLE__ # if !TARGET_OS_IOS # include # define _CUPS_LOCATION_DEFAULTS 1 # endif /* !TARGET_OS_IOS */ # define kCUPSPrintingPrefs CFSTR("org.cups.PrintingPrefs") # define kDefaultPaperIDKey CFSTR("DefaultPaperID") # define kLastUsedPrintersKey CFSTR("LastUsedPrinters") # define kLocationNetworkKey CFSTR("Network") # define kLocationPrinterIDKey CFSTR("PrinterID") # define kUseLastPrinter CFSTR("UseLastPrinter") #endif /* __APPLE__ */ #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) # define _CUPS_DNSSD_GET_DESTS 250 /* Milliseconds for cupsGetDests */ # define _CUPS_DNSSD_MAXTIME 50 /* Milliseconds for maximum quantum of time */ #else # define _CUPS_DNSSD_GET_DESTS 0 /* Milliseconds for cupsGetDests */ #endif /* HAVE_DNSSD || HAVE_AVAHI */ /* * Types... */ #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) typedef enum _cups_dnssd_state_e /* Enumerated device state */ { _CUPS_DNSSD_NEW, _CUPS_DNSSD_QUERY, _CUPS_DNSSD_PENDING, _CUPS_DNSSD_ACTIVE, _CUPS_DNSSD_INCOMPATIBLE, _CUPS_DNSSD_ERROR } _cups_dnssd_state_t; typedef struct _cups_dnssd_data_s /* Enumeration data */ { # ifdef HAVE_DNSSD DNSServiceRef main_ref; /* Main service reference */ # else /* HAVE_AVAHI */ AvahiSimplePoll *simple_poll; /* Polling interface */ AvahiClient *client; /* Client information */ int got_data; /* Did we get data? */ int browsers; /* How many browsers are running? */ # endif /* HAVE_DNSSD */ cups_dest_cb_t cb; /* Callback */ void *user_data; /* User data pointer */ cups_ptype_t type, /* Printer type filter */ mask; /* Printer type mask */ cups_array_t *devices; /* Devices found so far */ int num_dests; /* Number of lpoptions destinations */ cups_dest_t *dests; /* lpoptions destinations */ char def_name[1024], /* Default printer name, if any */ *def_instance; /* Default printer instance, if any */ } _cups_dnssd_data_t; typedef struct _cups_dnssd_device_s /* Enumerated device */ { _cups_dnssd_state_t state; /* State of device listing */ # ifdef HAVE_DNSSD DNSServiceRef ref; /* Service reference for query */ # else /* HAVE_AVAHI */ AvahiRecordBrowser *ref; /* Browser for query */ # endif /* HAVE_DNSSD */ char *fullName, /* Full name */ *regtype, /* Registration type */ *domain; /* Domain name */ cups_ptype_t type; /* Device registration type */ cups_dest_t dest; /* Destination record */ } _cups_dnssd_device_t; typedef struct _cups_dnssd_resolve_s /* Data for resolving URI */ { int *cancel; /* Pointer to "cancel" variable */ struct timeval end_time; /* Ending time */ } _cups_dnssd_resolve_t; #endif /* HAVE_DNSSD */ typedef struct _cups_getdata_s { int num_dests; /* Number of destinations */ cups_dest_t *dests; /* Destinations */ char def_name[1024], /* Default printer name, if any */ *def_instance; /* Default printer instance, if any */ } _cups_getdata_t; typedef struct _cups_namedata_s { const char *name; /* Named destination */ cups_dest_t *dest; /* Destination */ } _cups_namedata_t; /* * Local functions... */ #if _CUPS_LOCATION_DEFAULTS static CFArrayRef appleCopyLocations(void); static CFStringRef appleCopyNetwork(void); #endif /* _CUPS_LOCATION_DEFAULTS */ #ifdef __APPLE__ static char *appleGetPaperSize(char *name, size_t namesize); #endif /* __APPLE__ */ #if _CUPS_LOCATION_DEFAULTS static CFStringRef appleGetPrinter(CFArrayRef locations, CFStringRef network, CFIndex *locindex); #endif /* _CUPS_LOCATION_DEFAULTS */ static cups_dest_t *cups_add_dest(const char *name, const char *instance, int *num_dests, cups_dest_t **dests); #ifdef __BLOCKS__ static int cups_block_cb(cups_dest_block_t block, unsigned flags, cups_dest_t *dest); #endif /* __BLOCKS__ */ static int cups_compare_dests(cups_dest_t *a, cups_dest_t *b); #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) # ifdef HAVE_DNSSD static void cups_dnssd_browse_cb(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context); # else /* HAVE_AVAHI */ static void cups_dnssd_browse_cb(AvahiServiceBrowser *browser, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *serviceName, const char *regtype, const char *replyDomain, AvahiLookupResultFlags flags, void *context); static void cups_dnssd_client_cb(AvahiClient *client, AvahiClientState state, void *context); # endif /* HAVE_DNSSD */ static int cups_dnssd_compare_devices(_cups_dnssd_device_t *a, _cups_dnssd_device_t *b); static void cups_dnssd_free_device(_cups_dnssd_device_t *device, _cups_dnssd_data_t *data); static _cups_dnssd_device_t * cups_dnssd_get_device(_cups_dnssd_data_t *data, const char *serviceName, const char *regtype, const char *replyDomain); # ifdef HAVE_DNSSD static void cups_dnssd_query_cb(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullName, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context); # else /* HAVE_AVAHI */ static int cups_dnssd_poll_cb(struct pollfd *pollfds, unsigned int num_pollfds, int timeout, void *context); static void cups_dnssd_query_cb(AvahiRecordBrowser *browser, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, uint16_t rrclass, uint16_t rrtype, const void *rdata, size_t rdlen, AvahiLookupResultFlags flags, void *context); # endif /* HAVE_DNSSD */ static const char *cups_dnssd_resolve(cups_dest_t *dest, const char *uri, int msec, int *cancel, cups_dest_cb_t cb, void *user_data); static int cups_dnssd_resolve_cb(void *context); static void cups_dnssd_unquote(char *dst, const char *src, size_t dstsize); static int cups_elapsed(struct timeval *t); #endif /* HAVE_DNSSD || HAVE_AVAHI */ static int cups_enum_dests(http_t *http, unsigned flags, int msec, int *cancel, cups_ptype_t type, cups_ptype_t mask, cups_dest_cb_t cb, void *user_data); static int cups_find_dest(const char *name, const char *instance, int num_dests, cups_dest_t *dests, int prev, int *rdiff); static int cups_get_cb(_cups_getdata_t *data, unsigned flags, cups_dest_t *dest); static char *cups_get_default(const char *filename, char *namebuf, size_t namesize, const char **instance); static int cups_get_dests(const char *filename, const char *match_name, const char *match_inst, int load_all, int user_default_set, int num_dests, cups_dest_t **dests); static char *cups_make_string(ipp_attribute_t *attr, char *buffer, size_t bufsize); static int cups_name_cb(_cups_namedata_t *data, unsigned flags, cups_dest_t *dest); static void cups_queue_name(char *name, const char *serviceName, size_t namesize); /* * 'cupsAddDest()' - Add a destination to the list of destinations. * * This function cannot be used to add a new class or printer queue, * it only adds a new container of saved options for the named * destination or instance. * * If the named destination already exists, the destination list is * returned unchanged. Adding a new instance of a destination creates * a copy of that destination's options. * * Use the @link cupsSaveDests@ function to save the updated list of * destinations to the user's lpoptions file. */ int /* O - New number of destinations */ cupsAddDest(const char *name, /* I - Destination name */ const char *instance, /* I - Instance name or @code NULL@ for none/primary */ int num_dests, /* I - Number of destinations */ cups_dest_t **dests) /* IO - Destinations */ { int i; /* Looping var */ cups_dest_t *dest; /* Destination pointer */ cups_dest_t *parent = NULL; /* Parent destination */ cups_option_t *doption, /* Current destination option */ *poption; /* Current parent option */ if (!name || !dests) return (0); if (!cupsGetDest(name, instance, num_dests, *dests)) { if (instance && !cupsGetDest(name, NULL, num_dests, *dests)) return (num_dests); if ((dest = cups_add_dest(name, instance, &num_dests, dests)) == NULL) return (num_dests); /* * Find the base dest again now the array has been realloc'd. */ parent = cupsGetDest(name, NULL, num_dests, *dests); if (instance && parent && parent->num_options > 0) { /* * Copy options from parent... */ dest->options = calloc(sizeof(cups_option_t), (size_t)parent->num_options); if (dest->options) { dest->num_options = parent->num_options; for (i = dest->num_options, doption = dest->options, poption = parent->options; i > 0; i --, doption ++, poption ++) { doption->name = _cupsStrRetain(poption->name); doption->value = _cupsStrRetain(poption->value); } } } } return (num_dests); } #ifdef __APPLE__ /* * '_cupsAppleCopyDefaultPaperID()' - Get the default paper ID. */ CFStringRef /* O - Default paper ID */ _cupsAppleCopyDefaultPaperID(void) { return (CFPreferencesCopyAppValue(kDefaultPaperIDKey, kCUPSPrintingPrefs)); } /* * '_cupsAppleCopyDefaultPrinter()' - Get the default printer at this location. */ CFStringRef /* O - Default printer name */ _cupsAppleCopyDefaultPrinter(void) { # if _CUPS_LOCATION_DEFAULTS CFStringRef network; /* Network location */ CFArrayRef locations; /* Location array */ CFStringRef locprinter; /* Current printer */ /* * Use location-based defaults only if "use last printer" is selected in the * system preferences... */ if (!_cupsAppleGetUseLastPrinter()) { DEBUG_puts("1_cupsAppleCopyDefaultPrinter: Not using last printer as " "default."); return (NULL); } /* * Get the current location... */ if ((network = appleCopyNetwork()) == NULL) { DEBUG_puts("1_cupsAppleCopyDefaultPrinter: Unable to get current " "network."); return (NULL); } /* * Lookup the network in the preferences... */ if ((locations = appleCopyLocations()) == NULL) { /* * Missing or bad location array, so no location-based default... */ DEBUG_puts("1_cupsAppleCopyDefaultPrinter: Missing or bad last used " "printer array."); CFRelease(network); return (NULL); } DEBUG_printf(("1_cupsAppleCopyDefaultPrinter: Got locations, %d entries.", (int)CFArrayGetCount(locations))); if ((locprinter = appleGetPrinter(locations, network, NULL)) != NULL) CFRetain(locprinter); CFRelease(network); CFRelease(locations); return (locprinter); # else return (NULL); # endif /* _CUPS_LOCATION_DEFAULTS */ } /* * '_cupsAppleGetUseLastPrinter()' - Get whether to use the last used printer. */ int /* O - 1 to use last printer, 0 otherwise */ _cupsAppleGetUseLastPrinter(void) { Boolean uselast, /* Use last printer preference value */ uselast_set; /* Valid is set? */ if (getenv("CUPS_DISABLE_APPLE_DEFAULT")) return (0); uselast = CFPreferencesGetAppBooleanValue(kUseLastPrinter, kCUPSPrintingPrefs, &uselast_set); if (!uselast_set) return (1); else return (uselast); } /* * '_cupsAppleSetDefaultPaperID()' - Set the default paper id. */ void _cupsAppleSetDefaultPaperID( CFStringRef name) /* I - New paper ID */ { CFPreferencesSetAppValue(kDefaultPaperIDKey, name, kCUPSPrintingPrefs); CFPreferencesAppSynchronize(kCUPSPrintingPrefs); # ifdef HAVE_NOTIFY_POST notify_post("com.apple.printerPrefsChange"); # endif /* HAVE_NOTIFY_POST */ } /* * '_cupsAppleSetDefaultPrinter()' - Set the default printer for this location. */ void _cupsAppleSetDefaultPrinter( CFStringRef name) /* I - Default printer/class name */ { # if _CUPS_LOCATION_DEFAULTS CFStringRef network; /* Current network */ CFArrayRef locations; /* Old locations array */ CFIndex locindex; /* Index in locations array */ CFStringRef locprinter; /* Current printer */ CFMutableArrayRef newlocations; /* New locations array */ CFMutableDictionaryRef newlocation; /* New location */ /* * Get the current location... */ if ((network = appleCopyNetwork()) == NULL) { DEBUG_puts("1_cupsAppleSetDefaultPrinter: Unable to get current network..."); return; } /* * Lookup the network in the preferences... */ if ((locations = appleCopyLocations()) != NULL) locprinter = appleGetPrinter(locations, network, &locindex); else { locprinter = NULL; locindex = -1; } if (!locprinter || CFStringCompare(locprinter, name, 0) != kCFCompareEqualTo) { /* * Need to change the locations array... */ if (locations) { newlocations = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, locations); if (locprinter) CFArrayRemoveValueAtIndex(newlocations, locindex); } else newlocations = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); newlocation = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (newlocation && newlocations) { /* * Put the new location at the front of the array... */ CFDictionaryAddValue(newlocation, kLocationNetworkKey, network); CFDictionaryAddValue(newlocation, kLocationPrinterIDKey, name); CFArrayInsertValueAtIndex(newlocations, 0, newlocation); /* * Limit the number of locations to 10... */ while (CFArrayGetCount(newlocations) > 10) CFArrayRemoveValueAtIndex(newlocations, 10); /* * Push the changes out... */ CFPreferencesSetAppValue(kLastUsedPrintersKey, newlocations, kCUPSPrintingPrefs); CFPreferencesAppSynchronize(kCUPSPrintingPrefs); # ifdef HAVE_NOTIFY_POST notify_post("com.apple.printerPrefsChange"); # endif /* HAVE_NOTIFY_POST */ } if (newlocations) CFRelease(newlocations); if (newlocation) CFRelease(newlocation); } if (locations) CFRelease(locations); CFRelease(network); # else (void)name; # endif /* _CUPS_LOCATION_DEFAULTS */ } /* * '_cupsAppleSetUseLastPrinter()' - Set whether to use the last used printer. */ void _cupsAppleSetUseLastPrinter( int uselast) /* O - 1 to use last printer, 0 otherwise */ { CFPreferencesSetAppValue(kUseLastPrinter, uselast ? kCFBooleanTrue : kCFBooleanFalse, kCUPSPrintingPrefs); CFPreferencesAppSynchronize(kCUPSPrintingPrefs); # ifdef HAVE_NOTIFY_POST notify_post("com.apple.printerPrefsChange"); # endif /* HAVE_NOTIFY_POST */ } #endif /* __APPLE__ */ /* * 'cupsConnectDest()' - Open a conection to the destination. * * Connect to the destination, returning a new @code http_t@ connection object * and optionally the resource path to use for the destination. These calls * will block until a connection is made, the timeout expires, the integer * pointed to by "cancel" is non-zero, or the callback function (or block) * returns 0. The caller is responsible for calling @link httpClose@ on the * returned connection. * * Starting with CUPS 2.2.4, the caller can pass @code CUPS_DEST_FLAGS_DEVICE@ * for the "flags" argument to connect directly to the device associated with * the destination. Otherwise, the connection is made to the CUPS scheduler * associated with the destination. * * @since CUPS 1.6/macOS 10.8@ */ http_t * /* O - Connection to destination or @code NULL@ */ cupsConnectDest( cups_dest_t *dest, /* I - Destination */ unsigned flags, /* I - Connection flags */ int msec, /* I - Timeout in milliseconds */ int *cancel, /* I - Pointer to "cancel" variable */ char *resource, /* I - Resource buffer */ size_t resourcesize, /* I - Size of resource buffer */ cups_dest_cb_t cb, /* I - Callback function */ void *user_data) /* I - User data pointer */ { const char *uri; /* Printer URI */ char scheme[32], /* URI scheme */ userpass[256], /* Username and password (unused) */ hostname[256], /* Hostname */ tempresource[1024]; /* Temporary resource buffer */ int port; /* Port number */ char portstr[16]; /* Port number string */ http_encryption_t encryption; /* Encryption to use */ http_addrlist_t *addrlist; /* Address list for server */ http_t *http; /* Connection to server */ DEBUG_printf(("cupsConnectDest(dest=%p, flags=0x%x, msec=%d, cancel=%p(%d), resource=\"%s\", resourcesize=" CUPS_LLFMT ", cb=%p, user_data=%p)", (void *)dest, flags, msec, (void *)cancel, cancel ? *cancel : -1, resource, CUPS_LLCAST resourcesize, (void *)cb, user_data)); /* * Range check input... */ if (!dest) { if (resource) *resource = '\0'; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (NULL); } if (!resource || resourcesize < 1) { resource = tempresource; resourcesize = sizeof(tempresource); } /* * Grab the printer URI... */ if (flags & CUPS_DEST_FLAGS_DEVICE) { if ((uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL) { #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) if (strstr(uri, "._tcp")) uri = cups_dnssd_resolve(dest, uri, msec, cancel, cb, user_data); #endif /* HAVE_DNSSD || HAVE_AVAHI */ } } else if ((uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options)) == NULL) { if ((uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL) { #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) if (strstr(uri, "._tcp")) uri = cups_dnssd_resolve(dest, uri, msec, cancel, cb, user_data); #endif /* HAVE_DNSSD || HAVE_AVAHI */ } if (uri) uri = _cupsCreateDest(dest->name, cupsGetOption("printer-info", dest->num_options, dest->options), NULL, uri, tempresource, sizeof(tempresource)); if (uri) { dest->num_options = cupsAddOption("printer-uri-supported", uri, dest->num_options, &dest->options); uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options); } } if (!uri) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0); if (cb) (*cb)(user_data, CUPS_DEST_FLAGS_UNCONNECTED | CUPS_DEST_FLAGS_ERROR, dest); return (NULL); } if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, (int)resourcesize) < HTTP_URI_STATUS_OK) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad printer-uri."), 1); if (cb) (*cb)(user_data, CUPS_DEST_FLAGS_UNCONNECTED | CUPS_DEST_FLAGS_ERROR, dest); return (NULL); } /* * Lookup the address for the server... */ if (cb) (*cb)(user_data, CUPS_DEST_FLAGS_UNCONNECTED | CUPS_DEST_FLAGS_RESOLVING, dest); snprintf(portstr, sizeof(portstr), "%d", port); if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portstr)) == NULL) { if (cb) (*cb)(user_data, CUPS_DEST_FLAGS_UNCONNECTED | CUPS_DEST_FLAGS_ERROR, dest); return (NULL); } if (cancel && *cancel) { httpAddrFreeList(addrlist); if (cb) (*cb)(user_data, CUPS_DEST_FLAGS_UNCONNECTED | CUPS_DEST_FLAGS_CANCELED, dest); return (NULL); } /* * Create the HTTP object pointing to the server referenced by the URI... */ if (!strcmp(scheme, "ipps") || port == 443) encryption = HTTP_ENCRYPTION_ALWAYS; else encryption = HTTP_ENCRYPTION_IF_REQUESTED; http = httpConnect2(hostname, port, addrlist, AF_UNSPEC, encryption, 1, 0, NULL); httpAddrFreeList(addrlist); /* * Connect if requested... */ if (flags & CUPS_DEST_FLAGS_UNCONNECTED) { if (cb) (*cb)(user_data, CUPS_DEST_FLAGS_UNCONNECTED, dest); } else { if (cb) (*cb)(user_data, CUPS_DEST_FLAGS_UNCONNECTED | CUPS_DEST_FLAGS_CONNECTING, dest); if (!httpReconnect2(http, msec, cancel) && cb) { if (cancel && *cancel) (*cb)(user_data, CUPS_DEST_FLAGS_UNCONNECTED | CUPS_DEST_FLAGS_CONNECTING, dest); else (*cb)(user_data, CUPS_DEST_FLAGS_UNCONNECTED | CUPS_DEST_FLAGS_ERROR, dest); } else if (cb) (*cb)(user_data, CUPS_DEST_FLAGS_NONE, dest); } return (http); } #ifdef __BLOCKS__ /* * 'cupsConnectDestBlock()' - Open a connection to the destination. * * Connect to the destination, returning a new @code http_t@ connection object * and optionally the resource path to use for the destination. These calls * will block until a connection is made, the timeout expires, the integer * pointed to by "cancel" is non-zero, or the block returns 0. The caller is * responsible for calling @link httpClose@ on the returned connection. * * Starting with CUPS 2.2.4, the caller can pass @code CUPS_DEST_FLAGS_DEVICE@ * for the "flags" argument to connect directly to the device associated with * the destination. Otherwise, the connection is made to the CUPS scheduler * associated with the destination. * * @since CUPS 1.6/macOS 10.8@ @exclude all@ */ http_t * /* O - Connection to destination or @code NULL@ */ cupsConnectDestBlock( cups_dest_t *dest, /* I - Destination */ unsigned flags, /* I - Connection flags */ int msec, /* I - Timeout in milliseconds */ int *cancel, /* I - Pointer to "cancel" variable */ char *resource, /* I - Resource buffer */ size_t resourcesize, /* I - Size of resource buffer */ cups_dest_block_t block) /* I - Callback block */ { return (cupsConnectDest(dest, flags, msec, cancel, resource, resourcesize, (cups_dest_cb_t)cups_block_cb, (void *)block)); } #endif /* __BLOCKS__ */ /* * 'cupsCopyDest()' - Copy a destination. * * Make a copy of the destination to an array of destinations (or just a single * copy) - for use with the cupsEnumDests* functions. The caller is responsible * for calling cupsFreeDests() on the returned object(s). * * @since CUPS 1.6/macOS 10.8@ */ int /* O - New number of destinations */ cupsCopyDest(cups_dest_t *dest, /* I - Destination to copy */ int num_dests, /* I - Number of destinations */ cups_dest_t **dests) /* IO - Destination array */ { int i; /* Looping var */ cups_dest_t *new_dest; /* New destination pointer */ cups_option_t *new_option, /* Current destination option */ *option; /* Current parent option */ /* * Range check input... */ if (!dest || num_dests < 0 || !dests) return (num_dests); /* * See if the destination already exists... */ if ((new_dest = cupsGetDest(dest->name, dest->instance, num_dests, *dests)) != NULL) { /* * Protect against copying destination to itself... */ if (new_dest == dest) return (num_dests); /* * Otherwise, free the options... */ cupsFreeOptions(new_dest->num_options, new_dest->options); new_dest->num_options = 0; new_dest->options = NULL; } else new_dest = cups_add_dest(dest->name, dest->instance, &num_dests, dests); if (new_dest) { new_dest->is_default = dest->is_default; if ((new_dest->options = calloc(sizeof(cups_option_t), (size_t)dest->num_options)) == NULL) return (cupsRemoveDest(dest->name, dest->instance, num_dests, dests)); new_dest->num_options = dest->num_options; for (i = dest->num_options, option = dest->options, new_option = new_dest->options; i > 0; i --, option ++, new_option ++) { new_option->name = _cupsStrRetain(option->name); new_option->value = _cupsStrRetain(option->value); } } return (num_dests); } /* * '_cupsCreateDest()' - Create a local (temporary) queue. */ char * /* O - Printer URI or @code NULL@ on error */ _cupsCreateDest(const char *name, /* I - Printer name */ const char *info, /* I - Printer description of @code NULL@ */ const char *device_id, /* I - 1284 Device ID or @code NULL@ */ const char *device_uri, /* I - Device URI */ char *uri, /* I - Printer URI buffer */ size_t urisize) /* I - Size of URI buffer */ { http_t *http; /* Connection to server */ ipp_t *request, /* CUPS-Create-Local-Printer request */ *response; /* CUPS-Create-Local-Printer response */ ipp_attribute_t *attr; /* printer-uri-supported attribute */ ipp_pstate_t state = IPP_PSTATE_STOPPED; /* printer-state value */ if (!name || !device_uri || !uri || urisize < 32) return (NULL); if ((http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL)) == NULL) return (NULL); request = ippNewRequest(IPP_OP_CUPS_CREATE_LOCAL_PRINTER); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, "ipp://localhost/"); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, device_uri); ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL, name); if (info) ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL, info); if (device_id) ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-device-id", NULL, device_id); response = cupsDoRequest(http, request, "/"); if ((attr = ippFindAttribute(response, "printer-uri-supported", IPP_TAG_URI)) != NULL) strlcpy(uri, ippGetString(attr, 0, NULL), urisize); else { ippDelete(response); httpClose(http); return (NULL); } if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) state = (ipp_pstate_t)ippGetInteger(attr, 0); while (state == IPP_PSTATE_STOPPED && cupsLastError() == IPP_STATUS_OK) { sleep(1); ippDelete(response); request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", NULL, "printer-state"); response = cupsDoRequest(http, request, "/"); if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) state = (ipp_pstate_t)ippGetInteger(attr, 0); } ippDelete(response); httpClose(http); return (uri); } /* * 'cupsEnumDests()' - Enumerate available destinations with a callback function. * * Destinations are enumerated from one or more sources. The callback function * receives the @code user_data@ pointer and the destination pointer which can * be used as input to the @link cupsCopyDest@ function. The function must * return 1 to continue enumeration or 0 to stop. * * The @code type@ and @code mask@ arguments allow the caller to filter the * destinations that are enumerated. Passing 0 for both will enumerate all * printers. The constant @code CUPS_PRINTER_DISCOVERED@ is used to filter on * destinations that are available but have not yet been added locally. * * Enumeration happens on the current thread and does not return until all * destinations have been enumerated or the callback function returns 0. * * Note: The callback function will likely receive multiple updates for the same * destinations - it is up to the caller to suppress any duplicate destinations. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ cupsEnumDests( unsigned flags, /* I - Enumeration flags */ int msec, /* I - Timeout in milliseconds, -1 for indefinite */ int *cancel, /* I - Pointer to "cancel" variable */ cups_ptype_t type, /* I - Printer type bits */ cups_ptype_t mask, /* I - Mask for printer type bits */ cups_dest_cb_t cb, /* I - Callback function */ void *user_data) /* I - User data */ { return (cups_enum_dests(CUPS_HTTP_DEFAULT, flags, msec, cancel, type, mask, cb, user_data)); } # ifdef __BLOCKS__ /* * 'cupsEnumDestsBlock()' - Enumerate available destinations with a block. * * Destinations are enumerated from one or more sources. The block receives the * @code user_data@ pointer and the destination pointer which can be used as * input to the @link cupsCopyDest@ function. The block must return 1 to * continue enumeration or 0 to stop. * * The @code type@ and @code mask@ arguments allow the caller to filter the * destinations that are enumerated. Passing 0 for both will enumerate all * printers. The constant @code CUPS_PRINTER_DISCOVERED@ is used to filter on * destinations that are available but have not yet been added locally. * * Enumeration happens on the current thread and does not return until all * destinations have been enumerated or the block returns 0. * * Note: The block will likely receive multiple updates for the same * destinations - it is up to the caller to suppress any duplicate destinations. * * @since CUPS 1.6/macOS 10.8@ @exclude all@ */ int /* O - 1 on success, 0 on failure */ cupsEnumDestsBlock( unsigned flags, /* I - Enumeration flags */ int timeout, /* I - Timeout in milliseconds, 0 for indefinite */ int *cancel, /* I - Pointer to "cancel" variable */ cups_ptype_t type, /* I - Printer type bits */ cups_ptype_t mask, /* I - Mask for printer type bits */ cups_dest_block_t block) /* I - Block */ { return (cupsEnumDests(flags, timeout, cancel, type, mask, (cups_dest_cb_t)cups_block_cb, (void *)block)); } # endif /* __BLOCKS__ */ /* * 'cupsFreeDests()' - Free the memory used by the list of destinations. */ void cupsFreeDests(int num_dests, /* I - Number of destinations */ cups_dest_t *dests) /* I - Destinations */ { int i; /* Looping var */ cups_dest_t *dest; /* Current destination */ if (num_dests == 0 || dests == NULL) return; for (i = num_dests, dest = dests; i > 0; i --, dest ++) { _cupsStrFree(dest->name); _cupsStrFree(dest->instance); cupsFreeOptions(dest->num_options, dest->options); } free(dests); } /* * 'cupsGetDest()' - Get the named destination from the list. * * Use the @link cupsEnumDests@ or @link cupsGetDests2@ functions to get a * list of supported destinations for the current user. */ cups_dest_t * /* O - Destination pointer or @code NULL@ */ cupsGetDest(const char *name, /* I - Destination name or @code NULL@ for the default destination */ const char *instance, /* I - Instance name or @code NULL@ */ int num_dests, /* I - Number of destinations */ cups_dest_t *dests) /* I - Destinations */ { int diff, /* Result of comparison */ match; /* Matching index */ if (num_dests <= 0 || !dests) return (NULL); if (!name) { /* * NULL name for default printer. */ while (num_dests > 0) { if (dests->is_default) return (dests); num_dests --; dests ++; } } else { /* * Lookup name and optionally the instance... */ match = cups_find_dest(name, instance, num_dests, dests, -1, &diff); if (!diff) return (dests + match); } return (NULL); } /* * '_cupsGetDestResource()' - Get the resource path and URI for a destination. */ const char * /* O - URI */ _cupsGetDestResource( cups_dest_t *dest, /* I - Destination */ unsigned flags, /* I - Destination flags */ char *resource, /* I - Resource buffer */ size_t resourcesize) /* I - Size of resource buffer */ { const char *uri, /* URI */ *device_uri, /* Device URI */ *printer_uri; /* Printer URI */ char scheme[32], /* URI scheme */ userpass[256], /* Username and password (unused) */ hostname[256]; /* Hostname */ int port; /* Port number */ DEBUG_printf(("_cupsGetDestResource(dest=%p(%s), flags=%u, resource=%p, resourcesize=%d)", (void *)dest, dest->name, flags, (void *)resource, (int)resourcesize)); /* * Range check input... */ if (!dest || !resource || resourcesize < 1) { if (resource) *resource = '\0'; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (NULL); } /* * Grab the printer and device URIs... */ device_uri = cupsGetOption("device-uri", dest->num_options, dest->options); printer_uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options); DEBUG_printf(("1_cupsGetDestResource: device-uri=\"%s\", printer-uri-supported=\"%s\".", device_uri, printer_uri)); #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) if (((flags & CUPS_DEST_FLAGS_DEVICE) || !printer_uri) && strstr(device_uri, "._tcp")) { if ((device_uri = cups_dnssd_resolve(dest, device_uri, 5000, NULL, NULL, NULL)) != NULL) { DEBUG_printf(("1_cupsGetDestResource: Resolved device-uri=\"%s\".", device_uri)); } else { DEBUG_puts("1_cupsGetDestResource: Unable to resolve device."); if (resource) *resource = '\0'; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0); return (NULL); } } #endif /* HAVE_DNSSD || HAVE_AVAHI */ if (flags & CUPS_DEST_FLAGS_DEVICE) { uri = device_uri; } else if (printer_uri) { uri = printer_uri; } else { uri = _cupsCreateDest(dest->name, cupsGetOption("printer-info", dest->num_options, dest->options), NULL, device_uri, resource, resourcesize); if (uri) { DEBUG_printf(("1_cupsGetDestResource: Local printer-uri-supported=\"%s\"", uri)); dest->num_options = cupsAddOption("printer-uri-supported", uri, dest->num_options, &dest->options); uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options); } } if (!uri) { DEBUG_puts("1_cupsGetDestResource: No printer-uri-supported or device-uri found."); if (resource) *resource = '\0'; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0); return (NULL); } else if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, (int)resourcesize) < HTTP_URI_STATUS_OK) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad URI."), 1); return (NULL); } DEBUG_printf(("1_cupsGetDestResource: resource=\"%s\"", resource)); return (uri); } /* * 'cupsGetDestWithURI()' - Get a destination associated with a URI. * * "name" is the desired name for the printer. If @code NULL@, a name will be * created using the URI. * * "uri" is the "ipp" or "ipps" URI for the printer. * * @since CUPS 2.0/macOS 10.10@ */ cups_dest_t * /* O - Destination or @code NULL@ */ cupsGetDestWithURI(const char *name, /* I - Desired printer name or @code NULL@ */ const char *uri) /* I - URI for the printer */ { cups_dest_t *dest; /* New destination */ char temp[1024], /* Temporary string */ scheme[256], /* Scheme from URI */ userpass[256], /* Username:password from URI */ hostname[256], /* Hostname from URI */ resource[1024], /* Resource path from URI */ *ptr; /* Pointer into string */ const char *info; /* printer-info string */ int port; /* Port number from URI */ /* * Range check input... */ if (!uri) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (NULL); } if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK || (strncmp(uri, "ipp://", 6) && strncmp(uri, "ipps://", 7))) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad printer-uri."), 1); return (NULL); } if (name) { info = name; } else { /* * Create the name from the URI... */ if (strstr(hostname, "._tcp")) { /* * Use the service instance name... */ if ((ptr = strstr(hostname, "._")) != NULL) *ptr = '\0'; cups_queue_name(temp, hostname, sizeof(temp)); name = temp; info = hostname; } else if (!strncmp(resource, "/classes/", 9)) { snprintf(temp, sizeof(temp), "%s @ %s", resource + 9, hostname); name = resource + 9; info = temp; } else if (!strncmp(resource, "/printers/", 10)) { snprintf(temp, sizeof(temp), "%s @ %s", resource + 10, hostname); name = resource + 10; info = temp; } else { name = hostname; info = hostname; } } /* * Create the destination... */ if ((dest = calloc(1, sizeof(cups_dest_t))) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); return (NULL); } dest->name = _cupsStrAlloc(name); dest->num_options = cupsAddOption("device-uri", uri, dest->num_options, &(dest->options)); dest->num_options = cupsAddOption("printer-info", info, dest->num_options, &(dest->options)); return (dest); } /* * '_cupsGetDests()' - Get destinations from a server. * * "op" is IPP_OP_CUPS_GET_PRINTERS to get a full list, IPP_OP_CUPS_GET_DEFAULT * to get the system-wide default printer, or IPP_OP_GET_PRINTER_ATTRIBUTES for * a known printer. * * "name" is the name of an existing printer and is only used when "op" is * IPP_OP_GET_PRINTER_ATTRIBUTES. * * "dest" is initialized to point to the array of destinations. * * 0 is returned if there are no printers, no default printer, or the named * printer does not exist, respectively. * * Free the memory used by the destination array using the @link cupsFreeDests@ * function. * * Note: On macOS this function also gets the default paper from the system * preferences (~/L/P/org.cups.PrintingPrefs.plist) and includes it in the * options array for each destination that supports it. */ int /* O - Number of destinations */ _cupsGetDests(http_t *http, /* I - Connection to server or * @code CUPS_HTTP_DEFAULT@ */ ipp_op_t op, /* I - IPP operation */ const char *name, /* I - Name of destination */ cups_dest_t **dests, /* IO - Destinations */ cups_ptype_t type, /* I - Printer type bits */ cups_ptype_t mask) /* I - Printer type mask */ { int num_dests = 0; /* Number of destinations */ cups_dest_t *dest; /* Current destination */ ipp_t *request, /* IPP Request */ *response; /* IPP Response */ ipp_attribute_t *attr; /* Current attribute */ const char *printer_name; /* printer-name attribute */ char uri[1024]; /* printer-uri value */ int num_options; /* Number of options */ cups_option_t *options; /* Options */ #ifdef __APPLE__ char media_default[41]; /* Default paper size */ #endif /* __APPLE__ */ char optname[1024], /* Option name */ value[2048], /* Option value */ *ptr; /* Pointer into name/value */ static const char * const pattrs[] = /* Attributes we're interested in */ { "auth-info-required", "device-uri", "job-sheets-default", "marker-change-time", "marker-colors", "marker-high-levels", "marker-levels", "marker-low-levels", "marker-message", "marker-names", "marker-types", #ifdef __APPLE__ "media-supported", #endif /* __APPLE__ */ "printer-commands", "printer-defaults", "printer-info", "printer-is-accepting-jobs", "printer-is-shared", "printer-is-temporary", "printer-location", "printer-make-and-model", "printer-mandatory-job-attributes", "printer-name", "printer-state", "printer-state-change-time", "printer-state-reasons", "printer-type", "printer-uri-supported" }; DEBUG_printf(("_cupsGetDests(http=%p, op=%x(%s), name=\"%s\", dests=%p, type=%x, mask=%x)", (void *)http, op, ippOpString(op), name, (void *)dests, type, mask)); #ifdef __APPLE__ /* * Get the default paper size... */ appleGetPaperSize(media_default, sizeof(media_default)); DEBUG_printf(("1_cupsGetDests: Default media is '%s'.", media_default)); #endif /* __APPLE__ */ /* * Build a IPP_OP_CUPS_GET_PRINTERS or IPP_OP_GET_PRINTER_ATTRIBUTES request, which * require the following attributes: * * attributes-charset * attributes-natural-language * requesting-user-name * printer-uri [for IPP_OP_GET_PRINTER_ATTRIBUTES] */ request = ippNewRequest(op); ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]), NULL, pattrs); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); if (name && op != IPP_OP_CUPS_GET_DEFAULT) { httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, "localhost", ippPort(), "/printers/%s", name); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); } else if (mask) { ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type", (int)type); ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask", (int)mask); } /* * Do the request and get back a response... */ if ((response = cupsDoRequest(http, request, "/")) != NULL) { for (attr = response->attrs; attr != NULL; attr = attr->next) { /* * Skip leading attributes until we hit a printer... */ while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) attr = attr->next; if (attr == NULL) break; /* * Pull the needed attributes from this printer... */ printer_name = NULL; num_options = 0; options = NULL; for (; attr && attr->group_tag == IPP_TAG_PRINTER; attr = attr->next) { if (attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM && attr->value_tag != IPP_TAG_BOOLEAN && attr->value_tag != IPP_TAG_TEXT && attr->value_tag != IPP_TAG_TEXTLANG && attr->value_tag != IPP_TAG_NAME && attr->value_tag != IPP_TAG_NAMELANG && attr->value_tag != IPP_TAG_KEYWORD && attr->value_tag != IPP_TAG_RANGE && attr->value_tag != IPP_TAG_URI) continue; if (!strcmp(attr->name, "auth-info-required") || !strcmp(attr->name, "device-uri") || !strcmp(attr->name, "marker-change-time") || !strcmp(attr->name, "marker-colors") || !strcmp(attr->name, "marker-high-levels") || !strcmp(attr->name, "marker-levels") || !strcmp(attr->name, "marker-low-levels") || !strcmp(attr->name, "marker-message") || !strcmp(attr->name, "marker-names") || !strcmp(attr->name, "marker-types") || !strcmp(attr->name, "printer-commands") || !strcmp(attr->name, "printer-info") || !strcmp(attr->name, "printer-is-shared") || !strcmp(attr->name, "printer-is-temporary") || !strcmp(attr->name, "printer-make-and-model") || !strcmp(attr->name, "printer-mandatory-job-attributes") || !strcmp(attr->name, "printer-state") || !strcmp(attr->name, "printer-state-change-time") || !strcmp(attr->name, "printer-type") || !strcmp(attr->name, "printer-is-accepting-jobs") || !strcmp(attr->name, "printer-location") || !strcmp(attr->name, "printer-state-reasons") || !strcmp(attr->name, "printer-uri-supported")) { /* * Add a printer description attribute... */ num_options = cupsAddOption(attr->name, cups_make_string(attr, value, sizeof(value)), num_options, &options); } #ifdef __APPLE__ else if (!strcmp(attr->name, "media-supported") && media_default[0]) { /* * See if we can set a default media size... */ int i; /* Looping var */ for (i = 0; i < attr->num_values; i ++) if (!_cups_strcasecmp(media_default, attr->values[i].string.text)) { DEBUG_printf(("1_cupsGetDests: Setting media to '%s'.", media_default)); num_options = cupsAddOption("media", media_default, num_options, &options); break; } } #endif /* __APPLE__ */ else if (!strcmp(attr->name, "printer-name") && attr->value_tag == IPP_TAG_NAME) printer_name = attr->values[0].string.text; else if (strncmp(attr->name, "notify-", 7) && strncmp(attr->name, "print-quality-", 14) && (attr->value_tag == IPP_TAG_BOOLEAN || attr->value_tag == IPP_TAG_ENUM || attr->value_tag == IPP_TAG_INTEGER || attr->value_tag == IPP_TAG_KEYWORD || attr->value_tag == IPP_TAG_NAME || attr->value_tag == IPP_TAG_RANGE) && (ptr = strstr(attr->name, "-default")) != NULL) { /* * Add a default option... */ strlcpy(optname, attr->name, sizeof(optname)); optname[ptr - attr->name] = '\0'; if (_cups_strcasecmp(optname, "media") || !cupsGetOption("media", num_options, options)) num_options = cupsAddOption(optname, cups_make_string(attr, value, sizeof(value)), num_options, &options); } } /* * See if we have everything needed... */ if (!printer_name) { cupsFreeOptions(num_options, options); if (attr == NULL) break; else continue; } if ((dest = cups_add_dest(printer_name, NULL, &num_dests, dests)) != NULL) { dest->num_options = num_options; dest->options = options; } else cupsFreeOptions(num_options, options); if (attr == NULL) break; } ippDelete(response); } /* * Return the count... */ return (num_dests); } /* * 'cupsGetDests()' - Get the list of destinations from the default server. * * Starting with CUPS 1.2, the returned list of destinations include the * "printer-info", "printer-is-accepting-jobs", "printer-is-shared", * "printer-make-and-model", "printer-state", "printer-state-change-time", * "printer-state-reasons", "printer-type", and "printer-uri-supported" * attributes as options. * * CUPS 1.4 adds the "marker-change-time", "marker-colors", * "marker-high-levels", "marker-levels", "marker-low-levels", "marker-message", * "marker-names", "marker-types", and "printer-commands" attributes as options. * * CUPS 2.2 adds accessible IPP printers to the list of destinations that can * be used. The "printer-uri-supported" option will be present for those IPP * printers that have been recently used. * * Use the @link cupsFreeDests@ function to free the destination list and * the @link cupsGetDest@ function to find a particular destination. * * @exclude all@ */ int /* O - Number of destinations */ cupsGetDests(cups_dest_t **dests) /* O - Destinations */ { return (cupsGetDests2(CUPS_HTTP_DEFAULT, dests)); } /* * 'cupsGetDests2()' - Get the list of destinations from the specified server. * * Starting with CUPS 1.2, the returned list of destinations include the * "printer-info", "printer-is-accepting-jobs", "printer-is-shared", * "printer-make-and-model", "printer-state", "printer-state-change-time", * "printer-state-reasons", "printer-type", and "printer-uri-supported" * attributes as options. * * CUPS 1.4 adds the "marker-change-time", "marker-colors", * "marker-high-levels", "marker-levels", "marker-low-levels", "marker-message", * "marker-names", "marker-types", and "printer-commands" attributes as options. * * CUPS 2.2 adds accessible IPP printers to the list of destinations that can * be used. The "printer-uri-supported" option will be present for those IPP * printers that have been recently used. * * Use the @link cupsFreeDests@ function to free the destination list and * the @link cupsGetDest@ function to find a particular destination. * * @since CUPS 1.1.21/macOS 10.4@ */ int /* O - Number of destinations */ cupsGetDests2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ cups_dest_t **dests) /* O - Destinations */ { _cups_getdata_t data; /* Enumeration data */ DEBUG_printf(("cupsGetDests2(http=%p, dests=%p)", (void *)http, (void *)dests)); /* * Range check the input... */ if (!dests) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad NULL dests pointer"), 1); DEBUG_puts("1cupsGetDests2: NULL dests pointer, returning 0."); return (0); } /* * Connect to the server as needed... */ if (!http) { if ((http = _cupsConnect()) == NULL) { *dests = NULL; return (0); } } /* * Grab the printers and classes... */ data.num_dests = 0; data.dests = NULL; if (!httpAddrLocalhost(httpGetAddress(http))) { /* * When talking to a remote cupsd, just enumerate printers on the remote * cupsd. */ cups_enum_dests(http, 0, _CUPS_DNSSD_GET_DESTS, NULL, 0, CUPS_PRINTER_DISCOVERED, (cups_dest_cb_t)cups_get_cb, &data); } else { /* * When talking to a local cupsd, enumerate both local printers and ones we * can find on the network... */ cups_enum_dests(http, 0, _CUPS_DNSSD_GET_DESTS, NULL, 0, 0, (cups_dest_cb_t)cups_get_cb, &data); } /* * Return the number of destinations... */ *dests = data.dests; if (data.num_dests > 0) _cupsSetError(IPP_STATUS_OK, NULL, 0); DEBUG_printf(("1cupsGetDests2: Returning %d destinations.", data.num_dests)); return (data.num_dests); } /* * 'cupsGetNamedDest()' - Get options for the named destination. * * This function is optimized for retrieving a single destination and should * be used instead of @link cupsGetDests2@ and @link cupsGetDest@ when you * either know the name of the destination or want to print to the default * destination. If @code NULL@ is returned, the destination does not exist or * there is no default destination. * * If "http" is @code CUPS_HTTP_DEFAULT@, the connection to the default print * server will be used. * * If "name" is @code NULL@, the default printer for the current user will be * returned. * * The returned destination must be freed using @link cupsFreeDests@ with a * "num_dests" value of 1. * * @since CUPS 1.4/macOS 10.6@ */ cups_dest_t * /* O - Destination or @code NULL@ */ cupsGetNamedDest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *name, /* I - Destination name or @code NULL@ for the default destination */ const char *instance) /* I - Instance name or @code NULL@ */ { const char *dest_name; /* Working destination name */ cups_dest_t *dest; /* Destination */ char filename[1024], /* Path to lpoptions */ defname[256]; /* Default printer name */ const char *home = getenv("HOME"); /* Home directory */ int set_as_default = 0; /* Set returned destination as default */ ipp_op_t op = IPP_OP_GET_PRINTER_ATTRIBUTES; /* IPP operation to get server ops */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ DEBUG_printf(("cupsGetNamedDest(http=%p, name=\"%s\", instance=\"%s\")", (void *)http, name, instance)); /* * If "name" is NULL, find the default destination... */ dest_name = name; if (!dest_name) { set_as_default = 1; dest_name = _cupsUserDefault(defname, sizeof(defname)); if (dest_name) { char *ptr; /* Temporary pointer... */ if ((ptr = strchr(defname, '/')) != NULL) { *ptr++ = '\0'; instance = ptr; } else instance = NULL; } else if (home) { /* * No default in the environment, try the user's lpoptions files... */ snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home); dest_name = cups_get_default(filename, defname, sizeof(defname), &instance); if (dest_name) set_as_default = 2; } if (!dest_name) { /* * Still not there? Try the system lpoptions file... */ snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot); dest_name = cups_get_default(filename, defname, sizeof(defname), &instance); if (dest_name) set_as_default = 3; } if (!dest_name) { /* * No locally-set default destination, ask the server... */ op = IPP_OP_CUPS_GET_DEFAULT; set_as_default = 4; DEBUG_puts("1cupsGetNamedDest: Asking server for default printer..."); } else DEBUG_printf(("1cupsGetNamedDest: Using name=\"%s\"...", name)); } /* * Get the printer's attributes... */ if (!_cupsGetDests(http, op, dest_name, &dest, 0, 0)) { if (name) { _cups_namedata_t data; /* Callback data */ DEBUG_puts("1cupsGetNamedDest: No queue found for printer, looking on network..."); data.name = name; data.dest = NULL; cupsEnumDests(0, 1000, NULL, 0, 0, (cups_dest_cb_t)cups_name_cb, &data); if (!data.dest) return (NULL); dest = data.dest; } else { switch (set_as_default) { default : break; case 1 : /* Set from env vars */ if (getenv("LPDEST")) _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, _("LPDEST environment variable names default destination that does not exist."), 1); else if (getenv("PRINTER")) _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, _("PRINTER environment variable names default destination that does not exist."), 1); else _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, _("No default destination."), 1); break; case 2 : /* Set from ~/.cups/lpoptions */ _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, _("~/.cups/lpoptions file names default destination that does not exist."), 1); break; case 3 : /* Set from /etc/cups/lpoptions */ _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, _("/etc/cups/lpoptions file names default destination that does not exist."), 1); break; case 4 : /* Set from server */ _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, _("No default destination."), 1); break; } return (NULL); } } DEBUG_printf(("1cupsGetNamedDest: Got dest=%p", (void *)dest)); if (instance) dest->instance = _cupsStrAlloc(instance); if (set_as_default) dest->is_default = 1; /* * Then add local options... */ snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot); cups_get_dests(filename, dest_name, instance, 0, 1, 1, &dest); if (home) { snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home); cups_get_dests(filename, dest_name, instance, 0, 1, 1, &dest); } /* * Return the result... */ return (dest); } /* * 'cupsRemoveDest()' - Remove a destination from the destination list. * * Removing a destination/instance does not delete the class or printer * queue, merely the lpoptions for that destination/instance. Use the * @link cupsSetDests@ or @link cupsSetDests2@ functions to save the new * options for the user. * * @since CUPS 1.3/macOS 10.5@ */ int /* O - New number of destinations */ cupsRemoveDest(const char *name, /* I - Destination name */ const char *instance, /* I - Instance name or @code NULL@ */ int num_dests, /* I - Number of destinations */ cups_dest_t **dests) /* IO - Destinations */ { int i; /* Index into destinations */ cups_dest_t *dest; /* Pointer to destination */ /* * Find the destination... */ if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL) return (num_dests); /* * Free memory... */ _cupsStrFree(dest->name); _cupsStrFree(dest->instance); cupsFreeOptions(dest->num_options, dest->options); /* * Remove the destination from the array... */ num_dests --; i = (int)(dest - *dests); if (i < num_dests) memmove(dest, dest + 1, (size_t)(num_dests - i) * sizeof(cups_dest_t)); return (num_dests); } /* * 'cupsSetDefaultDest()' - Set the default destination. * * @since CUPS 1.3/macOS 10.5@ */ void cupsSetDefaultDest( const char *name, /* I - Destination name */ const char *instance, /* I - Instance name or @code NULL@ */ int num_dests, /* I - Number of destinations */ cups_dest_t *dests) /* I - Destinations */ { int i; /* Looping var */ cups_dest_t *dest; /* Current destination */ /* * Range check input... */ if (!name || num_dests <= 0 || !dests) return; /* * Loop through the array and set the "is_default" flag for the matching * destination... */ for (i = num_dests, dest = dests; i > 0; i --, dest ++) dest->is_default = !_cups_strcasecmp(name, dest->name) && ((!instance && !dest->instance) || (instance && dest->instance && !_cups_strcasecmp(instance, dest->instance))); } /* * 'cupsSetDests()' - Save the list of destinations for the default server. * * This function saves the destinations to /etc/cups/lpoptions when run * as root and ~/.cups/lpoptions when run as a normal user. * * @exclude all@ */ void cupsSetDests(int num_dests, /* I - Number of destinations */ cups_dest_t *dests) /* I - Destinations */ { cupsSetDests2(CUPS_HTTP_DEFAULT, num_dests, dests); } /* * 'cupsSetDests2()' - Save the list of destinations for the specified server. * * This function saves the destinations to /etc/cups/lpoptions when run * as root and ~/.cups/lpoptions when run as a normal user. * * @since CUPS 1.1.21/macOS 10.4@ */ int /* O - 0 on success, -1 on error */ cupsSetDests2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ int num_dests, /* I - Number of destinations */ cups_dest_t *dests) /* I - Destinations */ { int i, j; /* Looping vars */ int wrote; /* Wrote definition? */ cups_dest_t *dest; /* Current destination */ cups_option_t *option; /* Current option */ _ipp_option_t *match; /* Matching attribute for option */ FILE *fp; /* File pointer */ #ifndef WIN32 const char *home; /* HOME environment variable */ #endif /* WIN32 */ char filename[1024]; /* lpoptions file */ int num_temps; /* Number of temporary destinations */ cups_dest_t *temps = NULL, /* Temporary destinations */ *temp; /* Current temporary dest */ const char *val; /* Value of temporary option */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ /* * Range check the input... */ if (!num_dests || !dests) return (-1); /* * Get the server destinations... */ num_temps = _cupsGetDests(http, IPP_OP_CUPS_GET_PRINTERS, NULL, &temps, 0, 0); if (cupsLastError() >= IPP_STATUS_REDIRECTION_OTHER_SITE) { cupsFreeDests(num_temps, temps); return (-1); } /* * Figure out which file to write to... */ snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot); #ifndef WIN32 if (getuid()) { /* * Point to user defaults... */ if ((home = getenv("HOME")) != NULL) { /* * Create ~/.cups subdirectory... */ snprintf(filename, sizeof(filename), "%s/.cups", home); if (access(filename, 0)) mkdir(filename, 0700); snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home); } } #endif /* !WIN32 */ /* * Try to open the file... */ if ((fp = fopen(filename, "w")) == NULL) { cupsFreeDests(num_temps, temps); return (-1); } #ifndef WIN32 /* * Set the permissions to 0644 when saving to the /etc/cups/lpoptions * file... */ if (!getuid()) fchmod(fileno(fp), 0644); #endif /* !WIN32 */ /* * Write each printer; each line looks like: * * Dest name[/instance] options * Default name[/instance] options */ for (i = num_dests, dest = dests; i > 0; i --, dest ++) if (dest->instance != NULL || dest->num_options != 0 || dest->is_default) { if (dest->is_default) { fprintf(fp, "Default %s", dest->name); if (dest->instance) fprintf(fp, "/%s", dest->instance); wrote = 1; } else wrote = 0; temp = cupsGetDest(dest->name, NULL, num_temps, temps); for (j = dest->num_options, option = dest->options; j > 0; j --, option ++) { /* * See if this option is a printer attribute; if so, skip it... */ if ((match = _ippFindOption(option->name)) != NULL && match->group_tag == IPP_TAG_PRINTER) continue; /* * See if the server options match these; if so, don't write 'em. */ if (temp && (val = cupsGetOption(option->name, temp->num_options, temp->options)) != NULL && !_cups_strcasecmp(val, option->value)) continue; /* * Options don't match, write to the file... */ if (!wrote) { fprintf(fp, "Dest %s", dest->name); if (dest->instance) fprintf(fp, "/%s", dest->instance); wrote = 1; } if (option->value[0]) { if (strchr(option->value, ' ') || strchr(option->value, '\\') || strchr(option->value, '\"') || strchr(option->value, '\'')) { /* * Quote the value... */ fprintf(fp, " %s=\"", option->name); for (val = option->value; *val; val ++) { if (strchr("\"\'\\", *val)) putc('\\', fp); putc(*val, fp); } putc('\"', fp); } else { /* * Store the literal value... */ fprintf(fp, " %s=%s", option->name, option->value); } } else fprintf(fp, " %s", option->name); } if (wrote) fputs("\n", fp); } /* * Free the temporary destinations and close the file... */ cupsFreeDests(num_temps, temps); fclose(fp); #ifdef __APPLE__ /* * Set the default printer for this location - this allows command-line * and GUI applications to share the same default destination... */ if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL) { CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, dest->name, kCFStringEncodingUTF8); /* Default printer name */ if (name) { _cupsAppleSetDefaultPrinter(name); CFRelease(name); } } #endif /* __APPLE__ */ #ifdef HAVE_NOTIFY_POST /* * Send a notification so that macOS applications can know about the * change, too. */ notify_post("com.apple.printerListChange"); #endif /* HAVE_NOTIFY_POST */ return (0); } /* * '_cupsUserDefault()' - Get the user default printer from environment * variables and location information. */ char * /* O - Default printer or NULL */ _cupsUserDefault(char *name, /* I - Name buffer */ size_t namesize) /* I - Size of name buffer */ { const char *env; /* LPDEST or PRINTER env variable */ #ifdef __APPLE__ CFStringRef locprinter; /* Last printer as this location */ #endif /* __APPLE__ */ if ((env = getenv("LPDEST")) == NULL) if ((env = getenv("PRINTER")) != NULL && !strcmp(env, "lp")) env = NULL; if (env) { strlcpy(name, env, namesize); return (name); } #ifdef __APPLE__ /* * Use location-based defaults if "use last printer" is selected in the * system preferences... */ if ((locprinter = _cupsAppleCopyDefaultPrinter()) != NULL) { CFStringGetCString(locprinter, name, (CFIndex)namesize, kCFStringEncodingUTF8); CFRelease(locprinter); } else name[0] = '\0'; DEBUG_printf(("1_cupsUserDefault: Returning \"%s\".", name)); return (*name ? name : NULL); #else /* * No location-based defaults on this platform... */ name[0] = '\0'; return (NULL); #endif /* __APPLE__ */ } #if _CUPS_LOCATION_DEFAULTS /* * 'appleCopyLocations()' - Copy the location history array. */ static CFArrayRef /* O - Location array or NULL */ appleCopyLocations(void) { CFArrayRef locations; /* Location array */ /* * Look up the location array in the preferences... */ if ((locations = CFPreferencesCopyAppValue(kLastUsedPrintersKey, kCUPSPrintingPrefs)) == NULL) return (NULL); if (CFGetTypeID(locations) != CFArrayGetTypeID()) { CFRelease(locations); return (NULL); } return (locations); } /* * 'appleCopyNetwork()' - Get the network ID for the current location. */ static CFStringRef /* O - Network ID */ appleCopyNetwork(void) { SCDynamicStoreRef dynamicStore; /* System configuration data */ CFStringRef key; /* Current network configuration key */ CFDictionaryRef ip_dict; /* Network configuration data */ CFStringRef network = NULL; /* Current network ID */ if ((dynamicStore = SCDynamicStoreCreate(NULL, CFSTR("libcups"), NULL, NULL)) != NULL) { /* * First use the IPv6 router address, if available, since that will generally * be a globally-unique link-local address. */ if ((key = SCDynamicStoreKeyCreateNetworkGlobalEntity( NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6)) != NULL) { if ((ip_dict = SCDynamicStoreCopyValue(dynamicStore, key)) != NULL) { if ((network = CFDictionaryGetValue(ip_dict, kSCPropNetIPv6Router)) != NULL) CFRetain(network); CFRelease(ip_dict); } CFRelease(key); } /* * If that doesn't work, try the IPv4 router address. This isn't as unique * and will likely be a 10.x.y.z or 192.168.y.z address... */ if (!network) { if ((key = SCDynamicStoreKeyCreateNetworkGlobalEntity( NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4)) != NULL) { if ((ip_dict = SCDynamicStoreCopyValue(dynamicStore, key)) != NULL) { if ((network = CFDictionaryGetValue(ip_dict, kSCPropNetIPv4Router)) != NULL) CFRetain(network); CFRelease(ip_dict); } CFRelease(key); } } CFRelease(dynamicStore); } return (network); } #endif /* _CUPS_LOCATION_DEFAULTS */ #ifdef __APPLE__ /* * 'appleGetPaperSize()' - Get the default paper size. */ static char * /* O - Default paper size */ appleGetPaperSize(char *name, /* I - Paper size name buffer */ size_t namesize) /* I - Size of buffer */ { CFStringRef defaultPaperID; /* Default paper ID */ pwg_media_t *pwgmedia; /* PWG media size */ defaultPaperID = _cupsAppleCopyDefaultPaperID(); if (!defaultPaperID || CFGetTypeID(defaultPaperID) != CFStringGetTypeID() || !CFStringGetCString(defaultPaperID, name, (CFIndex)namesize, kCFStringEncodingUTF8)) name[0] = '\0'; else if ((pwgmedia = pwgMediaForLegacy(name)) != NULL) strlcpy(name, pwgmedia->pwg, namesize); if (defaultPaperID) CFRelease(defaultPaperID); return (name); } #endif /* __APPLE__ */ #if _CUPS_LOCATION_DEFAULTS /* * 'appleGetPrinter()' - Get a printer from the history array. */ static CFStringRef /* O - Printer name or NULL */ appleGetPrinter(CFArrayRef locations, /* I - Location array */ CFStringRef network, /* I - Network name */ CFIndex *locindex) /* O - Index in array */ { CFIndex i, /* Looping var */ count; /* Number of locations */ CFDictionaryRef location; /* Current location */ CFStringRef locnetwork, /* Current network */ locprinter; /* Current printer */ for (i = 0, count = CFArrayGetCount(locations); i < count; i ++) if ((location = CFArrayGetValueAtIndex(locations, i)) != NULL && CFGetTypeID(location) == CFDictionaryGetTypeID()) { if ((locnetwork = CFDictionaryGetValue(location, kLocationNetworkKey)) != NULL && CFGetTypeID(locnetwork) == CFStringGetTypeID() && CFStringCompare(network, locnetwork, 0) == kCFCompareEqualTo && (locprinter = CFDictionaryGetValue(location, kLocationPrinterIDKey)) != NULL && CFGetTypeID(locprinter) == CFStringGetTypeID()) { if (locindex) *locindex = i; return (locprinter); } } return (NULL); } #endif /* _CUPS_LOCATION_DEFAULTS */ /* * 'cups_add_dest()' - Add a destination to the array. * * Unlike cupsAddDest(), this function does not check for duplicates. */ static cups_dest_t * /* O - New destination */ cups_add_dest(const char *name, /* I - Name of destination */ const char *instance, /* I - Instance or NULL */ int *num_dests, /* IO - Number of destinations */ cups_dest_t **dests) /* IO - Destinations */ { int insert, /* Insertion point */ diff; /* Result of comparison */ cups_dest_t *dest; /* Destination pointer */ /* * Add new destination... */ if (*num_dests == 0) dest = malloc(sizeof(cups_dest_t)); else dest = realloc(*dests, sizeof(cups_dest_t) * (size_t)(*num_dests + 1)); if (!dest) return (NULL); *dests = dest; /* * Find where to insert the destination... */ if (*num_dests == 0) insert = 0; else { insert = cups_find_dest(name, instance, *num_dests, *dests, *num_dests - 1, &diff); if (diff > 0) insert ++; } /* * Move the array elements as needed... */ if (insert < *num_dests) memmove(*dests + insert + 1, *dests + insert, (size_t)(*num_dests - insert) * sizeof(cups_dest_t)); (*num_dests) ++; /* * Initialize the destination... */ dest = *dests + insert; dest->name = _cupsStrAlloc(name); dest->instance = _cupsStrAlloc(instance); dest->is_default = 0; dest->num_options = 0; dest->options = (cups_option_t *)0; return (dest); } # ifdef __BLOCKS__ /* * 'cups_block_cb()' - Enumeration callback for block API. */ static int /* O - 1 to continue, 0 to stop */ cups_block_cb( cups_dest_block_t block, /* I - Block */ unsigned flags, /* I - Destination flags */ cups_dest_t *dest) /* I - Destination */ { return ((block)(flags, dest)); } # endif /* __BLOCKS__ */ /* * 'cups_compare_dests()' - Compare two destinations. */ static int /* O - Result of comparison */ cups_compare_dests(cups_dest_t *a, /* I - First destination */ cups_dest_t *b) /* I - Second destination */ { int diff; /* Difference */ if ((diff = _cups_strcasecmp(a->name, b->name)) != 0) return (diff); else if (a->instance && b->instance) return (_cups_strcasecmp(a->instance, b->instance)); else return ((a->instance && !b->instance) - (!a->instance && b->instance)); } #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) # ifdef HAVE_DNSSD /* * 'cups_dnssd_browse_cb()' - Browse for printers. */ static void cups_dnssd_browse_cb( DNSServiceRef sdRef, /* I - Service reference */ DNSServiceFlags flags, /* I - Option flags */ uint32_t interfaceIndex, /* I - Interface number */ DNSServiceErrorType errorCode, /* I - Error, if any */ const char *serviceName, /* I - Name of service/device */ const char *regtype, /* I - Type of service */ const char *replyDomain, /* I - Service domain */ void *context) /* I - Enumeration data */ { _cups_dnssd_data_t *data = (_cups_dnssd_data_t *)context; /* Enumeration data */ DEBUG_printf(("5cups_dnssd_browse_cb(sdRef=%p, flags=%x, interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", regtype=\"%s\", replyDomain=\"%s\", context=%p)", (void *)sdRef, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain, context)); /* * Don't do anything on error... */ if (errorCode != kDNSServiceErr_NoError) return; /* * Get the device... */ cups_dnssd_get_device(data, serviceName, regtype, replyDomain); } # else /* HAVE_AVAHI */ /* * 'cups_dnssd_browse_cb()' - Browse for printers. */ static void cups_dnssd_browse_cb( AvahiServiceBrowser *browser, /* I - Browser */ AvahiIfIndex interface, /* I - Interface index (unused) */ AvahiProtocol protocol, /* I - Network protocol (unused) */ AvahiBrowserEvent event, /* I - What happened */ const char *name, /* I - Service name */ const char *type, /* I - Registration type */ const char *domain, /* I - Domain */ AvahiLookupResultFlags flags, /* I - Flags */ void *context) /* I - Devices array */ { #ifdef DEBUG AvahiClient *client = avahi_service_browser_get_client(browser); /* Client information */ #endif /* DEBUG */ _cups_dnssd_data_t *data = (_cups_dnssd_data_t *)context; /* Enumeration data */ (void)interface; (void)protocol; (void)context; DEBUG_printf(("cups_dnssd_browse_cb(..., name=\"%s\", type=\"%s\", domain=\"%s\", ...);", name, type, domain)); switch (event) { case AVAHI_BROWSER_FAILURE: DEBUG_printf(("cups_dnssd_browse_cb: %s", avahi_strerror(avahi_client_errno(client)))); avahi_simple_poll_quit(data->simple_poll); break; case AVAHI_BROWSER_NEW: /* * This object is new on the network. */ cups_dnssd_get_device(data, name, type, domain); break; case AVAHI_BROWSER_REMOVE : case AVAHI_BROWSER_CACHE_EXHAUSTED : break; case AVAHI_BROWSER_ALL_FOR_NOW : DEBUG_puts("cups_dnssd_browse_cb: ALL_FOR_NOW"); data->browsers --; break; } } /* * 'cups_dnssd_client_cb()' - Avahi client callback function. */ static void cups_dnssd_client_cb( AvahiClient *client, /* I - Client information (unused) */ AvahiClientState state, /* I - Current state */ void *context) /* I - User data (unused) */ { _cups_dnssd_data_t *data = (_cups_dnssd_data_t *)context; /* Enumeration data */ (void)client; DEBUG_printf(("cups_dnssd_client_cb(client=%p, state=%d, context=%p)", client, state, context)); /* * If the connection drops, quit. */ if (state == AVAHI_CLIENT_FAILURE) { DEBUG_puts("cups_dnssd_client_cb: Avahi connection failed."); avahi_simple_poll_quit(data->simple_poll); } } # endif /* HAVE_DNSSD */ /* * 'cups_dnssd_compare_device()' - Compare two devices. */ static int /* O - Result of comparison */ cups_dnssd_compare_devices( _cups_dnssd_device_t *a, /* I - First device */ _cups_dnssd_device_t *b) /* I - Second device */ { return (strcmp(a->dest.name, b->dest.name)); } /* * 'cups_dnssd_free_device()' - Free the memory used by a device. */ static void cups_dnssd_free_device( _cups_dnssd_device_t *device, /* I - Device */ _cups_dnssd_data_t *data) /* I - Enumeration data */ { DEBUG_printf(("5cups_dnssd_free_device(device=%p(%s), data=%p)", (void *)device, device->dest.name, (void *)data)); # ifdef HAVE_DNSSD if (device->ref) DNSServiceRefDeallocate(device->ref); # else /* HAVE_AVAHI */ if (device->ref) avahi_record_browser_free(device->ref); # endif /* HAVE_DNSSD */ _cupsStrFree(device->domain); _cupsStrFree(device->fullName); _cupsStrFree(device->regtype); _cupsStrFree(device->dest.name); cupsFreeOptions(device->dest.num_options, device->dest.options); free(device); } /* * 'cups_dnssd_get_device()' - Lookup a device and create it as needed. */ static _cups_dnssd_device_t * /* O - Device */ cups_dnssd_get_device( _cups_dnssd_data_t *data, /* I - Enumeration data */ const char *serviceName, /* I - Service name */ const char *regtype, /* I - Registration type */ const char *replyDomain) /* I - Domain name */ { _cups_dnssd_device_t key, /* Search key */ *device; /* Device */ char fullName[kDNSServiceMaxDomainName], /* Full name for query */ name[128]; /* Queue name */ DEBUG_printf(("5cups_dnssd_get_device(data=%p, serviceName=\"%s\", regtype=\"%s\", replyDomain=\"%s\")", (void *)data, serviceName, regtype, replyDomain)); /* * See if this is an existing device... */ cups_queue_name(name, serviceName, sizeof(name)); key.dest.name = name; if ((device = cupsArrayFind(data->devices, &key)) != NULL) { /* * Yes, see if we need to do anything with this... */ int update = 0; /* Non-zero if we need to update */ if (!_cups_strcasecmp(replyDomain, "local.") && _cups_strcasecmp(device->domain, replyDomain)) { /* * Update the "global" listing to use the .local domain name instead. */ _cupsStrFree(device->domain); device->domain = _cupsStrAlloc(replyDomain); DEBUG_printf(("6cups_dnssd_get_device: Updating '%s' to use local " "domain.", device->dest.name)); update = 1; } if (!_cups_strcasecmp(regtype, "_ipps._tcp") && _cups_strcasecmp(device->regtype, regtype)) { /* * Prefer IPPS over IPP. */ _cupsStrFree(device->regtype); device->regtype = _cupsStrAlloc(regtype); DEBUG_printf(("6cups_dnssd_get_device: Updating '%s' to use IPPS.", device->dest.name)); update = 1; } if (!update) { DEBUG_printf(("6cups_dnssd_get_device: No changes to '%s'.", device->dest.name)); return (device); } } else { /* * No, add the device... */ DEBUG_printf(("6cups_dnssd_get_device: Adding '%s' for %s with domain " "'%s'.", serviceName, !strcmp(regtype, "_ipps._tcp") ? "IPPS" : "IPP", replyDomain)); device = calloc(sizeof(_cups_dnssd_device_t), 1); device->dest.name = _cupsStrAlloc(name); device->domain = _cupsStrAlloc(replyDomain); device->regtype = _cupsStrAlloc(regtype); device->dest.num_options = cupsAddOption("printer-info", serviceName, 0, &device->dest.options); cupsArrayAdd(data->devices, device); } /* * Set the "full name" of this service, which is used for queries... */ # ifdef HAVE_DNSSD DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain); # else /* HAVE_AVAHI */ avahi_service_name_join(fullName, kDNSServiceMaxDomainName, serviceName, regtype, replyDomain); # endif /* HAVE_DNSSD */ _cupsStrFree(device->fullName); device->fullName = _cupsStrAlloc(fullName); if (device->ref) { # ifdef HAVE_DNSSD DNSServiceRefDeallocate(device->ref); # else /* HAVE_AVAHI */ avahi_record_browser_free(device->ref); # endif /* HAVE_DNSSD */ device->ref = 0; } if (device->state == _CUPS_DNSSD_ACTIVE) { DEBUG_printf(("6cups_dnssd_get_device: Remove callback for \"%s\".", device->dest.name)); (*data->cb)(data->user_data, CUPS_DEST_FLAGS_REMOVED, &device->dest); device->state = _CUPS_DNSSD_NEW; } return (device); } # ifdef HAVE_AVAHI /* * 'cups_dnssd_poll_cb()' - Wait for input on the specified file descriptors. * * Note: This function is needed because avahi_simple_poll_iterate is broken * and always uses a timeout of 0 (!) milliseconds. * (https://github.com/lathiat/avahi/issues/127) * * @private@ */ static int /* O - Number of file descriptors matching */ cups_dnssd_poll_cb( struct pollfd *pollfds, /* I - File descriptors */ unsigned int num_pollfds, /* I - Number of file descriptors */ int timeout, /* I - Timeout in milliseconds (unused) */ void *context) /* I - User data (unused) */ { _cups_dnssd_data_t *data = (_cups_dnssd_data_t *)context; /* Enumeration data */ int val; /* Return value */ DEBUG_printf(("cups_dnssd_poll_cb(pollfds=%p, num_pollfds=%d, timeout=%d, context=%p)", pollfds, num_pollfds, timeout, context)); (void)timeout; val = poll(pollfds, num_pollfds, _CUPS_DNSSD_MAXTIME); DEBUG_printf(("cups_dnssd_poll_cb: poll() returned %d", val)); if (val < 0) { DEBUG_printf(("cups_dnssd_poll_cb: %s", strerror(errno))); } else if (val > 0) { data->got_data = 1; } return (val); } # endif /* HAVE_AVAHI */ /* * 'cups_dnssd_query_cb()' - Process query data. */ static void cups_dnssd_query_cb( # ifdef HAVE_DNSSD DNSServiceRef sdRef, /* I - Service reference */ DNSServiceFlags flags, /* I - Data flags */ uint32_t interfaceIndex, /* I - Interface */ DNSServiceErrorType errorCode, /* I - Error, if any */ const char *fullName, /* I - Full service name */ uint16_t rrtype, /* I - Record type */ uint16_t rrclass, /* I - Record class */ uint16_t rdlen, /* I - Length of record data */ const void *rdata, /* I - Record data */ uint32_t ttl, /* I - Time-to-live */ # else /* HAVE_AVAHI */ AvahiRecordBrowser *browser, /* I - Record browser */ AvahiIfIndex interfaceIndex, /* I - Interface index (unused) */ AvahiProtocol protocol, /* I - Network protocol (unused) */ AvahiBrowserEvent event, /* I - What happened? */ const char *fullName, /* I - Service name */ uint16_t rrclass, /* I - Record class */ uint16_t rrtype, /* I - Record type */ const void *rdata, /* I - TXT record */ size_t rdlen, /* I - Length of TXT record */ AvahiLookupResultFlags flags, /* I - Flags */ # endif /* HAVE_DNSSD */ void *context) /* I - Enumeration data */ { # if defined(DEBUG) && defined(HAVE_AVAHI) AvahiClient *client = avahi_record_browser_get_client(browser); /* Client information */ # endif /* DEBUG && HAVE_AVAHI */ _cups_dnssd_data_t *data = (_cups_dnssd_data_t *)context; /* Enumeration data */ char serviceName[256],/* Service name */ name[128], /* Queue name */ *ptr; /* Pointer into string */ _cups_dnssd_device_t dkey, /* Search key */ *device; /* Device */ # ifdef HAVE_DNSSD DEBUG_printf(("5cups_dnssd_query_cb(sdRef=%p, flags=%x, interfaceIndex=%d, errorCode=%d, fullName=\"%s\", rrtype=%u, rrclass=%u, rdlen=%u, rdata=%p, ttl=%u, context=%p)", (void *)sdRef, flags, interfaceIndex, errorCode, fullName, rrtype, rrclass, rdlen, rdata, ttl, context)); /* * Only process "add" data... */ if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd)) return; # else /* HAVE_AVAHI */ DEBUG_printf(("cups_dnssd_query_cb(browser=%p, interfaceIndex=%d, protocol=%d, event=%d, fullName=\"%s\", rrclass=%u, rrtype=%u, rdata=%p, rdlen=%u, flags=%x, context=%p)", browser, interfaceIndex, protocol, event, fullName, rrclass, rrtype, rdata, (unsigned)rdlen, flags, context)); /* * Only process "add" data... */ if (event != AVAHI_BROWSER_NEW) { if (event == AVAHI_BROWSER_FAILURE) DEBUG_printf(("cups_dnssd_query_cb: %s", avahi_strerror(avahi_client_errno(client)))); return; } # endif /* HAVE_DNSSD */ /* * Lookup the service in the devices array. */ cups_dnssd_unquote(serviceName, fullName, sizeof(serviceName)); if ((ptr = strstr(serviceName, "._")) != NULL) *ptr = '\0'; cups_queue_name(name, serviceName, sizeof(name)); dkey.dest.name = name; if ((device = cupsArrayFind(data->devices, &dkey)) != NULL && device->state == _CUPS_DNSSD_NEW) { /* * Found it, pull out the make and model from the TXT record and save it... */ const uint8_t *txt, /* Pointer into data */ *txtnext, /* Next key/value pair */ *txtend; /* End of entire TXT record */ uint8_t txtlen; /* Length of current key/value pair */ char key[256], /* Key string */ value[256], /* Value string */ make_and_model[512], /* Manufacturer and model */ model[256], /* Model */ uriname[1024], /* Name for URI */ uri[1024]; /* Printer URI */ cups_ptype_t type = CUPS_PRINTER_DISCOVERED | CUPS_PRINTER_BW; /* Printer type */ int saw_printer_type = 0; /* Did we see a printer-type key? */ device->state = _CUPS_DNSSD_PENDING; make_and_model[0] = '\0'; strlcpy(model, "Unknown", sizeof(model)); for (txt = rdata, txtend = txt + rdlen; txt < txtend; txt = txtnext) { /* * Read a key/value pair starting with an 8-bit length. Since the * length is 8 bits and the size of the key/value buffers is 256, we * don't need to check for overflow... */ txtlen = *txt++; if (!txtlen || (txt + txtlen) > txtend) break; txtnext = txt + txtlen; for (ptr = key; txt < txtnext && *txt != '='; txt ++) *ptr++ = (char)*txt; *ptr = '\0'; if (txt < txtnext && *txt == '=') { txt ++; if (txt < txtnext) memcpy(value, txt, (size_t)(txtnext - txt)); value[txtnext - txt] = '\0'; DEBUG_printf(("6cups_dnssd_query_cb: %s=%s", key, value)); } else { DEBUG_printf(("6cups_dnssd_query_cb: '%s' with no value.", key)); continue; } if (!_cups_strcasecmp(key, "usb_MFG") || !_cups_strcasecmp(key, "usb_MANU") || !_cups_strcasecmp(key, "usb_MANUFACTURER")) strlcpy(make_and_model, value, sizeof(make_and_model)); else if (!_cups_strcasecmp(key, "usb_MDL") || !_cups_strcasecmp(key, "usb_MODEL")) strlcpy(model, value, sizeof(model)); else if (!_cups_strcasecmp(key, "product") && !strstr(value, "Ghostscript")) { if (value[0] == '(') { /* * Strip parenthesis... */ if ((ptr = value + strlen(value) - 1) > value && *ptr == ')') *ptr = '\0'; strlcpy(model, value + 1, sizeof(model)); } else strlcpy(model, value, sizeof(model)); } else if (!_cups_strcasecmp(key, "ty")) { strlcpy(model, value, sizeof(model)); if ((ptr = strchr(model, ',')) != NULL) *ptr = '\0'; } else if (!_cups_strcasecmp(key, "note")) device->dest.num_options = cupsAddOption("printer-location", value, device->dest.num_options, &device->dest.options); else if (!_cups_strcasecmp(key, "pdl")) { /* * Look for PDF-capable printers; only PDF-capable printers are shown. */ const char *start, *next; /* Pointer into value */ int have_pdf = 0, /* Have PDF? */ have_raster = 0;/* Have raster format support? */ for (start = value; start && *start; start = next) { if (!_cups_strncasecmp(start, "application/pdf", 15) && (!start[15] || start[15] == ',')) { have_pdf = 1; break; } else if ((!_cups_strncasecmp(start, "image/pwg-raster", 16) && (!start[16] || start[16] == ',')) || (!_cups_strncasecmp(start, "image/urf", 9) && (!start[9] || start[9] == ','))) { have_raster = 1; break; } if ((next = strchr(start, ',')) != NULL) next ++; } if (!have_pdf && !have_raster) device->state = _CUPS_DNSSD_INCOMPATIBLE; } else if (!_cups_strcasecmp(key, "printer-type")) { /* * Value is either NNNN or 0xXXXX */ saw_printer_type = 1; type = (cups_ptype_t)strtol(value, NULL, 0) | CUPS_PRINTER_DISCOVERED; } else if (!saw_printer_type) { if (!_cups_strcasecmp(key, "air") && !_cups_strcasecmp(value, "t")) type |= CUPS_PRINTER_AUTHENTICATED; else if (!_cups_strcasecmp(key, "bind") && !_cups_strcasecmp(value, "t")) type |= CUPS_PRINTER_BIND; else if (!_cups_strcasecmp(key, "collate") && !_cups_strcasecmp(value, "t")) type |= CUPS_PRINTER_COLLATE; else if (!_cups_strcasecmp(key, "color") && !_cups_strcasecmp(value, "t")) type |= CUPS_PRINTER_COLOR; else if (!_cups_strcasecmp(key, "copies") && !_cups_strcasecmp(value, "t")) type |= CUPS_PRINTER_COPIES; else if (!_cups_strcasecmp(key, "duplex") && !_cups_strcasecmp(value, "t")) type |= CUPS_PRINTER_DUPLEX; else if (!_cups_strcasecmp(key, "fax") && !_cups_strcasecmp(value, "t")) type |= CUPS_PRINTER_MFP; else if (!_cups_strcasecmp(key, "papercustom") && !_cups_strcasecmp(value, "t")) type |= CUPS_PRINTER_VARIABLE; else if (!_cups_strcasecmp(key, "papermax")) { if (!_cups_strcasecmp(value, "legal-a4")) type |= CUPS_PRINTER_SMALL; else if (!_cups_strcasecmp(value, "isoc-a2")) type |= CUPS_PRINTER_MEDIUM; else if (!_cups_strcasecmp(value, ">isoc-a2")) type |= CUPS_PRINTER_LARGE; } else if (!_cups_strcasecmp(key, "punch") && !_cups_strcasecmp(value, "t")) type |= CUPS_PRINTER_PUNCH; else if (!_cups_strcasecmp(key, "scan") && !_cups_strcasecmp(value, "t")) type |= CUPS_PRINTER_MFP; else if (!_cups_strcasecmp(key, "sort") && !_cups_strcasecmp(value, "t")) type |= CUPS_PRINTER_SORT; else if (!_cups_strcasecmp(key, "staple") && !_cups_strcasecmp(value, "t")) type |= CUPS_PRINTER_STAPLE; } } /* * Save the printer-xxx values... */ if (make_and_model[0]) { strlcat(make_and_model, " ", sizeof(make_and_model)); strlcat(make_and_model, model, sizeof(make_and_model)); device->dest.num_options = cupsAddOption("printer-make-and-model", make_and_model, device->dest.num_options, &device->dest.options); } else device->dest.num_options = cupsAddOption("printer-make-and-model", model, device->dest.num_options, &device->dest.options); device->type = type; snprintf(value, sizeof(value), "%u", type); device->dest.num_options = cupsAddOption("printer-type", value, device->dest.num_options, &device->dest.options); /* * Save the URI... */ cups_dnssd_unquote(uriname, device->fullName, sizeof(uriname)); httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), !strcmp(device->regtype, "_ipps._tcp") ? "ipps" : "ipp", NULL, uriname, 0, saw_printer_type ? "/cups" : "/"); DEBUG_printf(("6cups_dnssd_query: device-uri=\"%s\"", uri)); device->dest.num_options = cupsAddOption("device-uri", uri, device->dest.num_options, &device->dest.options); } else DEBUG_printf(("6cups_dnssd_query: Ignoring TXT record for '%s'.", fullName)); } /* * 'cups_dnssd_resolve()' - Resolve a Bonjour printer URI. */ static const char * /* O - Resolved URI or NULL */ cups_dnssd_resolve( cups_dest_t *dest, /* I - Destination */ const char *uri, /* I - Current printer URI */ int msec, /* I - Time in milliseconds */ int *cancel, /* I - Pointer to "cancel" variable */ cups_dest_cb_t cb, /* I - Callback */ void *user_data) /* I - User data for callback */ { char tempuri[1024]; /* Temporary URI buffer */ _cups_dnssd_resolve_t resolve; /* Resolve data */ /* * Resolve the URI... */ resolve.cancel = cancel; gettimeofday(&resolve.end_time, NULL); if (msec > 0) { resolve.end_time.tv_sec += msec / 1000; resolve.end_time.tv_usec += (msec % 1000) * 1000; while (resolve.end_time.tv_usec >= 1000000) { resolve.end_time.tv_sec ++; resolve.end_time.tv_usec -= 1000000; } } else resolve.end_time.tv_sec += 75; if (cb) (*cb)(user_data, CUPS_DEST_FLAGS_UNCONNECTED | CUPS_DEST_FLAGS_RESOLVING, dest); if ((uri = _httpResolveURI(uri, tempuri, sizeof(tempuri), _HTTP_RESOLVE_DEFAULT, cups_dnssd_resolve_cb, &resolve)) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to resolve printer-uri."), 1); if (cb) (*cb)(user_data, CUPS_DEST_FLAGS_UNCONNECTED | CUPS_DEST_FLAGS_ERROR, dest); return (NULL); } /* * Save the resolved URI... */ dest->num_options = cupsAddOption("device-uri", uri, dest->num_options, &dest->options); return (cupsGetOption("device-uri", dest->num_options, dest->options)); } /* * 'cups_dnssd_resolve_cb()' - See if we should continue resolving. */ static int /* O - 1 to continue, 0 to stop */ cups_dnssd_resolve_cb(void *context) /* I - Resolve data */ { _cups_dnssd_resolve_t *resolve = (_cups_dnssd_resolve_t *)context; /* Resolve data */ struct timeval curtime; /* Current time */ /* * If the cancel variable is set, return immediately. */ if (resolve->cancel && *(resolve->cancel)) { DEBUG_puts("4cups_dnssd_resolve_cb: Canceled."); return (0); } /* * Otherwise check the end time... */ gettimeofday(&curtime, NULL); DEBUG_printf(("4cups_dnssd_resolve_cb: curtime=%d.%06d, end_time=%d.%06d", (int)curtime.tv_sec, (int)curtime.tv_usec, (int)resolve->end_time.tv_sec, (int)resolve->end_time.tv_usec)); return (curtime.tv_sec < resolve->end_time.tv_sec || (curtime.tv_sec == resolve->end_time.tv_sec && curtime.tv_usec < resolve->end_time.tv_usec)); } /* * 'cups_dnssd_unquote()' - Unquote a name string. */ static void cups_dnssd_unquote(char *dst, /* I - Destination buffer */ const char *src, /* I - Source string */ size_t dstsize) /* I - Size of destination buffer */ { char *dstend = dst + dstsize - 1; /* End of destination buffer */ while (*src && dst < dstend) { if (*src == '\\') { src ++; if (isdigit(src[0] & 255) && isdigit(src[1] & 255) && isdigit(src[2] & 255)) { *dst++ = ((((src[0] - '0') * 10) + src[1] - '0') * 10) + src[2] - '0'; src += 3; } else *dst++ = *src++; } else *dst++ = *src ++; } *dst = '\0'; } #endif /* HAVE_DNSSD */ #if defined(HAVE_AVAHI) || defined(HAVE_DNSSD) /* * 'cups_elapsed()' - Return the elapsed time in milliseconds. */ static int /* O - Elapsed time in milliseconds */ cups_elapsed(struct timeval *t) /* IO - Previous time */ { int msecs; /* Milliseconds */ struct timeval nt; /* New time */ gettimeofday(&nt, NULL); msecs = (int)(1000 * (nt.tv_sec - t->tv_sec) + (nt.tv_usec - t->tv_usec) / 1000); *t = nt; return (msecs); } #endif /* HAVE_AVAHI || HAVE_DNSSD */ /* * 'cups_enum_dests()' - Enumerate destinations from a specific server. */ static int /* O - 1 on success, 0 on failure */ cups_enum_dests( http_t *http, /* I - Connection to scheduler */ unsigned flags, /* I - Enumeration flags */ int msec, /* I - Timeout in milliseconds, -1 for indefinite */ int *cancel, /* I - Pointer to "cancel" variable */ cups_ptype_t type, /* I - Printer type bits */ cups_ptype_t mask, /* I - Mask for printer type bits */ cups_dest_cb_t cb, /* I - Callback function */ void *user_data) /* I - User data */ { int i, j, /* Looping vars */ num_dests; /* Number of destinations */ cups_dest_t *dests = NULL, /* Destinations */ *dest, /* Current destination */ *user_dest; /* User destination */ cups_option_t *option; /* Current option */ char *user_default; /* User default printer */ #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) int count, /* Number of queries started */ completed, /* Number of completed queries */ remaining; /* Remainder of timeout */ struct timeval curtime; /* Current time */ _cups_dnssd_data_t data; /* Data for callback */ _cups_dnssd_device_t *device; /* Current device */ # ifdef HAVE_DNSSD int nfds, /* Number of files responded */ main_fd; /* File descriptor for lookups */ DNSServiceRef ipp_ref = NULL; /* IPP browser */ # ifdef HAVE_SSL DNSServiceRef ipps_ref = NULL; /* IPPS browser */ # endif /* HAVE_SSL */ # ifdef HAVE_POLL struct pollfd pfd; /* Polling data */ # else fd_set input; /* Input set for select() */ struct timeval timeout; /* Timeout for select() */ # endif /* HAVE_POLL */ # else /* HAVE_AVAHI */ int error; /* Error value */ AvahiServiceBrowser *ipp_ref = NULL; /* IPP browser */ # ifdef HAVE_SSL AvahiServiceBrowser *ipps_ref = NULL; /* IPPS browser */ # endif /* HAVE_SSL */ # endif /* HAVE_DNSSD */ #else _cups_getdata_t data; /* Data for callback */ #endif /* HAVE_DNSSD || HAVE_AVAHI */ const char *home; /* HOME environment variable */ char filename[1024]; /* Local lpoptions file */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ DEBUG_printf(("cups_enum_dests(flags=%x, msec=%d, cancel=%p, type=%x, mask=%x, cb=%p, user_data=%p)", flags, msec, (void *)cancel, type, mask, (void *)cb, (void *)user_data)); /* * Range check input... */ (void)flags; if (!cb) { DEBUG_puts("1cups_enum_dests: No callback, returning 0."); return (0); } /* * Load the /etc/cups/lpoptions and ~/.cups/lpoptions files... */ memset(&data, 0, sizeof(data)); if ((user_default = _cupsUserDefault(data.def_name, sizeof(data.def_name))) == NULL) { const char *defprinter = cupsGetDefault2(http); /* Server default, if any */ if (defprinter) strlcpy(data.def_name, defprinter, sizeof(data.def_name)); } if (data.def_name[0]) { /* * Separate printer and instance name... */ if ((data.def_instance = strchr(data.def_name, '/')) != NULL) *data.def_instance++ = '\0'; } DEBUG_printf(("1cups_enum_dests: def_name=\"%s\", def_instance=\"%s\"", data.def_name, data.def_instance)); snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot); data.num_dests = cups_get_dests(filename, NULL, NULL, 1, user_default != NULL, data.num_dests, &data.dests); if ((home = getenv("HOME")) != NULL) { snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home); data.num_dests = cups_get_dests(filename, NULL, NULL, 1, user_default != NULL, data.num_dests, &data.dests); } /* * Get ready to enumerate... */ #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) data.type = type; data.mask = mask; data.cb = cb; data.user_data = user_data; data.devices = cupsArrayNew3((cups_array_func_t)cups_dnssd_compare_devices, NULL, NULL, 0, NULL, (cups_afree_func_t)cups_dnssd_free_device); #endif /* HAVE_DNSSD || HAVE_AVAHI */ if (!(mask & CUPS_PRINTER_DISCOVERED) || !(type & CUPS_PRINTER_DISCOVERED)) { /* * Get the list of local printers and pass them to the callback function... */ num_dests = _cupsGetDests(http, IPP_OP_CUPS_GET_PRINTERS, NULL, &dests, type, mask); if (data.def_name[0]) { /* * Lookup the named default printer and instance and make it the default... */ if ((dest = cupsGetDest(data.def_name, data.def_instance, num_dests, dests)) != NULL) { DEBUG_printf(("1cups_enum_dests: Setting is_default on \"%s/%s\".", dest->name, dest->instance)); dest->is_default = 1; } } for (i = num_dests, dest = dests; i > 0 && (!cancel || !*cancel); i --, dest ++) { #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) const char *device_uri; /* Device URI */ #endif /* HAVE_DNSSD || HAVE_AVAHI */ if ((user_dest = cupsGetDest(dest->name, dest->instance, data.num_dests, data.dests)) != NULL) { /* * Apply user defaults to this destination... */ for (j = user_dest->num_options, option = user_dest->options; j > 0; j --, option ++) dest->num_options = cupsAddOption(option->name, option->value, dest->num_options, &dest->options); } if (!(*cb)(user_data, i > 1 ? CUPS_DEST_FLAGS_MORE : CUPS_DEST_FLAGS_NONE, dest)) break; #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) if (!dest->instance && (device_uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL && !strncmp(device_uri, "dnssd://", 8)) { /* * Add existing queue using service name, etc. so we don't list it again... */ char scheme[32], /* URI scheme */ userpass[32], /* Username:password */ serviceName[256], /* Service name (host field) */ resource[256], /* Resource (options) */ *regtype, /* Registration type */ *replyDomain; /* Registration domain */ int port; /* Port number (not used) */ if (httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), serviceName, sizeof(serviceName), &port, resource, sizeof(resource)) >= HTTP_URI_STATUS_OK) { if ((regtype = strstr(serviceName, "._ipp")) != NULL) { *regtype++ = '\0'; if ((replyDomain = strstr(regtype, "._tcp.")) != NULL) { replyDomain[5] = '\0'; replyDomain += 6; if ((device = cups_dnssd_get_device(&data, serviceName, regtype, replyDomain)) != NULL) device->state = _CUPS_DNSSD_ACTIVE; } } } } #endif /* HAVE_DNSSD || HAVE_AVAHI */ } cupsFreeDests(num_dests, dests); if (i > 0 || msec == 0) goto enum_finished; } /* * Return early if the caller doesn't want to do discovery... */ if ((mask & CUPS_PRINTER_DISCOVERED) && !(type & CUPS_PRINTER_DISCOVERED)) goto enum_finished; #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) /* * Get Bonjour-shared printers... */ gettimeofday(&curtime, NULL); # ifdef HAVE_DNSSD if (DNSServiceCreateConnection(&data.main_ref) != kDNSServiceErr_NoError) { DEBUG_puts("1cups_enum_dests: Unable to create service browser, returning 0."); cupsFreeDests(data.num_dests, data.dests); return (0); } main_fd = DNSServiceRefSockFD(data.main_ref); ipp_ref = data.main_ref; if (DNSServiceBrowse(&ipp_ref, kDNSServiceFlagsShareConnection, 0, "_ipp._tcp", NULL, (DNSServiceBrowseReply)cups_dnssd_browse_cb, &data) != kDNSServiceErr_NoError) { DEBUG_puts("1cups_enum_dests: Unable to create IPP browser, returning 0."); DNSServiceRefDeallocate(data.main_ref); cupsFreeDests(data.num_dests, data.dests); return (0); } # ifdef HAVE_SSL ipps_ref = data.main_ref; if (DNSServiceBrowse(&ipps_ref, kDNSServiceFlagsShareConnection, 0, "_ipps._tcp", NULL, (DNSServiceBrowseReply)cups_dnssd_browse_cb, &data) != kDNSServiceErr_NoError) { DEBUG_puts("1cups_enum_dests: Unable to create IPPS browser, returning 0."); DNSServiceRefDeallocate(data.main_ref); cupsFreeDests(data.num_dests, data.dests); return (0); } # endif /* HAVE_SSL */ # else /* HAVE_AVAHI */ if ((data.simple_poll = avahi_simple_poll_new()) == NULL) { DEBUG_puts("1cups_enum_dests: Unable to create Avahi poll, returning 0."); cupsFreeDests(data.num_dests, data.dests); return (0); } avahi_simple_poll_set_func(data.simple_poll, cups_dnssd_poll_cb, &data); data.client = avahi_client_new(avahi_simple_poll_get(data.simple_poll), 0, cups_dnssd_client_cb, &data, &error); if (!data.client) { DEBUG_puts("1cups_enum_dests: Unable to create Avahi client, returning 0."); avahi_simple_poll_free(data.simple_poll); cupsFreeDests(data.num_dests, data.dests); return (0); } data.browsers = 1; if ((ipp_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_ipp._tcp", NULL, 0, cups_dnssd_browse_cb, &data)) == NULL) { DEBUG_puts("1cups_enum_dests: Unable to create Avahi IPP browser, returning 0."); avahi_client_free(data.client); avahi_simple_poll_free(data.simple_poll); cupsFreeDests(data.num_dests, data.dests); return (0); } # ifdef HAVE_SSL data.browsers ++; if ((ipps_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_ipps._tcp", NULL, 0, cups_dnssd_browse_cb, &data)) == NULL) { DEBUG_puts("1cups_enum_dests: Unable to create Avahi IPPS browser, returning 0."); avahi_service_browser_free(ipp_ref); avahi_client_free(data.client); avahi_simple_poll_free(data.simple_poll); cupsFreeDests(data.num_dests, data.dests); return (0); } # endif /* HAVE_SSL */ # endif /* HAVE_DNSSD */ if (msec < 0) remaining = INT_MAX; else remaining = msec; while (remaining > 0 && (!cancel || !*cancel)) { /* * Check for input... */ DEBUG_printf(("1cups_enum_dests: remaining=%d", remaining)); cups_elapsed(&curtime); # ifdef HAVE_DNSSD # ifdef HAVE_POLL pfd.fd = main_fd; pfd.events = POLLIN; nfds = poll(&pfd, 1, remaining > _CUPS_DNSSD_MAXTIME ? _CUPS_DNSSD_MAXTIME : remaining); # else FD_ZERO(&input); FD_SET(main_fd, &input); timeout.tv_sec = 0; timeout.tv_usec = 1000 * (remaining > _CUPS_DNSSD_MAXTIME ? _CUPS_DNSSD_MAXTIME : remaining); nfds = select(main_fd + 1, &input, NULL, NULL, &timeout); # endif /* HAVE_POLL */ if (nfds > 0) DNSServiceProcessResult(data.main_ref); else if (nfds < 0 && errno != EINTR && errno != EAGAIN) break; # else /* HAVE_AVAHI */ data.got_data = 0; if ((error = avahi_simple_poll_iterate(data.simple_poll, _CUPS_DNSSD_MAXTIME)) > 0) { /* * We've been told to exit the loop. Perhaps the connection to * Avahi failed. */ break; } DEBUG_printf(("1cups_enum_dests: got_data=%d", data.got_data)); # endif /* HAVE_DNSSD */ remaining -= cups_elapsed(&curtime); for (device = (_cups_dnssd_device_t *)cupsArrayFirst(data.devices), count = 0, completed = 0; device; device = (_cups_dnssd_device_t *)cupsArrayNext(data.devices)) { if (device->ref) count ++; if (device->state == _CUPS_DNSSD_ACTIVE) completed ++; if (!device->ref && device->state == _CUPS_DNSSD_NEW) { DEBUG_printf(("1cups_enum_dests: Querying '%s'.", device->fullName)); # ifdef HAVE_DNSSD device->ref = data.main_ref; if (DNSServiceQueryRecord(&(device->ref), kDNSServiceFlagsShareConnection, 0, device->fullName, kDNSServiceType_TXT, kDNSServiceClass_IN, (DNSServiceQueryRecordReply)cups_dnssd_query_cb, &data) == kDNSServiceErr_NoError) { count ++; } else { device->ref = 0; device->state = _CUPS_DNSSD_ERROR; DEBUG_puts("1cups_enum_dests: Query failed."); } # else /* HAVE_AVAHI */ if ((device->ref = avahi_record_browser_new(data.client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, device->fullName, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT, 0, cups_dnssd_query_cb, &data)) != NULL) { DEBUG_printf(("1cups_enum_dests: Query ref=%p", device->ref)); count ++; } else { device->state = _CUPS_DNSSD_ERROR; DEBUG_printf(("1cups_enum_dests: Query failed: %s", avahi_strerror(avahi_client_errno(data.client)))); } # endif /* HAVE_DNSSD */ } else if (device->ref && device->state == _CUPS_DNSSD_PENDING) { completed ++; DEBUG_printf(("1cups_enum_dests: Query for \"%s\" is complete.", device->fullName)); if ((device->type & mask) == type) { dest = &device->dest; if ((user_dest = cupsGetDest(dest->name, dest->instance, data.num_dests, data.dests)) != NULL) { /* * Apply user defaults to this destination... */ for (j = user_dest->num_options, option = user_dest->options; j > 0; j --, option ++) dest->num_options = cupsAddOption(option->name, option->value, dest->num_options, &dest->options); } if (!strcasecmp(dest->name, data.def_name) && !data.def_instance) { DEBUG_printf(("1cups_enum_dests: Setting is_default on discovered \"%s\".", dest->name)); dest->is_default = 1; } DEBUG_printf(("1cups_enum_dests: Add callback for \"%s\".", device->dest.name)); if (!(*cb)(user_data, CUPS_DEST_FLAGS_NONE, dest)) { remaining = -1; break; } } device->state = _CUPS_DNSSD_ACTIVE; } } # ifdef HAVE_AVAHI DEBUG_printf(("1cups_enum_dests: remaining=%d, browsers=%d, completed=%d, count=%d, devices count=%d", remaining, data.browsers, completed, count, cupsArrayCount(data.devices))); if (data.browsers == 0 && completed == cupsArrayCount(data.devices)) break; # else DEBUG_printf(("1cups_enum_dests: remaining=%d, completed=%d, count=%d, devices count=%d", remaining, completed, count, cupsArrayCount(data.devices))); if (completed == cupsArrayCount(data.devices)) break; # endif /* HAVE_AVAHI */ } #endif /* HAVE_DNSSD || HAVE_AVAHI */ /* * Return... */ enum_finished: cupsFreeDests(data.num_dests, data.dests); #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) cupsArrayDelete(data.devices); # ifdef HAVE_DNSSD if (ipp_ref) DNSServiceRefDeallocate(ipp_ref); # ifdef HAVE_SSL if (ipps_ref) DNSServiceRefDeallocate(ipps_ref); # endif /* HAVE_SSL */ if (data.main_ref) DNSServiceRefDeallocate(data.main_ref); # else /* HAVE_AVAHI */ if (ipp_ref) avahi_service_browser_free(ipp_ref); # ifdef HAVE_SSL if (ipps_ref) avahi_service_browser_free(ipps_ref); # endif /* HAVE_SSL */ if (data.client) avahi_client_free(data.client); if (data.simple_poll) avahi_simple_poll_free(data.simple_poll); # endif /* HAVE_DNSSD */ #endif /* HAVE_DNSSD || HAVE_AVAHI */ DEBUG_puts("1cups_enum_dests: Returning 1."); return (1); } /* * 'cups_find_dest()' - Find a destination using a binary search. */ static int /* O - Index of match */ cups_find_dest(const char *name, /* I - Destination name */ const char *instance, /* I - Instance or NULL */ int num_dests, /* I - Number of destinations */ cups_dest_t *dests, /* I - Destinations */ int prev, /* I - Previous index */ int *rdiff) /* O - Difference of match */ { int left, /* Low mark for binary search */ right, /* High mark for binary search */ current, /* Current index */ diff; /* Result of comparison */ cups_dest_t key; /* Search key */ key.name = (char *)name; key.instance = (char *)instance; if (prev >= 0) { /* * Start search on either side of previous... */ if ((diff = cups_compare_dests(&key, dests + prev)) == 0 || (diff < 0 && prev == 0) || (diff > 0 && prev == (num_dests - 1))) { *rdiff = diff; return (prev); } else if (diff < 0) { /* * Start with previous on right side... */ left = 0; right = prev; } else { /* * Start wih previous on left side... */ left = prev; right = num_dests - 1; } } else { /* * Start search in the middle... */ left = 0; right = num_dests - 1; } do { current = (left + right) / 2; diff = cups_compare_dests(&key, dests + current); if (diff == 0) break; else if (diff < 0) right = current; else left = current; } while ((right - left) > 1); if (diff != 0) { /* * Check the last 1 or 2 elements... */ if ((diff = cups_compare_dests(&key, dests + left)) <= 0) current = left; else { diff = cups_compare_dests(&key, dests + right); current = right; } } /* * Return the closest destination and the difference... */ *rdiff = diff; return (current); } /* * 'cups_get_cb()' - Collect enumerated destinations. */ static int /* O - 1 to continue, 0 to stop */ cups_get_cb(_cups_getdata_t *data, /* I - Data from cupsGetDests */ unsigned flags, /* I - Enumeration flags */ cups_dest_t *dest) /* I - Destination */ { if (flags & CUPS_DEST_FLAGS_REMOVED) { /* * Remove destination from array... */ data->num_dests = cupsRemoveDest(dest->name, dest->instance, data->num_dests, &data->dests); } else { /* * Add destination to array... */ data->num_dests = cupsCopyDest(dest, data->num_dests, &data->dests); } return (1); } /* * 'cups_get_default()' - Get the default destination from an lpoptions file. */ static char * /* O - Default destination or NULL */ cups_get_default(const char *filename, /* I - File to read */ char *namebuf, /* I - Name buffer */ size_t namesize, /* I - Size of name buffer */ const char **instance) /* I - Instance */ { cups_file_t *fp; /* lpoptions file */ char line[8192], /* Line from file */ *value, /* Value for line */ *nameptr; /* Pointer into name */ int linenum; /* Current line */ *namebuf = '\0'; if ((fp = cupsFileOpen(filename, "r")) != NULL) { linenum = 0; while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) { if (!_cups_strcasecmp(line, "default") && value) { strlcpy(namebuf, value, namesize); if ((nameptr = strchr(namebuf, ' ')) != NULL) *nameptr = '\0'; if ((nameptr = strchr(namebuf, '\t')) != NULL) *nameptr = '\0'; if ((nameptr = strchr(namebuf, '/')) != NULL) *nameptr++ = '\0'; *instance = nameptr; break; } } cupsFileClose(fp); } return (*namebuf ? namebuf : NULL); } /* * 'cups_get_dests()' - Get destinations from a file. */ static int /* O - Number of destinations */ cups_get_dests( const char *filename, /* I - File to read from */ const char *match_name, /* I - Destination name we want */ const char *match_inst, /* I - Instance name we want */ int load_all, /* I - Load all saved destinations? */ int user_default_set, /* I - User default printer set? */ int num_dests, /* I - Number of destinations */ cups_dest_t **dests) /* IO - Destinations */ { int i; /* Looping var */ cups_dest_t *dest; /* Current destination */ cups_file_t *fp; /* File pointer */ char line[8192], /* Line from file */ *lineptr, /* Pointer into line */ *name, /* Name of destination/option */ *instance; /* Instance of destination */ int linenum; /* Current line number */ DEBUG_printf(("7cups_get_dests(filename=\"%s\", match_name=\"%s\", match_inst=\"%s\", load_all=%d, user_default_set=%d, num_dests=%d, dests=%p)", filename, match_name, match_inst, load_all, user_default_set, num_dests, (void *)dests)); /* * Try to open the file... */ if ((fp = cupsFileOpen(filename, "r")) == NULL) return (num_dests); /* * Read each printer; each line looks like: * * Dest name[/instance] options * Default name[/instance] options */ linenum = 0; while (cupsFileGetConf(fp, line, sizeof(line), &lineptr, &linenum)) { /* * See what type of line it is... */ DEBUG_printf(("9cups_get_dests: linenum=%d line=\"%s\" lineptr=\"%s\"", linenum, line, lineptr)); if ((_cups_strcasecmp(line, "dest") && _cups_strcasecmp(line, "default")) || !lineptr) { DEBUG_puts("9cups_get_dests: Not a dest or default line..."); continue; } name = lineptr; /* * Search for an instance... */ while (!isspace(*lineptr & 255) && *lineptr && *lineptr != '/') lineptr ++; if (*lineptr == '/') { /* * Found an instance... */ *lineptr++ = '\0'; instance = lineptr; /* * Search for an instance... */ while (!isspace(*lineptr & 255) && *lineptr) lineptr ++; } else instance = NULL; if (*lineptr) *lineptr++ = '\0'; DEBUG_printf(("9cups_get_dests: name=\"%s\", instance=\"%s\"", name, instance)); /* * Match and/or ignore missing destinations... */ if (match_name) { if (_cups_strcasecmp(name, match_name) || (!instance && match_inst) || (instance && !match_inst) || (instance && _cups_strcasecmp(instance, match_inst))) continue; dest = *dests; } else if (!load_all && cupsGetDest(name, NULL, num_dests, *dests) == NULL) { DEBUG_puts("9cups_get_dests: Not found!"); continue; } else { /* * Add the destination... */ num_dests = cupsAddDest(name, instance, num_dests, dests); if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL) { /* * Out of memory! */ DEBUG_puts("9cups_get_dests: Out of memory!"); break; } } /* * Add options until we hit the end of the line... */ dest->num_options = cupsParseOptions(lineptr, dest->num_options, &(dest->options)); /* * If we found what we were looking for, stop now... */ if (match_name) break; /* * Set this as default if needed... */ if (!user_default_set && !_cups_strcasecmp(line, "default")) { DEBUG_puts("9cups_get_dests: Setting as default..."); for (i = 0; i < num_dests; i ++) (*dests)[i].is_default = 0; dest->is_default = 1; } } /* * Close the file and return... */ cupsFileClose(fp); return (num_dests); } /* * 'cups_make_string()' - Make a comma-separated string of values from an IPP * attribute. */ static char * /* O - New string */ cups_make_string( ipp_attribute_t *attr, /* I - Attribute to convert */ char *buffer, /* I - Buffer */ size_t bufsize) /* I - Size of buffer */ { int i; /* Looping var */ char *ptr, /* Pointer into buffer */ *end, /* Pointer to end of buffer */ *valptr; /* Pointer into string attribute */ /* * Return quickly if we have a single string value... */ if (attr->num_values == 1 && attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM && attr->value_tag != IPP_TAG_BOOLEAN && attr->value_tag != IPP_TAG_RANGE) return (attr->values[0].string.text); /* * Copy the values to the string, separating with commas and escaping strings * as needed... */ end = buffer + bufsize - 1; for (i = 0, ptr = buffer; i < attr->num_values && ptr < end; i ++) { if (i) *ptr++ = ','; switch (attr->value_tag) { case IPP_TAG_INTEGER : case IPP_TAG_ENUM : snprintf(ptr, (size_t)(end - ptr + 1), "%d", attr->values[i].integer); break; case IPP_TAG_BOOLEAN : if (attr->values[i].boolean) strlcpy(ptr, "true", (size_t)(end - ptr + 1)); else strlcpy(ptr, "false", (size_t)(end - ptr + 1)); break; case IPP_TAG_RANGE : if (attr->values[i].range.lower == attr->values[i].range.upper) snprintf(ptr, (size_t)(end - ptr + 1), "%d", attr->values[i].range.lower); else snprintf(ptr, (size_t)(end - ptr + 1), "%d-%d", attr->values[i].range.lower, attr->values[i].range.upper); break; default : for (valptr = attr->values[i].string.text; *valptr && ptr < end;) { if (strchr(" \t\n\\\'\"", *valptr)) { if (ptr >= (end - 1)) break; *ptr++ = '\\'; } *ptr++ = *valptr++; } *ptr = '\0'; break; } ptr += strlen(ptr); } *ptr = '\0'; return (buffer); } /* * 'cups_name_cb()' - Find an enumerated destination. */ static int /* O - 1 to continue, 0 to stop */ cups_name_cb(_cups_namedata_t *data, /* I - Data from cupsGetNamedDest */ unsigned flags, /* I - Enumeration flags */ cups_dest_t *dest) /* I - Destination */ { DEBUG_printf(("2cups_name_cb(data=%p(%s), flags=%x, dest=%p(%s)", (void *)data, data->name, flags, (void *)dest, dest->name)); if (!(flags & CUPS_DEST_FLAGS_REMOVED) && !dest->instance && !strcasecmp(data->name, dest->name)) { /* * Copy destination and stop enumeration... */ cupsCopyDest(dest, 0, &data->dest); return (0); } return (1); } /* * 'cups_queue_name()' - Create a local queue name based on the service name. */ static void cups_queue_name( char *name, /* I - Name buffer */ const char *serviceName, /* I - Service name */ size_t namesize) /* I - Size of name buffer */ { const char *ptr; /* Pointer into serviceName */ char *nameptr; /* Pointer into name */ for (nameptr = name, ptr = serviceName; *ptr && nameptr < (name + namesize - 1); ptr ++) { /* * Sanitize the printer name... */ if (_cups_isalnum(*ptr)) *nameptr++ = *ptr; else if (nameptr == name || nameptr[-1] != '_') *nameptr++ = '_'; } *nameptr = '\0'; } ippsample/cups/options.c0000644000175000017500000003713413240604116014360 0ustar tilltill/* * Option routines for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" /* * Local functions... */ static int cups_compare_options(cups_option_t *a, cups_option_t *b); static int cups_find_option(const char *name, int num_options, cups_option_t *option, int prev, int *rdiff); /* * 'cupsAddIntegerOption()' - Add an integer option to an option array. * * New option arrays can be initialized simply by passing 0 for the * "num_options" parameter. * * @since CUPS 2.2.4/macOS 10.13@ */ int /* O - Number of options */ cupsAddIntegerOption( const char *name, /* I - Name of option */ int value, /* I - Value of option */ int num_options, /* I - Number of options */ cups_option_t **options) /* IO - Pointer to options */ { char strvalue[32]; /* String value */ snprintf(strvalue, sizeof(strvalue), "%d", value); return (cupsAddOption(name, strvalue, num_options, options)); } /* * 'cupsAddOption()' - Add an option to an option array. * * New option arrays can be initialized simply by passing 0 for the * "num_options" parameter. */ int /* O - Number of options */ cupsAddOption(const char *name, /* I - Name of option */ const char *value, /* I - Value of option */ int num_options,/* I - Number of options */ cups_option_t **options) /* IO - Pointer to options */ { cups_option_t *temp; /* Pointer to new option */ int insert, /* Insertion point */ diff; /* Result of search */ DEBUG_printf(("2cupsAddOption(name=\"%s\", value=\"%s\", num_options=%d, options=%p)", name, value, num_options, (void *)options)); if (!name || !name[0] || !value || !options || num_options < 0) { DEBUG_printf(("3cupsAddOption: Returning %d", num_options)); return (num_options); } if (!_cups_strcasecmp(name, "cupsPrintQuality")) num_options = cupsRemoveOption("print-quality", num_options, options); else if (!_cups_strcasecmp(name, "print-quality")) num_options = cupsRemoveOption("cupsPrintQuality", num_options, options); /* * Look for an existing option with the same name... */ if (num_options == 0) { insert = 0; diff = 1; } else { insert = cups_find_option(name, num_options, *options, num_options - 1, &diff); if (diff > 0) insert ++; } if (diff) { /* * No matching option name... */ DEBUG_printf(("4cupsAddOption: New option inserted at index %d...", insert)); if (num_options == 0) temp = (cups_option_t *)malloc(sizeof(cups_option_t)); else temp = (cups_option_t *)realloc(*options, sizeof(cups_option_t) * (size_t)(num_options + 1)); if (!temp) { DEBUG_puts("3cupsAddOption: Unable to expand option array, returning 0"); return (0); } *options = temp; if (insert < num_options) { DEBUG_printf(("4cupsAddOption: Shifting %d options...", (int)(num_options - insert))); memmove(temp + insert + 1, temp + insert, (size_t)(num_options - insert) * sizeof(cups_option_t)); } temp += insert; temp->name = _cupsStrAlloc(name); num_options ++; } else { /* * Match found; free the old value... */ DEBUG_printf(("4cupsAddOption: Option already exists at index %d...", insert)); temp = *options + insert; _cupsStrFree(temp->value); } temp->value = _cupsStrAlloc(value); DEBUG_printf(("3cupsAddOption: Returning %d", num_options)); return (num_options); } /* * 'cupsFreeOptions()' - Free all memory used by options. */ void cupsFreeOptions( int num_options, /* I - Number of options */ cups_option_t *options) /* I - Pointer to options */ { int i; /* Looping var */ DEBUG_printf(("cupsFreeOptions(num_options=%d, options=%p)", num_options, (void *)options)); if (num_options <= 0 || !options) return; for (i = 0; i < num_options; i ++) { _cupsStrFree(options[i].name); _cupsStrFree(options[i].value); } free(options); } /* * 'cupsGetIntegerOption()' - Get an integer option value. * * INT_MIN is returned when the option does not exist, is not an integer, or * exceeds the range of values for the "int" type. * * @since CUPS 2.2.4/macOS 10.13@ */ int /* O - Option value or @code INT_MIN@ */ cupsGetIntegerOption( const char *name, /* I - Name of option */ int num_options, /* I - Number of options */ cups_option_t *options) /* I - Options */ { const char *value = cupsGetOption(name, num_options, options); /* String value of option */ char *ptr; /* Pointer into string value */ long intvalue; /* Integer value */ if (!value || !*value) return (INT_MIN); intvalue = strtol(value, &ptr, 10); if (intvalue < INT_MIN || intvalue > INT_MAX || *ptr) return (INT_MIN); return ((int)intvalue); } /* * 'cupsGetOption()' - Get an option value. */ const char * /* O - Option value or @code NULL@ */ cupsGetOption(const char *name, /* I - Name of option */ int num_options,/* I - Number of options */ cups_option_t *options) /* I - Options */ { int diff, /* Result of comparison */ match; /* Matching index */ DEBUG_printf(("2cupsGetOption(name=\"%s\", num_options=%d, options=%p)", name, num_options, (void *)options)); if (!name || num_options <= 0 || !options) { DEBUG_puts("3cupsGetOption: Returning NULL"); return (NULL); } match = cups_find_option(name, num_options, options, -1, &diff); if (!diff) { DEBUG_printf(("3cupsGetOption: Returning \"%s\"", options[match].value)); return (options[match].value); } DEBUG_puts("3cupsGetOption: Returning NULL"); return (NULL); } /* * 'cupsParseOptions()' - Parse options from a command-line argument. * * This function converts space-delimited name/value pairs according * to the PAPI text option ABNF specification. Collection values * ("name={a=... b=... c=...}") are stored with the curley brackets * intact - use @code cupsParseOptions@ on the value to extract the * collection attributes. */ int /* O - Number of options found */ cupsParseOptions( const char *arg, /* I - Argument to parse */ int num_options, /* I - Number of options */ cups_option_t **options) /* O - Options found */ { char *copyarg, /* Copy of input string */ *ptr, /* Pointer into string */ *name, /* Pointer to name */ *value, /* Pointer to value */ sep, /* Separator character */ quote; /* Quote character */ DEBUG_printf(("cupsParseOptions(arg=\"%s\", num_options=%d, options=%p)", arg, num_options, (void *)options)); /* * Range check input... */ if (!arg) { DEBUG_printf(("1cupsParseOptions: Returning %d", num_options)); return (num_options); } if (!options || num_options < 0) { DEBUG_puts("1cupsParseOptions: Returning 0"); return (0); } /* * Make a copy of the argument string and then divide it up... */ if ((copyarg = strdup(arg)) == NULL) { DEBUG_puts("1cupsParseOptions: Unable to copy arg string"); DEBUG_printf(("1cupsParseOptions: Returning %d", num_options)); return (num_options); } if (*copyarg == '{') { /* * Remove surrounding {} so we can parse "{name=value ... name=value}"... */ if ((ptr = copyarg + strlen(copyarg) - 1) > copyarg && *ptr == '}') { *ptr = '\0'; ptr = copyarg + 1; } else ptr = copyarg; } else ptr = copyarg; /* * Skip leading spaces... */ while (_cups_isspace(*ptr)) ptr ++; /* * Loop through the string... */ while (*ptr != '\0') { /* * Get the name up to a SPACE, =, or end-of-string... */ name = ptr; while (!strchr("\f\n\r\t\v =", *ptr) && *ptr) ptr ++; /* * Avoid an empty name... */ if (ptr == name) break; /* * Skip trailing spaces... */ while (_cups_isspace(*ptr)) *ptr++ = '\0'; if ((sep = *ptr) == '=') *ptr++ = '\0'; DEBUG_printf(("2cupsParseOptions: name=\"%s\"", name)); if (sep != '=') { /* * Boolean option... */ if (!_cups_strncasecmp(name, "no", 2)) num_options = cupsAddOption(name + 2, "false", num_options, options); else num_options = cupsAddOption(name, "true", num_options, options); continue; } /* * Remove = and parse the value... */ value = ptr; while (*ptr && !_cups_isspace(*ptr)) { if (*ptr == ',') ptr ++; else if (*ptr == '\'' || *ptr == '\"') { /* * Quoted string constant... */ quote = *ptr; _cups_strcpy(ptr, ptr + 1); while (*ptr != quote && *ptr) { if (*ptr == '\\' && ptr[1]) _cups_strcpy(ptr, ptr + 1); ptr ++; } if (*ptr) _cups_strcpy(ptr, ptr + 1); } else if (*ptr == '{') { /* * Collection value... */ int depth; for (depth = 0; *ptr; ptr ++) { if (*ptr == '{') depth ++; else if (*ptr == '}') { depth --; if (!depth) { ptr ++; break; } } else if (*ptr == '\\' && ptr[1]) _cups_strcpy(ptr, ptr + 1); } } else { /* * Normal space-delimited string... */ while (*ptr && !_cups_isspace(*ptr)) { if (*ptr == '\\' && ptr[1]) _cups_strcpy(ptr, ptr + 1); ptr ++; } } } if (*ptr != '\0') *ptr++ = '\0'; DEBUG_printf(("2cupsParseOptions: value=\"%s\"", value)); /* * Skip trailing whitespace... */ while (_cups_isspace(*ptr)) ptr ++; /* * Add the string value... */ num_options = cupsAddOption(name, value, num_options, options); } /* * Free the copy of the argument we made and return the number of options * found. */ free(copyarg); DEBUG_printf(("1cupsParseOptions: Returning %d", num_options)); return (num_options); } /* * 'cupsRemoveOption()' - Remove an option from an option array. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - New number of options */ cupsRemoveOption( const char *name, /* I - Option name */ int num_options, /* I - Current number of options */ cups_option_t **options) /* IO - Options */ { int i; /* Looping var */ cups_option_t *option; /* Current option */ DEBUG_printf(("2cupsRemoveOption(name=\"%s\", num_options=%d, options=%p)", name, num_options, (void *)options)); /* * Range check input... */ if (!name || num_options < 1 || !options) { DEBUG_printf(("3cupsRemoveOption: Returning %d", num_options)); return (num_options); } /* * Loop for the option... */ for (i = num_options, option = *options; i > 0; i --, option ++) if (!_cups_strcasecmp(name, option->name)) break; if (i) { /* * Remove this option from the array... */ DEBUG_puts("4cupsRemoveOption: Found option, removing it..."); num_options --; i --; _cupsStrFree(option->name); _cupsStrFree(option->value); if (i > 0) memmove(option, option + 1, (size_t)i * sizeof(cups_option_t)); } /* * Return the new number of options... */ DEBUG_printf(("3cupsRemoveOption: Returning %d", num_options)); return (num_options); } /* * '_cupsGet1284Values()' - Get 1284 device ID keys and values. * * The returned dictionary is a CUPS option array that can be queried with * cupsGetOption and freed with cupsFreeOptions. */ int /* O - Number of key/value pairs */ _cupsGet1284Values( const char *device_id, /* I - IEEE-1284 device ID string */ cups_option_t **values) /* O - Array of key/value pairs */ { int num_values; /* Number of values */ char key[256], /* Key string */ value[256], /* Value string */ *ptr; /* Pointer into key/value */ /* * Range check input... */ if (values) *values = NULL; if (!device_id || !values) return (0); /* * Parse the 1284 device ID value into keys and values. The format is * repeating sequences of: * * [whitespace]key:value[whitespace]; */ num_values = 0; while (*device_id) { while (_cups_isspace(*device_id)) device_id ++; if (!*device_id) break; for (ptr = key; *device_id && *device_id != ':'; device_id ++) if (ptr < (key + sizeof(key) - 1)) *ptr++ = *device_id; if (!*device_id) break; while (ptr > key && _cups_isspace(ptr[-1])) ptr --; *ptr = '\0'; device_id ++; while (_cups_isspace(*device_id)) device_id ++; if (!*device_id) break; for (ptr = value; *device_id && *device_id != ';'; device_id ++) if (ptr < (value + sizeof(value) - 1)) *ptr++ = *device_id; if (!*device_id) break; while (ptr > value && _cups_isspace(ptr[-1])) ptr --; *ptr = '\0'; device_id ++; num_values = cupsAddOption(key, value, num_values, values); } return (num_values); } /* * 'cups_compare_options()' - Compare two options. */ static int /* O - Result of comparison */ cups_compare_options(cups_option_t *a, /* I - First option */ cups_option_t *b) /* I - Second option */ { return (_cups_strcasecmp(a->name, b->name)); } /* * 'cups_find_option()' - Find an option using a binary search. */ static int /* O - Index of match */ cups_find_option( const char *name, /* I - Option name */ int num_options, /* I - Number of options */ cups_option_t *options, /* I - Options */ int prev, /* I - Previous index */ int *rdiff) /* O - Difference of match */ { int left, /* Low mark for binary search */ right, /* High mark for binary search */ current, /* Current index */ diff; /* Result of comparison */ cups_option_t key; /* Search key */ DEBUG_printf(("7cups_find_option(name=\"%s\", num_options=%d, options=%p, prev=%d, rdiff=%p)", name, num_options, (void *)options, prev, (void *)rdiff)); #ifdef DEBUG for (left = 0; left < num_options; left ++) DEBUG_printf(("9cups_find_option: options[%d].name=\"%s\", .value=\"%s\"", left, options[left].name, options[left].value)); #endif /* DEBUG */ key.name = (char *)name; if (prev >= 0) { /* * Start search on either side of previous... */ if ((diff = cups_compare_options(&key, options + prev)) == 0 || (diff < 0 && prev == 0) || (diff > 0 && prev == (num_options - 1))) { *rdiff = diff; return (prev); } else if (diff < 0) { /* * Start with previous on right side... */ left = 0; right = prev; } else { /* * Start wih previous on left side... */ left = prev; right = num_options - 1; } } else { /* * Start search in the middle... */ left = 0; right = num_options - 1; } do { current = (left + right) / 2; diff = cups_compare_options(&key, options + current); if (diff == 0) break; else if (diff < 0) right = current; else left = current; } while ((right - left) > 1); if (diff != 0) { /* * Check the last 1 or 2 elements... */ if ((diff = cups_compare_options(&key, options + left)) <= 0) current = left; else { diff = cups_compare_options(&key, options + right); current = right; } } /* * Return the closest destination and the difference... */ *rdiff = diff; return (current); } ippsample/cups/testraster.c0000644000175000017500000005055613240604116015070 0ustar tilltill/* * Raster test program routines for CUPS. * * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ /* * Include necessary headers... */ #include #include /* * Local functions... */ static int do_ras_file(const char *filename); static int do_raster_tests(cups_mode_t mode); static void print_changes(cups_page_header2_t *header, cups_page_header2_t *expected); /* * 'main()' - Test the raster functions. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line arguments */ { int errors = 0; /* Number of errors */ if (argc == 1) { errors += do_raster_tests(CUPS_RASTER_WRITE); errors += do_raster_tests(CUPS_RASTER_WRITE_COMPRESSED); errors += do_raster_tests(CUPS_RASTER_WRITE_PWG); errors += do_raster_tests(CUPS_RASTER_WRITE_APPLE); } else { int i; /* Looping var */ for (i = 1; i < argc; i ++) errors += do_ras_file(argv[i]); } return (errors != 0); } /* * 'do_ras_file()' - Test reading of a raster file. */ static int /* O - Number of errors */ do_ras_file(const char *filename) /* I - Filename */ { unsigned y; /* Looping vars */ int fd; /* File descriptor */ cups_raster_t *ras; /* Raster stream */ cups_page_header2_t header; /* Page header */ unsigned char *data; /* Raster data */ int errors = 0; /* Number of errors */ unsigned pages = 0; /* Number of pages */ if ((fd = open(filename, O_RDONLY)) < 0) { printf("%s: %s\n", filename, strerror(errno)); return (1); } if ((ras = cupsRasterOpen(fd, CUPS_RASTER_READ)) == NULL) { printf("%s: cupsRasterOpen failed.\n", filename); close(fd); return (1); } printf("%s:\n", filename); while (cupsRasterReadHeader2(ras, &header)) { pages ++; data = malloc(header.cupsBytesPerLine); printf(" Page %u: %ux%ux%u@%ux%udpi", pages, header.cupsWidth, header.cupsHeight, header.cupsBitsPerPixel, header.HWResolution[0], header.HWResolution[1]); fflush(stdout); for (y = 0; y < header.cupsHeight; y ++) if (cupsRasterReadPixels(ras, data, header.cupsBytesPerLine) < header.cupsBytesPerLine) break; if (y < header.cupsHeight) printf(" ERROR AT LINE %d\n", y); else putchar('\n'); free(data); } printf("EOF at %ld\n", (long)lseek(fd, SEEK_CUR, 0)); cupsRasterClose(ras); close(fd); return (errors); } /* * 'do_raster_tests()' - Test reading and writing of raster data. */ static int /* O - Number of errors */ do_raster_tests(cups_mode_t mode) /* O - Write mode */ { unsigned page, x, y, count;/* Looping vars */ FILE *fp; /* Raster file */ cups_raster_t *r; /* Raster stream */ cups_page_header2_t header, /* Page header */ expected; /* Expected page header */ unsigned char data[2048]; /* Raster data */ int errors = 0; /* Number of errors */ /* * Test writing... */ printf("cupsRasterOpen(%s): ", mode == CUPS_RASTER_WRITE ? "CUPS_RASTER_WRITE" : mode == CUPS_RASTER_WRITE_COMPRESSED ? "CUPS_RASTER_WRITE_COMPRESSED" : mode == CUPS_RASTER_WRITE_PWG ? "CUPS_RASTER_WRITE_PWG" : "CUPS_RASTER_WRITE_APPLE"); fflush(stdout); if ((fp = fopen("test.raster", "wb")) == NULL) { printf("FAIL (%s)\n", strerror(errno)); return (1); } if ((r = cupsRasterOpen(fileno(fp), mode)) == NULL) { printf("FAIL (%s)\n", strerror(errno)); fclose(fp); return (1); } puts("PASS"); for (page = 0; page < 4; page ++) { memset(&header, 0, sizeof(header)); header.cupsWidth = 256; header.cupsHeight = 256; header.cupsBytesPerLine = 256; header.HWResolution[0] = 64; header.HWResolution[1] = 64; header.PageSize[0] = 288; header.PageSize[1] = 288; header.cupsPageSize[0] = 288.0f; header.cupsPageSize[1] = 288.0f; if (page & 1) { header.cupsBytesPerLine *= 4; header.cupsColorSpace = CUPS_CSPACE_CMYK; header.cupsColorOrder = CUPS_ORDER_CHUNKED; header.cupsNumColors = 4; } else { header.cupsColorSpace = CUPS_CSPACE_W; header.cupsColorOrder = CUPS_ORDER_CHUNKED; header.cupsNumColors = 1; } if (page & 2) { header.cupsBytesPerLine *= 2; header.cupsBitsPerColor = 16; header.cupsBitsPerPixel = (page & 1) ? 64 : 16; } else { header.cupsBitsPerColor = 8; header.cupsBitsPerPixel = (page & 1) ? 32 : 8; } printf("cupsRasterWriteHeader2(page %d): ", page + 1); if (cupsRasterWriteHeader2(r, &header)) { puts("PASS"); } else { puts("FAIL"); errors ++; } fputs("cupsRasterWritePixels: ", stdout); fflush(stdout); memset(data, 0, header.cupsBytesPerLine); for (y = 0; y < 64; y ++) if (!cupsRasterWritePixels(r, data, header.cupsBytesPerLine)) break; if (y < 64) { puts("FAIL"); errors ++; } else { for (x = 0; x < header.cupsBytesPerLine; x ++) data[x] = (unsigned char)x; for (y = 0; y < 64; y ++) if (!cupsRasterWritePixels(r, data, header.cupsBytesPerLine)) break; if (y < 64) { puts("FAIL"); errors ++; } else { memset(data, 255, header.cupsBytesPerLine); for (y = 0; y < 64; y ++) if (!cupsRasterWritePixels(r, data, header.cupsBytesPerLine)) break; if (y < 64) { puts("FAIL"); errors ++; } else { for (x = 0; x < header.cupsBytesPerLine; x ++) data[x] = (unsigned char)(x / 4); for (y = 0; y < 64; y ++) if (!cupsRasterWritePixels(r, data, header.cupsBytesPerLine)) break; if (y < 64) { puts("FAIL"); errors ++; } else puts("PASS"); } } } } cupsRasterClose(r); fclose(fp); /* * Test reading... */ fputs("cupsRasterOpen(CUPS_RASTER_READ): ", stdout); fflush(stdout); if ((fp = fopen("test.raster", "rb")) == NULL) { printf("FAIL (%s)\n", strerror(errno)); return (1); } if ((r = cupsRasterOpen(fileno(fp), CUPS_RASTER_READ)) == NULL) { printf("FAIL (%s)\n", strerror(errno)); fclose(fp); return (1); } puts("PASS"); for (page = 0; page < 4; page ++) { memset(&expected, 0, sizeof(expected)); expected.cupsWidth = 256; expected.cupsHeight = 256; expected.cupsBytesPerLine = 256; expected.HWResolution[0] = 64; expected.HWResolution[1] = 64; expected.PageSize[0] = 288; expected.PageSize[1] = 288; if (mode != CUPS_RASTER_WRITE_PWG) { expected.cupsPageSize[0] = 288.0f; expected.cupsPageSize[1] = 288.0f; } if (mode >= CUPS_RASTER_WRITE_PWG) { strlcpy(expected.MediaClass, "PwgRaster", sizeof(expected.MediaClass)); expected.cupsInteger[7] = 0xffffff; } if (page & 1) { expected.cupsBytesPerLine *= 4; expected.cupsColorSpace = CUPS_CSPACE_CMYK; expected.cupsColorOrder = CUPS_ORDER_CHUNKED; expected.cupsNumColors = 4; } else { expected.cupsColorSpace = CUPS_CSPACE_W; expected.cupsColorOrder = CUPS_ORDER_CHUNKED; expected.cupsNumColors = 1; } if (page & 2) { expected.cupsBytesPerLine *= 2; expected.cupsBitsPerColor = 16; expected.cupsBitsPerPixel = (page & 1) ? 64 : 16; } else { expected.cupsBitsPerColor = 8; expected.cupsBitsPerPixel = (page & 1) ? 32 : 8; } printf("cupsRasterReadHeader2(page %d): ", page + 1); fflush(stdout); if (!cupsRasterReadHeader2(r, &header)) { puts("FAIL (read error)"); errors ++; break; } else if (memcmp(&header, &expected, sizeof(header))) { puts("FAIL (bad page header)"); errors ++; print_changes(&header, &expected); } else puts("PASS"); fputs("cupsRasterReadPixels: ", stdout); fflush(stdout); for (y = 0; y < 64; y ++) { if (!cupsRasterReadPixels(r, data, header.cupsBytesPerLine)) { puts("FAIL (read error)"); errors ++; break; } if (data[0] != 0 || memcmp(data, data + 1, header.cupsBytesPerLine - 1)) { printf("FAIL (raster line %d corrupt)\n", y); for (x = 0, count = 0; x < header.cupsBytesPerLine && count < 10; x ++) { if (data[x]) { count ++; if (count == 10) puts(" ..."); else printf(" %4u %02X (expected %02X)\n", x, data[x], 0); } } errors ++; break; } } if (y == 64) { for (y = 0; y < 64; y ++) { if (!cupsRasterReadPixels(r, data, header.cupsBytesPerLine)) { puts("FAIL (read error)"); errors ++; break; } for (x = 0; x < header.cupsBytesPerLine; x ++) if (data[x] != (x & 255)) break; if (x < header.cupsBytesPerLine) { printf("FAIL (raster line %d corrupt)\n", y + 64); for (x = 0, count = 0; x < header.cupsBytesPerLine && count < 10; x ++) { if (data[x] != (x & 255)) { count ++; if (count == 10) puts(" ..."); else printf(" %4u %02X (expected %02X)\n", x, data[x], x & 255); } } errors ++; break; } } if (y == 64) { for (y = 0; y < 64; y ++) { if (!cupsRasterReadPixels(r, data, header.cupsBytesPerLine)) { puts("FAIL (read error)"); errors ++; break; } if (data[0] != 255 || memcmp(data, data + 1, header.cupsBytesPerLine - 1)) { printf("fail (raster line %d corrupt)\n", y + 128); for (x = 0, count = 0; x < header.cupsBytesPerLine && count < 10; x ++) { if (data[x] != 255) { count ++; if (count == 10) puts(" ..."); else printf(" %4u %02X (expected %02X)\n", x, data[x], 255); } } errors ++; break; } } if (y == 64) { for (y = 0; y < 64; y ++) { if (!cupsRasterReadPixels(r, data, header.cupsBytesPerLine)) { puts("FAIL (read error)"); errors ++; break; } for (x = 0; x < header.cupsBytesPerLine; x ++) if (data[x] != ((x / 4) & 255)) break; if (x < header.cupsBytesPerLine) { printf("FAIL (raster line %d corrupt)\n", y + 192); for (x = 0, count = 0; x < header.cupsBytesPerLine && count < 10; x ++) { if (data[x] != ((x / 4) & 255)) { count ++; if (count == 10) puts(" ..."); else printf(" %4u %02X (expected %02X)\n", x, data[x], (x / 4) & 255); } } errors ++; break; } } if (y == 64) puts("PASS"); } } } } cupsRasterClose(r); fclose(fp); return (errors); } /* * 'print_changes()' - Print differences in the page header. */ static void print_changes( cups_page_header2_t *header, /* I - Actual page header */ cups_page_header2_t *expected) /* I - Expected page header */ { int i; /* Looping var */ if (strcmp(header->MediaClass, expected->MediaClass)) printf(" MediaClass (%s), expected (%s)\n", header->MediaClass, expected->MediaClass); if (strcmp(header->MediaColor, expected->MediaColor)) printf(" MediaColor (%s), expected (%s)\n", header->MediaColor, expected->MediaColor); if (strcmp(header->MediaType, expected->MediaType)) printf(" MediaType (%s), expected (%s)\n", header->MediaType, expected->MediaType); if (strcmp(header->OutputType, expected->OutputType)) printf(" OutputType (%s), expected (%s)\n", header->OutputType, expected->OutputType); if (header->AdvanceDistance != expected->AdvanceDistance) printf(" AdvanceDistance %d, expected %d\n", header->AdvanceDistance, expected->AdvanceDistance); if (header->AdvanceMedia != expected->AdvanceMedia) printf(" AdvanceMedia %d, expected %d\n", header->AdvanceMedia, expected->AdvanceMedia); if (header->Collate != expected->Collate) printf(" Collate %d, expected %d\n", header->Collate, expected->Collate); if (header->CutMedia != expected->CutMedia) printf(" CutMedia %d, expected %d\n", header->CutMedia, expected->CutMedia); if (header->Duplex != expected->Duplex) printf(" Duplex %d, expected %d\n", header->Duplex, expected->Duplex); if (header->HWResolution[0] != expected->HWResolution[0] || header->HWResolution[1] != expected->HWResolution[1]) printf(" HWResolution [%d %d], expected [%d %d]\n", header->HWResolution[0], header->HWResolution[1], expected->HWResolution[0], expected->HWResolution[1]); if (memcmp(header->ImagingBoundingBox, expected->ImagingBoundingBox, sizeof(header->ImagingBoundingBox))) printf(" ImagingBoundingBox [%d %d %d %d], expected [%d %d %d %d]\n", header->ImagingBoundingBox[0], header->ImagingBoundingBox[1], header->ImagingBoundingBox[2], header->ImagingBoundingBox[3], expected->ImagingBoundingBox[0], expected->ImagingBoundingBox[1], expected->ImagingBoundingBox[2], expected->ImagingBoundingBox[3]); if (header->InsertSheet != expected->InsertSheet) printf(" InsertSheet %d, expected %d\n", header->InsertSheet, expected->InsertSheet); if (header->Jog != expected->Jog) printf(" Jog %d, expected %d\n", header->Jog, expected->Jog); if (header->LeadingEdge != expected->LeadingEdge) printf(" LeadingEdge %d, expected %d\n", header->LeadingEdge, expected->LeadingEdge); if (header->Margins[0] != expected->Margins[0] || header->Margins[1] != expected->Margins[1]) printf(" Margins [%d %d], expected [%d %d]\n", header->Margins[0], header->Margins[1], expected->Margins[0], expected->Margins[1]); if (header->ManualFeed != expected->ManualFeed) printf(" ManualFeed %d, expected %d\n", header->ManualFeed, expected->ManualFeed); if (header->MediaPosition != expected->MediaPosition) printf(" MediaPosition %d, expected %d\n", header->MediaPosition, expected->MediaPosition); if (header->MediaWeight != expected->MediaWeight) printf(" MediaWeight %d, expected %d\n", header->MediaWeight, expected->MediaWeight); if (header->MirrorPrint != expected->MirrorPrint) printf(" MirrorPrint %d, expected %d\n", header->MirrorPrint, expected->MirrorPrint); if (header->NegativePrint != expected->NegativePrint) printf(" NegativePrint %d, expected %d\n", header->NegativePrint, expected->NegativePrint); if (header->NumCopies != expected->NumCopies) printf(" NumCopies %d, expected %d\n", header->NumCopies, expected->NumCopies); if (header->Orientation != expected->Orientation) printf(" Orientation %d, expected %d\n", header->Orientation, expected->Orientation); if (header->OutputFaceUp != expected->OutputFaceUp) printf(" OutputFaceUp %d, expected %d\n", header->OutputFaceUp, expected->OutputFaceUp); if (header->PageSize[0] != expected->PageSize[0] || header->PageSize[1] != expected->PageSize[1]) printf(" PageSize [%d %d], expected [%d %d]\n", header->PageSize[0], header->PageSize[1], expected->PageSize[0], expected->PageSize[1]); if (header->Separations != expected->Separations) printf(" Separations %d, expected %d\n", header->Separations, expected->Separations); if (header->TraySwitch != expected->TraySwitch) printf(" TraySwitch %d, expected %d\n", header->TraySwitch, expected->TraySwitch); if (header->Tumble != expected->Tumble) printf(" Tumble %d, expected %d\n", header->Tumble, expected->Tumble); if (header->cupsWidth != expected->cupsWidth) printf(" cupsWidth %d, expected %d\n", header->cupsWidth, expected->cupsWidth); if (header->cupsHeight != expected->cupsHeight) printf(" cupsHeight %d, expected %d\n", header->cupsHeight, expected->cupsHeight); if (header->cupsMediaType != expected->cupsMediaType) printf(" cupsMediaType %d, expected %d\n", header->cupsMediaType, expected->cupsMediaType); if (header->cupsBitsPerColor != expected->cupsBitsPerColor) printf(" cupsBitsPerColor %d, expected %d\n", header->cupsBitsPerColor, expected->cupsBitsPerColor); if (header->cupsBitsPerPixel != expected->cupsBitsPerPixel) printf(" cupsBitsPerPixel %d, expected %d\n", header->cupsBitsPerPixel, expected->cupsBitsPerPixel); if (header->cupsBytesPerLine != expected->cupsBytesPerLine) printf(" cupsBytesPerLine %d, expected %d\n", header->cupsBytesPerLine, expected->cupsBytesPerLine); if (header->cupsColorOrder != expected->cupsColorOrder) printf(" cupsColorOrder %d, expected %d\n", header->cupsColorOrder, expected->cupsColorOrder); if (header->cupsColorSpace != expected->cupsColorSpace) printf(" cupsColorSpace %d, expected %d\n", header->cupsColorSpace, expected->cupsColorSpace); if (header->cupsCompression != expected->cupsCompression) printf(" cupsCompression %d, expected %d\n", header->cupsCompression, expected->cupsCompression); if (header->cupsRowCount != expected->cupsRowCount) printf(" cupsRowCount %d, expected %d\n", header->cupsRowCount, expected->cupsRowCount); if (header->cupsRowFeed != expected->cupsRowFeed) printf(" cupsRowFeed %d, expected %d\n", header->cupsRowFeed, expected->cupsRowFeed); if (header->cupsRowStep != expected->cupsRowStep) printf(" cupsRowStep %d, expected %d\n", header->cupsRowStep, expected->cupsRowStep); if (header->cupsNumColors != expected->cupsNumColors) printf(" cupsNumColors %d, expected %d\n", header->cupsNumColors, expected->cupsNumColors); if (fabs(header->cupsBorderlessScalingFactor - expected->cupsBorderlessScalingFactor) > 0.001) printf(" cupsBorderlessScalingFactor %g, expected %g\n", header->cupsBorderlessScalingFactor, expected->cupsBorderlessScalingFactor); if (fabs(header->cupsPageSize[0] - expected->cupsPageSize[0]) > 0.001 || fabs(header->cupsPageSize[1] - expected->cupsPageSize[1]) > 0.001) printf(" cupsPageSize [%g %g], expected [%g %g]\n", header->cupsPageSize[0], header->cupsPageSize[1], expected->cupsPageSize[0], expected->cupsPageSize[1]); if (fabs(header->cupsImagingBBox[0] - expected->cupsImagingBBox[0]) > 0.001 || fabs(header->cupsImagingBBox[1] - expected->cupsImagingBBox[1]) > 0.001 || fabs(header->cupsImagingBBox[2] - expected->cupsImagingBBox[2]) > 0.001 || fabs(header->cupsImagingBBox[3] - expected->cupsImagingBBox[3]) > 0.001) printf(" cupsImagingBBox [%g %g %g %g], expected [%g %g %g %g]\n", header->cupsImagingBBox[0], header->cupsImagingBBox[1], header->cupsImagingBBox[2], header->cupsImagingBBox[3], expected->cupsImagingBBox[0], expected->cupsImagingBBox[1], expected->cupsImagingBBox[2], expected->cupsImagingBBox[3]); for (i = 0; i < 16; i ++) if (header->cupsInteger[i] != expected->cupsInteger[i]) printf(" cupsInteger%d %d, expected %d\n", i, header->cupsInteger[i], expected->cupsInteger[i]); for (i = 0; i < 16; i ++) if (fabs(header->cupsReal[i] - expected->cupsReal[i]) > 0.001) printf(" cupsReal%d %g, expected %g\n", i, header->cupsReal[i], expected->cupsReal[i]); for (i = 0; i < 16; i ++) if (strcmp(header->cupsString[i], expected->cupsString[i])) printf(" cupsString%d (%s), expected (%s)\n", i, header->cupsString[i], expected->cupsString[i]); if (strcmp(header->cupsMarkerType, expected->cupsMarkerType)) printf(" cupsMarkerType (%s), expected (%s)\n", header->cupsMarkerType, expected->cupsMarkerType); if (strcmp(header->cupsRenderingIntent, expected->cupsRenderingIntent)) printf(" cupsRenderingIntent (%s), expected (%s)\n", header->cupsRenderingIntent, expected->cupsRenderingIntent); if (strcmp(header->cupsPageSizeName, expected->cupsPageSizeName)) printf(" cupsPageSizeName (%s), expected (%s)\n", header->cupsPageSizeName, expected->cupsPageSizeName); } ippsample/cups/debug.c0000644000175000017500000003173213240604116013751 0ustar tilltill/* * Debugging functions for CUPS. * * Copyright 2008-2015 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #include "thread-private.h" #ifdef WIN32 # include # include # include # define getpid (int)GetCurrentProcessId int /* O - 0 on success, -1 on failure */ _cups_gettimeofday(struct timeval *tv, /* I - Timeval struct */ void *tz) /* I - Timezone */ { struct _timeb timebuffer; /* Time buffer struct */ _ftime(&timebuffer); tv->tv_sec = (long)timebuffer.time; tv->tv_usec = timebuffer.millitm * 1000; return 0; } #else # include # include #endif /* WIN32 */ #include #include /* * Globals... */ int _cups_debug_fd = -1; /* Debug log file descriptor */ int _cups_debug_level = 1; /* Log level (0 to 9) */ #ifdef DEBUG /* * Local globals... */ static regex_t *debug_filter = NULL; /* Filter expression for messages */ static int debug_init = 0; /* Did we initialize debugging? */ static _cups_mutex_t debug_init_mutex = _CUPS_MUTEX_INITIALIZER, /* Mutex to control initialization */ debug_log_mutex = _CUPS_MUTEX_INITIALIZER; /* Mutex to serialize log entries */ /* * 'debug_thread_id()' - Return an integer representing the current thread. */ static int /* O - Local thread ID */ debug_thread_id(void) { _cups_globals_t *cg = _cupsGlobals(); /* Global data */ return (cg->thread_id); } /* * '_cups_debug_printf()' - Write a formatted line to the log. */ void DLLExport _cups_debug_printf(const char *format, /* I - Printf-style format string */ ...) /* I - Additional arguments as needed */ { va_list ap; /* Pointer to arguments */ struct timeval curtime; /* Current time */ char buffer[2048]; /* Output buffer */ ssize_t bytes; /* Number of bytes in buffer */ int level; /* Log level in message */ /* * See if we need to do any logging... */ if (!debug_init) _cups_debug_set(getenv("CUPS_DEBUG_LOG"), getenv("CUPS_DEBUG_LEVEL"), getenv("CUPS_DEBUG_FILTER"), 0); if (_cups_debug_fd < 0) return; /* * Filter as needed... */ if (isdigit(format[0])) level = *format++ - '0'; else level = 0; if (level > _cups_debug_level) return; if (debug_filter) { int result; /* Filter result */ _cupsMutexLock(&debug_init_mutex); result = regexec(debug_filter, format, 0, NULL, 0); _cupsMutexUnlock(&debug_init_mutex); if (result) return; } /* * Format the message... */ gettimeofday(&curtime, NULL); snprintf(buffer, sizeof(buffer), "T%03d %02d:%02d:%02d.%03d ", debug_thread_id(), (int)((curtime.tv_sec / 3600) % 24), (int)((curtime.tv_sec / 60) % 60), (int)(curtime.tv_sec % 60), (int)(curtime.tv_usec / 1000)); va_start(ap, format); bytes = _cups_safe_vsnprintf(buffer + 19, sizeof(buffer) - 20, format, ap) + 19; va_end(ap); if ((size_t)bytes >= (sizeof(buffer) - 1)) { buffer[sizeof(buffer) - 2] = '\n'; bytes = sizeof(buffer) - 1; } else if (buffer[bytes - 1] != '\n') { buffer[bytes++] = '\n'; buffer[bytes] = '\0'; } /* * Write it out... */ _cupsMutexLock(&debug_log_mutex); write(_cups_debug_fd, buffer, (size_t)bytes); _cupsMutexUnlock(&debug_log_mutex); } /* * '_cups_debug_puts()' - Write a single line to the log. */ void DLLExport _cups_debug_puts(const char *s) /* I - String to output */ { struct timeval curtime; /* Current time */ char buffer[2048]; /* Output buffer */ ssize_t bytes; /* Number of bytes in buffer */ int level; /* Log level in message */ /* * See if we need to do any logging... */ if (!debug_init) _cups_debug_set(getenv("CUPS_DEBUG_LOG"), getenv("CUPS_DEBUG_LEVEL"), getenv("CUPS_DEBUG_FILTER"), 0); if (_cups_debug_fd < 0) return; /* * Filter as needed... */ if (isdigit(s[0])) level = *s++ - '0'; else level = 0; if (level > _cups_debug_level) return; if (debug_filter) { int result; /* Filter result */ _cupsMutexLock(&debug_init_mutex); result = regexec(debug_filter, s, 0, NULL, 0); _cupsMutexUnlock(&debug_init_mutex); if (result) return; } /* * Format the message... */ gettimeofday(&curtime, NULL); bytes = snprintf(buffer, sizeof(buffer), "T%03d %02d:%02d:%02d.%03d %s", debug_thread_id(), (int)((curtime.tv_sec / 3600) % 24), (int)((curtime.tv_sec / 60) % 60), (int)(curtime.tv_sec % 60), (int)(curtime.tv_usec / 1000), s); if ((size_t)bytes >= (sizeof(buffer) - 1)) { buffer[sizeof(buffer) - 2] = '\n'; bytes = sizeof(buffer) - 1; } else if (buffer[bytes - 1] != '\n') { buffer[bytes++] = '\n'; buffer[bytes] = '\0'; } /* * Write it out... */ _cupsMutexLock(&debug_log_mutex); write(_cups_debug_fd, buffer, (size_t)bytes); _cupsMutexUnlock(&debug_log_mutex); } /* * '_cups_debug_set()' - Enable or disable debug logging. */ void DLLExport _cups_debug_set(const char *logfile, /* I - Log file or NULL */ const char *level, /* I - Log level or NULL */ const char *filter, /* I - Filter string or NULL */ int force) /* I - Force initialization */ { _cupsMutexLock(&debug_init_mutex); if (!debug_init || force) { /* * Restore debug settings to defaults... */ if (_cups_debug_fd != -1) { close(_cups_debug_fd); _cups_debug_fd = -1; } if (debug_filter) { regfree((regex_t *)debug_filter); debug_filter = NULL; } _cups_debug_level = 1; /* * Open logs, set log levels, etc. */ if (!logfile) _cups_debug_fd = -1; else if (!strcmp(logfile, "-")) _cups_debug_fd = 2; else { char buffer[1024]; /* Filename buffer */ snprintf(buffer, sizeof(buffer), logfile, getpid()); if (buffer[0] == '+') _cups_debug_fd = open(buffer + 1, O_WRONLY | O_APPEND | O_CREAT, 0644); else _cups_debug_fd = open(buffer, O_WRONLY | O_TRUNC | O_CREAT, 0644); } if (level) _cups_debug_level = atoi(level); if (filter) { if ((debug_filter = (regex_t *)calloc(1, sizeof(regex_t))) == NULL) fputs("Unable to allocate memory for CUPS_DEBUG_FILTER - results not " "filtered!\n", stderr); else if (regcomp(debug_filter, filter, REG_EXTENDED)) { fputs("Bad regular expression in CUPS_DEBUG_FILTER - results not " "filtered!\n", stderr); free(debug_filter); debug_filter = NULL; } } debug_init = 1; } _cupsMutexUnlock(&debug_init_mutex); } #endif /* DEBUG */ /* * '_cups_safe_vsnprintf()' - Format a string into a fixed size buffer, * quoting special characters. */ ssize_t /* O - Number of bytes formatted */ _cups_safe_vsnprintf( char *buffer, /* O - Output buffer */ size_t bufsize, /* O - Size of output buffer */ const char *format, /* I - printf-style format string */ va_list ap) /* I - Pointer to additional arguments */ { char *bufptr, /* Pointer to position in buffer */ *bufend, /* Pointer to end of buffer */ size, /* Size character (h, l, L) */ type; /* Format type character */ int width, /* Width of field */ prec; /* Number of characters of precision */ char tformat[100], /* Temporary format string for snprintf() */ *tptr, /* Pointer into temporary format */ temp[1024]; /* Buffer for formatted numbers */ char *s; /* Pointer to string */ ssize_t bytes; /* Total number of bytes needed */ if (!buffer || bufsize < 2 || !format) return (-1); /* * Loop through the format string, formatting as needed... */ bufptr = buffer; bufend = buffer + bufsize - 1; bytes = 0; while (*format) { if (*format == '%') { tptr = tformat; *tptr++ = *format++; if (*format == '%') { if (bufptr < bufend) *bufptr++ = *format; bytes ++; format ++; continue; } else if (strchr(" -+#\'", *format)) *tptr++ = *format++; if (*format == '*') { /* * Get width from argument... */ format ++; width = va_arg(ap, int); snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", width); tptr += strlen(tptr); } else { width = 0; while (isdigit(*format & 255)) { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; width = width * 10 + *format++ - '0'; } } if (*format == '.') { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; format ++; if (*format == '*') { /* * Get precision from argument... */ format ++; prec = va_arg(ap, int); snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", prec); tptr += strlen(tptr); } else { prec = 0; while (isdigit(*format & 255)) { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; prec = prec * 10 + *format++ - '0'; } } } if (*format == 'l' && format[1] == 'l') { size = 'L'; if (tptr < (tformat + sizeof(tformat) - 2)) { *tptr++ = 'l'; *tptr++ = 'l'; } format += 2; } else if (*format == 'h' || *format == 'l' || *format == 'L') { if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; size = *format++; } else size = 0; if (!*format) break; if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; type = *format++; *tptr = '\0'; switch (type) { case 'E' : /* Floating point formats */ case 'G' : case 'e' : case 'f' : case 'g' : if ((size_t)(width + 2) > sizeof(temp)) break; snprintf(temp, sizeof(temp), tformat, va_arg(ap, double)); bytes += (int)strlen(temp); if (bufptr) { strlcpy(bufptr, temp, (size_t)(bufend - bufptr)); bufptr += strlen(bufptr); } break; case 'B' : /* Integer formats */ case 'X' : case 'b' : case 'd' : case 'i' : case 'o' : case 'u' : case 'x' : if ((size_t)(width + 2) > sizeof(temp)) break; # ifdef HAVE_LONG_LONG if (size == 'L') snprintf(temp, sizeof(temp), tformat, va_arg(ap, long long)); else # endif /* HAVE_LONG_LONG */ if (size == 'l') snprintf(temp, sizeof(temp), tformat, va_arg(ap, long)); else snprintf(temp, sizeof(temp), tformat, va_arg(ap, int)); bytes += (int)strlen(temp); if (bufptr) { strlcpy(bufptr, temp, (size_t)(bufend - bufptr)); bufptr += strlen(bufptr); } break; case 'p' : /* Pointer value */ if ((size_t)(width + 2) > sizeof(temp)) break; snprintf(temp, sizeof(temp), tformat, va_arg(ap, void *)); bytes += (int)strlen(temp); if (bufptr) { strlcpy(bufptr, temp, (size_t)(bufend - bufptr)); bufptr += strlen(bufptr); } break; case 'c' : /* Character or character array */ bytes += width; if (bufptr) { if (width <= 1) *bufptr++ = (char)va_arg(ap, int); else { if ((bufptr + width) > bufend) width = (int)(bufend - bufptr); memcpy(bufptr, va_arg(ap, char *), (size_t)width); bufptr += width; } } break; case 's' : /* String */ if ((s = va_arg(ap, char *)) == NULL) s = "(null)"; /* * Copy the C string, replacing control chars and \ with * C character escapes... */ for (bufend --; *s && bufptr < bufend; s ++) { if (*s == '\n') { *bufptr++ = '\\'; *bufptr++ = 'n'; bytes += 2; } else if (*s == '\r') { *bufptr++ = '\\'; *bufptr++ = 'r'; bytes += 2; } else if (*s == '\t') { *bufptr++ = '\\'; *bufptr++ = 't'; bytes += 2; } else if (*s == '\\') { *bufptr++ = '\\'; *bufptr++ = '\\'; bytes += 2; } else if (*s == '\'') { *bufptr++ = '\\'; *bufptr++ = '\''; bytes += 2; } else if (*s == '\"') { *bufptr++ = '\\'; *bufptr++ = '\"'; bytes += 2; } else if ((*s & 255) < ' ') { if ((bufptr + 2) >= bufend) break; *bufptr++ = '\\'; *bufptr++ = '0'; *bufptr++ = '0' + *s / 8; *bufptr++ = '0' + (*s & 7); bytes += 4; } else { *bufptr++ = *s; bytes ++; } } bufend ++; break; case 'n' : /* Output number of chars so far */ *(va_arg(ap, int *)) = (int)bytes; break; } } else { bytes ++; if (bufptr < bufend) *bufptr++ = *format; format ++; } } /* * Nul-terminate the string and return the number of characters needed. */ *bufptr = '\0'; return (bytes); } ippsample/cups/testarray.c0000644000175000017500000002470013240604116014676 0ustar tilltill/* * Array test program for CUPS. * * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "string-private.h" #include "debug-private.h" #include "array-private.h" #include "dir.h" /* * Local functions... */ static double get_seconds(void); static int load_words(const char *filename, cups_array_t *array); /* * 'main()' - Main entry. */ int /* O - Exit status */ main(void) { int i; /* Looping var */ cups_array_t *array, /* Test array */ *dup_array; /* Duplicate array */ int status; /* Exit status */ char *text; /* Text from array */ char word[256]; /* Word from file */ double start, /* Start time */ end; /* End time */ cups_dir_t *dir; /* Current directory */ cups_dentry_t *dent; /* Directory entry */ char *saved[32]; /* Saved entries */ void *data; /* User data for arrays */ /* * No errors so far... */ status = 0; /* * cupsArrayNew() */ fputs("cupsArrayNew: ", stdout); data = (void *)"testarray"; array = cupsArrayNew((cups_array_func_t)strcmp, data); if (array) puts("PASS"); else { puts("FAIL (returned NULL, expected pointer)"); status ++; } /* * cupsArrayUserData() */ fputs("cupsArrayUserData: ", stdout); if (cupsArrayUserData(array) == data) puts("PASS"); else { printf("FAIL (returned %p instead of %p!)\n", cupsArrayUserData(array), data); status ++; } /* * cupsArrayAdd() */ fputs("cupsArrayAdd: ", stdout); if (!cupsArrayAdd(array, strdup("One Fish"))) { puts("FAIL (\"One Fish\")"); status ++; } else { if (!cupsArrayAdd(array, strdup("Two Fish"))) { puts("FAIL (\"Two Fish\")"); status ++; } else { if (!cupsArrayAdd(array, strdup("Red Fish"))) { puts("FAIL (\"Red Fish\")"); status ++; } else { if (!cupsArrayAdd(array, strdup("Blue Fish"))) { puts("FAIL (\"Blue Fish\")"); status ++; } else puts("PASS"); } } } /* * cupsArrayCount() */ fputs("cupsArrayCount: ", stdout); if (cupsArrayCount(array) == 4) puts("PASS"); else { printf("FAIL (returned %d, expected 4)\n", cupsArrayCount(array)); status ++; } /* * cupsArrayFirst() */ fputs("cupsArrayFirst: ", stdout); if ((text = (char *)cupsArrayFirst(array)) != NULL && !strcmp(text, "Blue Fish")) puts("PASS"); else { printf("FAIL (returned \"%s\", expected \"Blue Fish\")\n", text); status ++; } /* * cupsArrayNext() */ fputs("cupsArrayNext: ", stdout); if ((text = (char *)cupsArrayNext(array)) != NULL && !strcmp(text, "One Fish")) puts("PASS"); else { printf("FAIL (returned \"%s\", expected \"One Fish\")\n", text); status ++; } /* * cupsArrayLast() */ fputs("cupsArrayLast: ", stdout); if ((text = (char *)cupsArrayLast(array)) != NULL && !strcmp(text, "Two Fish")) puts("PASS"); else { printf("FAIL (returned \"%s\", expected \"Two Fish\")\n", text); status ++; } /* * cupsArrayPrev() */ fputs("cupsArrayPrev: ", stdout); if ((text = (char *)cupsArrayPrev(array)) != NULL && !strcmp(text, "Red Fish")) puts("PASS"); else { printf("FAIL (returned \"%s\", expected \"Red Fish\")\n", text); status ++; } /* * cupsArrayFind() */ fputs("cupsArrayFind: ", stdout); if ((text = (char *)cupsArrayFind(array, (void *)"One Fish")) != NULL && !strcmp(text, "One Fish")) puts("PASS"); else { printf("FAIL (returned \"%s\", expected \"One Fish\")\n", text); status ++; } /* * cupsArrayCurrent() */ fputs("cupsArrayCurrent: ", stdout); if ((text = (char *)cupsArrayCurrent(array)) != NULL && !strcmp(text, "One Fish")) puts("PASS"); else { printf("FAIL (returned \"%s\", expected \"One Fish\")\n", text); status ++; } /* * cupsArrayDup() */ fputs("cupsArrayDup: ", stdout); if ((dup_array = cupsArrayDup(array)) != NULL && cupsArrayCount(dup_array) == 4) puts("PASS"); else { printf("FAIL (returned %p with %d elements, expected pointer with 4 elements)\n", (void *)dup_array, cupsArrayCount(dup_array)); status ++; } /* * cupsArrayRemove() */ fputs("cupsArrayRemove: ", stdout); if (cupsArrayRemove(array, (void *)"One Fish") && cupsArrayCount(array) == 3) puts("PASS"); else { printf("FAIL (returned 0 with %d elements, expected 1 with 4 elements)\n", cupsArrayCount(array)); status ++; } /* * cupsArrayClear() */ fputs("cupsArrayClear: ", stdout); cupsArrayClear(array); if (cupsArrayCount(array) == 0) puts("PASS"); else { printf("FAIL (%d elements, expected 0 elements)\n", cupsArrayCount(array)); status ++; } /* * Now load this source file and grab all of the unique words... */ fputs("Load unique words: ", stdout); fflush(stdout); start = get_seconds(); if ((dir = cupsDirOpen(".")) == NULL) { puts("FAIL (cupsDirOpen failed)"); status ++; } else { while ((dent = cupsDirRead(dir)) != NULL) { i = (int)strlen(dent->filename) - 2; if (i > 0 && dent->filename[i] == '.' && (dent->filename[i + 1] == 'c' || dent->filename[i + 1] == 'h')) load_words(dent->filename, array); } cupsDirClose(dir); end = get_seconds(); printf("%d words in %.3f seconds (%.0f words/sec), ", cupsArrayCount(array), end - start, cupsArrayCount(array) / (end - start)); fflush(stdout); for (text = (char *)cupsArrayFirst(array); text;) { /* * Copy this word to the word buffer (safe because we strdup'd from * the same buffer in the first place... :) */ strlcpy(word, text, sizeof(word)); /* * Grab the next word and compare... */ if ((text = (char *)cupsArrayNext(array)) == NULL) break; if (strcmp(word, text) >= 0) break; } if (text) { printf("FAIL (\"%s\" >= \"%s\"!)\n", word, text); status ++; } else puts("PASS"); } /* * Test deleting with iteration... */ fputs("Delete While Iterating: ", stdout); text = (char *)cupsArrayFirst(array); cupsArrayRemove(array, text); free(text); text = (char *)cupsArrayNext(array); if (!text) { puts("FAIL (cupsArrayNext returned NULL!)"); status ++; } else puts("PASS"); /* * Test save/restore... */ fputs("cupsArraySave: ", stdout); for (i = 0, text = (char *)cupsArrayFirst(array); i < 32; i ++, text = (char *)cupsArrayNext(array)) { saved[i] = text; if (!cupsArraySave(array)) break; } if (i < 32) printf("FAIL (depth = %d)\n", i); else puts("PASS"); fputs("cupsArrayRestore: ", stdout); while (i > 0) { i --; text = cupsArrayRestore(array); if (text != saved[i]) break; } if (i) printf("FAIL (depth = %d)\n", i); else puts("PASS"); /* * Delete the arrays... */ cupsArrayDelete(array); cupsArrayDelete(dup_array); /* * Test the array with string functions... */ fputs("_cupsArrayNewStrings(\" \\t\\nfoo bar\\tboo\\nfar\", ' '): ", stdout); array = _cupsArrayNewStrings(" \t\nfoo bar\tboo\nfar", ' '); if (!array) { status = 1; puts("FAIL (unable to create array)"); } else if (cupsArrayCount(array) != 4) { status = 1; printf("FAIL (got %d elements, expected 4)\n", cupsArrayCount(array)); } else if (strcmp(text = (char *)cupsArrayFirst(array), "bar")) { status = 1; printf("FAIL (first element \"%s\", expected \"bar\")\n", text); } else if (strcmp(text = (char *)cupsArrayNext(array), "boo")) { status = 1; printf("FAIL (first element \"%s\", expected \"boo\")\n", text); } else if (strcmp(text = (char *)cupsArrayNext(array), "far")) { status = 1; printf("FAIL (first element \"%s\", expected \"far\")\n", text); } else if (strcmp(text = (char *)cupsArrayNext(array), "foo")) { status = 1; printf("FAIL (first element \"%s\", expected \"foo\")\n", text); } else puts("PASS"); fputs("_cupsArrayAddStrings(array, \"foo2,bar2\", ','): ", stdout); _cupsArrayAddStrings(array, "foo2,bar2", ','); if (cupsArrayCount(array) != 6) { status = 1; printf("FAIL (got %d elements, expected 6)\n", cupsArrayCount(array)); } else if (strcmp(text = (char *)cupsArrayFirst(array), "bar")) { status = 1; printf("FAIL (first element \"%s\", expected \"bar\")\n", text); } else if (strcmp(text = (char *)cupsArrayNext(array), "bar2")) { status = 1; printf("FAIL (first element \"%s\", expected \"bar2\")\n", text); } else if (strcmp(text = (char *)cupsArrayNext(array), "boo")) { status = 1; printf("FAIL (first element \"%s\", expected \"boo\")\n", text); } else if (strcmp(text = (char *)cupsArrayNext(array), "far")) { status = 1; printf("FAIL (first element \"%s\", expected \"far\")\n", text); } else if (strcmp(text = (char *)cupsArrayNext(array), "foo")) { status = 1; printf("FAIL (first element \"%s\", expected \"foo\")\n", text); } else if (strcmp(text = (char *)cupsArrayNext(array), "foo2")) { status = 1; printf("FAIL (first element \"%s\", expected \"foo2\")\n", text); } else puts("PASS"); cupsArrayDelete(array); /* * Summarize the results and return... */ if (!status) puts("\nALL TESTS PASSED!"); else printf("\n%d TEST(S) FAILED!\n", status); return (status); } /* * 'get_seconds()' - Get the current time in seconds... */ #ifdef WIN32 # include static double get_seconds(void) { } #else # include static double get_seconds(void) { struct timeval curtime; /* Current time */ gettimeofday(&curtime, NULL); return (curtime.tv_sec + 0.000001 * curtime.tv_usec); } #endif /* WIN32 */ /* * 'load_words()' - Load words from a file. */ static int /* O - 1 on success, 0 on failure */ load_words(const char *filename, /* I - File to load */ cups_array_t *array) /* I - Array to add to */ { FILE *fp; /* Test file */ char word[256]; /* Word from file */ if ((fp = fopen(filename, "r")) == NULL) { perror(filename); return (0); } while (fscanf(fp, "%255s", word) == 1) { if (!cupsArrayFind(array, word)) cupsArrayAdd(array, strdup(word)); } fclose(fp); return (1); } ippsample/cups/pwg-media.c0000644000175000017500000011235113240604116014532 0ustar tilltill/* * PWG media name API implementation for CUPS. * * Copyright 2009-2017 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #include /* * Local macros... */ #define _PWG_MEDIA_IN(p,l,a,x,y) {p, l, a, (int)(x * 2540), (int)(y * 2540)} #define _PWG_MEDIA_MM(p,l,a,x,y) {p, l, a, (int)(x * 100), (int)(y * 100)} /* * Local functions... */ static int pwg_compare_legacy(pwg_media_t *a, pwg_media_t *b); static int pwg_compare_pwg(pwg_media_t *a, pwg_media_t *b); static int pwg_compare_ppd(pwg_media_t *a, pwg_media_t *b); static char *pwg_format_inches(char *buf, size_t bufsize, int val); static char *pwg_format_millimeters(char *buf, size_t bufsize, int val); static int pwg_scan_measurement(const char *buf, char **bufptr, int numer, int denom); /* * Local globals... */ static pwg_media_t const cups_pwg_media[] = { /* Media size lookup table */ /* North American Standard Sheet Media Sizes */ _PWG_MEDIA_IN("na_index-3x5_3x5in", NULL, "3x5", 3, 5), _PWG_MEDIA_IN("na_personal_3.625x6.5in", NULL, "EnvPersonal", 3.625, 6.5), _PWG_MEDIA_IN("na_monarch_3.875x7.5in", "monarch-envelope", "EnvMonarch", 3.875, 7.5), _PWG_MEDIA_IN("na_number-9_3.875x8.875in", "na-number-9-envelope", "Env9", 3.875, 8.875), _PWG_MEDIA_IN("na_index-4x6_4x6in", NULL, "4x6", 4, 6), _PWG_MEDIA_IN("na_number-10_4.125x9.5in", "na-number-10-envelope", "Env10", 4.125, 9.5), _PWG_MEDIA_IN("na_a2_4.375x5.75in", NULL, "EnvA2", 4.375, 5.75), _PWG_MEDIA_IN("na_number-11_4.5x10.375in", NULL, "Env11", 4.5, 10.375), _PWG_MEDIA_IN("na_number-12_4.75x11in", NULL, "Env12", 4.75, 11), _PWG_MEDIA_IN("na_5x7_5x7in", NULL, "5x7", 5, 7), _PWG_MEDIA_IN("na_index-5x8_5x8in", NULL, "5x8", 5, 8), _PWG_MEDIA_IN("na_number-14_5x11.5in", NULL, "Env14", 5, 11.5), _PWG_MEDIA_IN("na_invoice_5.5x8.5in", "invoice", "Statement", 5.5, 8.5), _PWG_MEDIA_IN("na_index-4x6-ext_6x8in", NULL, "6x8", 6, 8), _PWG_MEDIA_IN("na_6x9_6x9in", "na-6x9-envelope", "6x9", 6, 9), _PWG_MEDIA_IN("na_c5_6.5x9.5in", NULL, "6.5x9.5", 6.5, 9.5), _PWG_MEDIA_IN("na_7x9_7x9in", "na-7x9-envelope", "7x9", 7, 9), _PWG_MEDIA_IN("na_executive_7.25x10.5in", "executive", "Executive", 7.25, 10.5), _PWG_MEDIA_IN("na_govt-letter_8x10in", "na-8x10", "8x10", 8, 10), _PWG_MEDIA_IN("na_govt-legal_8x13in", NULL, "8x13", 8, 13), _PWG_MEDIA_IN("na_quarto_8.5x10.83in", "quarto", "Quarto", 8.5, 10.83), _PWG_MEDIA_IN("na_letter_8.5x11in", "na-letter", "Letter", 8.5, 11), _PWG_MEDIA_IN("na_fanfold-eur_8.5x12in", NULL, "FanFoldGerman", 8.5, 12), _PWG_MEDIA_IN("na_letter-plus_8.5x12.69in", NULL, "LetterPlus", 8.5, 12.69), _PWG_MEDIA_IN("na_foolscap_8.5x13in", NULL, "FanFoldGermanLegal", 8.5, 13), _PWG_MEDIA_IN("na_oficio_8.5x13.4in", NULL, "Oficio", 8.5, 13.4), _PWG_MEDIA_IN("na_legal_8.5x14in", "na-legal", "Legal", 8.5, 14), _PWG_MEDIA_IN("na_super-a_8.94x14in", NULL, "SuperA", 8.94, 14), _PWG_MEDIA_IN("na_9x11_9x11in", "na-9x11-envelope", "9x11", 9, 11), _PWG_MEDIA_IN("na_arch-a_9x12in", "arch-a", "ARCHA", 9, 12), _PWG_MEDIA_IN("na_letter-extra_9.5x12in", NULL, "LetterExtra", 9.5, 12), _PWG_MEDIA_IN("na_legal-extra_9.5x15in", NULL, "LegalExtra", 9.5, 15), _PWG_MEDIA_IN("na_10x11_10x11in", NULL, "10x11", 10, 11), _PWG_MEDIA_IN("na_10x13_10x13in", "na-10x13-envelope", "10x13", 10, 13), _PWG_MEDIA_IN("na_10x14_10x14in", "na-10x14-envelope", "10x14", 10, 14), _PWG_MEDIA_IN("na_10x15_10x15in", "na-10x15-envelope", "10x15", 10, 15), _PWG_MEDIA_IN("na_11x12_11x12in", NULL, "11x12", 11, 12), _PWG_MEDIA_IN("na_edp_11x14in", NULL, "11x14", 11, 14), _PWG_MEDIA_IN("na_fanfold-us_11x14.875in", NULL, "11x14.875", 11, 14.875), _PWG_MEDIA_IN("na_11x15_11x15in", NULL, "11x15", 11, 15), _PWG_MEDIA_IN("na_ledger_11x17in", "tabloid", "Tabloid", 11, 17), _PWG_MEDIA_IN("na_eur-edp_12x14in", NULL, NULL, 12, 14), _PWG_MEDIA_IN("na_arch-b_12x18in", "arch-b", "ARCHB", 12, 18), _PWG_MEDIA_IN("na_12x19_12x19in", NULL, "12x19", 12, 19), _PWG_MEDIA_IN("na_b-plus_12x19.17in", NULL, "SuperB", 12, 19.17), _PWG_MEDIA_IN("na_super-b_13x19in", "super-b", "13x19", 13, 19), _PWG_MEDIA_IN("na_c_17x22in", "c", "AnsiC", 17, 22), _PWG_MEDIA_IN("na_arch-c_18x24in", "arch-c", "ARCHC", 18, 24), _PWG_MEDIA_IN("na_d_22x34in", "d", "AnsiD", 22, 34), _PWG_MEDIA_IN("na_arch-d_24x36in", "arch-d", "ARCHD", 24, 36), _PWG_MEDIA_IN("asme_f_28x40in", "f", "28x40", 28, 40), _PWG_MEDIA_IN("na_wide-format_30x42in", NULL, "30x42", 30, 42), _PWG_MEDIA_IN("na_e_34x44in", "e", "AnsiE", 34, 44), _PWG_MEDIA_IN("na_arch-e_36x48in", "arch-e", "ARCHE", 36, 48), _PWG_MEDIA_IN("na_f_44x68in", NULL, "AnsiF", 44, 68), /* ISO Standard Sheet Media Sizes */ _PWG_MEDIA_MM("iso_a10_26x37mm", "iso-a10", "A10", 26, 37), _PWG_MEDIA_MM("iso_a9_37x52mm", "iso-a9", "A9", 37, 52), _PWG_MEDIA_MM("iso_a8_52x74mm", "iso-a8", "A8", 52, 74), _PWG_MEDIA_MM("iso_a7_74x105mm", "iso-a7", "A7", 74, 105), _PWG_MEDIA_MM("iso_a6_105x148mm", "iso-a6", "A6", 105, 148), _PWG_MEDIA_MM("iso_a5_148x210mm", "iso-a5", "A5", 148, 210), _PWG_MEDIA_MM("iso_a5-extra_174x235mm", NULL, "A5Extra", 174, 235), _PWG_MEDIA_MM("iso_a4_210x297mm", "iso-a4", "A4", 210, 297), _PWG_MEDIA_MM("iso_a4-tab_225x297mm", NULL, "A4Tab", 225, 297), _PWG_MEDIA_MM("iso_a4-extra_235.5x322.3mm", NULL, "A4Extra", 235.5, 322.3), _PWG_MEDIA_MM("iso_a3_297x420mm", "iso-a3", "A3", 297, 420), _PWG_MEDIA_MM("iso_a4x3_297x630mm", "iso-a4x3", "A4x3", 297, 630), _PWG_MEDIA_MM("iso_a4x4_297x841mm", "iso-a4x4", "A4x4", 297, 841), _PWG_MEDIA_MM("iso_a4x5_297x1051mm", "iso-a4x5", "A4x5", 297, 1051), _PWG_MEDIA_MM("iso_a4x6_297x1261mm", "iso-a4x6", "A4x6", 297, 1261), _PWG_MEDIA_MM("iso_a4x7_297x1471mm", "iso-a4x7", "A4x7", 297, 1471), _PWG_MEDIA_MM("iso_a4x8_297x1682mm", "iso-a4x8", "A4x8", 297, 1682), _PWG_MEDIA_MM("iso_a4x9_297x1892mm", "iso-a4x9", "A4x9", 297, 1892), _PWG_MEDIA_MM("iso_a3-extra_322x445mm", "iso-a3-extra", "A3Extra", 322, 445), _PWG_MEDIA_MM("iso_a2_420x594mm", "iso-a2", "A2", 420, 594), _PWG_MEDIA_MM("iso_a3x3_420x891mm", "iso-a3x3", "A3x3", 420, 891), _PWG_MEDIA_MM("iso_a3x4_420x1189mm", "iso-a3x4", "A3x4", 420, 1189), _PWG_MEDIA_MM("iso_a3x5_420x1486mm", "iso-a3x5", "A3x6", 420, 1486), _PWG_MEDIA_MM("iso_a3x6_420x1783mm", "iso-a3x6", "A3x6", 420, 1783), _PWG_MEDIA_MM("iso_a3x7_420x2080mm", "iso-a3x7", "A3x7", 420, 2080), _PWG_MEDIA_MM("iso_a1_594x841mm", "iso-a1", "A1", 594, 841), _PWG_MEDIA_MM("iso_a2x3_594x1261mm", "iso-a2x3", "A2x3", 594, 1261), _PWG_MEDIA_MM("iso_a2x4_594x1682mm", "iso-a2x4", "A2x4", 594, 1682), _PWG_MEDIA_MM("iso_a2x5_594x2102mm", "iso-a2x5", "A2x5", 594, 2102), _PWG_MEDIA_MM("iso_a0_841x1189mm", "iso-a0", "A0", 841, 1189), _PWG_MEDIA_MM("iso_a1x3_841x1783mm", "iso-a1x3", "A1x3", 841, 1783), _PWG_MEDIA_MM("iso_a1x4_841x2378mm", "iso-a1x4", "A1x4", 841, 2378), _PWG_MEDIA_MM("iso_2a0_1189x1682mm", NULL, "1189x1682mm", 1189, 1682), _PWG_MEDIA_MM("iso_a0x3_1189x2523mm", NULL, "A0x3", 1189, 2523), _PWG_MEDIA_MM("iso_b10_31x44mm", "iso-b10", "ISOB10", 31, 44), _PWG_MEDIA_MM("iso_b9_44x62mm", "iso-b9", "ISOB9", 44, 62), _PWG_MEDIA_MM("iso_b8_62x88mm", "iso-b8", "ISOB8", 62, 88), _PWG_MEDIA_MM("iso_b7_88x125mm", "iso-b7", "ISOB7", 88, 125), _PWG_MEDIA_MM("iso_b6_125x176mm", "iso-b6", "ISOB6", 125, 176), _PWG_MEDIA_MM("iso_b6c4_125x324mm", NULL, "125x324mm", 125, 324), _PWG_MEDIA_MM("iso_b5_176x250mm", "iso-b5", "ISOB5", 176, 250), _PWG_MEDIA_MM("iso_b5-extra_201x276mm", NULL, "ISOB5Extra", 201, 276), _PWG_MEDIA_MM("iso_b4_250x353mm", "iso-b4", "ISOB4", 250, 353), _PWG_MEDIA_MM("iso_b3_353x500mm", "iso-b3", "ISOB3", 353, 500), _PWG_MEDIA_MM("iso_b2_500x707mm", "iso-b2", "ISOB2", 500, 707), _PWG_MEDIA_MM("iso_b1_707x1000mm", "iso-b1", "ISOB1", 707, 1000), _PWG_MEDIA_MM("iso_b0_1000x1414mm", "iso-b0", "ISOB0", 1000, 1414), _PWG_MEDIA_MM("iso_c10_28x40mm", "iso-c10", "EnvC10", 28, 40), _PWG_MEDIA_MM("iso_c9_40x57mm", "iso-c9", "EnvC9", 40, 57), _PWG_MEDIA_MM("iso_c8_57x81mm", "iso-c8", "EnvC8", 57, 81), _PWG_MEDIA_MM("iso_c7_81x114mm", "iso-c7", "EnvC7", 81, 114), _PWG_MEDIA_MM("iso_c7c6_81x162mm", NULL, "EnvC76", 81, 162), _PWG_MEDIA_MM("iso_c6_114x162mm", "iso-c6", "EnvC6", 114, 162), _PWG_MEDIA_MM("iso_c6c5_114x229mm", NULL, "EnvC65", 114, 229), _PWG_MEDIA_MM("iso_c5_162x229mm", "iso-c5", "EnvC5", 162, 229), _PWG_MEDIA_MM("iso_c4_229x324mm", "iso-c4", "EnvC4", 229, 324), _PWG_MEDIA_MM("iso_c3_324x458mm", "iso-c3", "EnvC3", 324, 458), _PWG_MEDIA_MM("iso_c2_458x648mm", "iso-c2", "EnvC2", 458, 648), _PWG_MEDIA_MM("iso_c1_648x917mm", "iso-c1", "EnvC1", 648, 917), _PWG_MEDIA_MM("iso_c0_917x1297mm", "iso-c0", "EnvC0", 917, 1297), _PWG_MEDIA_MM("iso_dl_110x220mm", "iso-designated", "EnvDL", 110, 220), _PWG_MEDIA_MM("iso_ra4_215x305mm", "iso-ra4", "RA4", 215, 305), _PWG_MEDIA_MM("iso_sra4_225x320mm", "iso-sra4", "SRA4", 225, 320), _PWG_MEDIA_MM("iso_ra3_305x430mm", "iso-ra3", "RA3", 305, 430), _PWG_MEDIA_MM("iso_sra3_320x450mm", "iso-sra3", "SRA3", 320, 450), _PWG_MEDIA_MM("iso_ra2_430x610mm", "iso-ra2", "RA2", 430, 610), _PWG_MEDIA_MM("iso_sra2_450x640mm", "iso-sra2", "SRA2", 450, 640), _PWG_MEDIA_MM("iso_ra1_610x860mm", "iso-ra1", "RA1", 610, 860), _PWG_MEDIA_MM("iso_sra1_640x900mm", "iso-sra1", "SRA1", 640, 900), _PWG_MEDIA_MM("iso_ra0_860x1220mm", "iso-ra0", "RA0", 860, 1220), _PWG_MEDIA_MM("iso_sra0_900x1280mm", "iso-sra0", "SRA0", 900, 1280), /* Japanese Standard Sheet Media Sizes */ _PWG_MEDIA_MM("jis_b10_32x45mm", "jis-b10", "B10", 32, 45), _PWG_MEDIA_MM("jis_b9_45x64mm", "jis-b9", "B9", 45, 64), _PWG_MEDIA_MM("jis_b8_64x91mm", "jis-b8", "B8", 64, 91), _PWG_MEDIA_MM("jis_b7_91x128mm", "jis-b7", "B7", 91, 128), _PWG_MEDIA_MM("jis_b6_128x182mm", "jis-b6", "B6", 128, 182), _PWG_MEDIA_MM("jis_b5_182x257mm", "jis-b5", "B5", 182, 257), _PWG_MEDIA_MM("jis_b4_257x364mm", "jis-b4", "B4", 257, 364), _PWG_MEDIA_MM("jis_b3_364x515mm", "jis-b3", "B3", 364, 515), _PWG_MEDIA_MM("jis_b2_515x728mm", "jis-b2", "B2", 515, 728), _PWG_MEDIA_MM("jis_b1_728x1030mm", "jis-b1", "B1", 728, 1030), _PWG_MEDIA_MM("jis_b0_1030x1456mm", "jis-b0", "B0", 1030, 1456), _PWG_MEDIA_MM("jis_exec_216x330mm", NULL, "216x330mm", 216, 330), _PWG_MEDIA_MM("jpn_kaku1_270x382mm", NULL, "EnvKaku1", 270, 382), _PWG_MEDIA_MM("jpn_kaku2_240x332mm", NULL, "EnvKaku2", 240, 332), _PWG_MEDIA_MM("jpn_kaku3_216x277mm", NULL, "EnvKaku3", 216, 277), _PWG_MEDIA_MM("jpn_kaku4_197x267mm", NULL, "EnvKaku4", 197, 267), _PWG_MEDIA_MM("jpn_kaku5_190x240mm", NULL, "EnvKaku5", 190, 240), _PWG_MEDIA_MM("jpn_kaku7_142x205mm", NULL, "EnvKaku7", 142, 205), _PWG_MEDIA_MM("jpn_kaku8_119x197mm", NULL, "EnvKaku8", 119, 197), _PWG_MEDIA_MM("jpn_chou4_90x205mm", NULL, "EnvChou4", 90, 205), _PWG_MEDIA_MM("jpn_hagaki_100x148mm", NULL, "Postcard", 100, 148), _PWG_MEDIA_MM("jpn_you4_105x235mm", NULL, "EnvYou4", 105, 235), _PWG_MEDIA_MM("jpn_you6_98x190mm", NULL, "EnvYou6", 98, 190), _PWG_MEDIA_MM("jpn_chou2_111.1x146mm", NULL, NULL, 111.1, 146), _PWG_MEDIA_MM("jpn_chou3_120x235mm", NULL, "EnvChou3", 120, 235), _PWG_MEDIA_MM("jpn_chou40_90x225mm", NULL, "EnvChou40", 90, 225), _PWG_MEDIA_MM("jpn_oufuku_148x200mm", NULL, "DoublePostcardRotated", 148, 200), _PWG_MEDIA_MM("jpn_kahu_240x322.1mm", NULL, "240x322mm", 240, 322.1), /* Chinese Standard Sheet Media Sizes */ _PWG_MEDIA_MM("prc_32k_97x151mm", NULL, "PRC32K", 97, 151), _PWG_MEDIA_MM("prc_1_102x165mm", NULL, "EnvPRC1", 102, 165), _PWG_MEDIA_MM("prc_2_102x176mm", NULL, "EnvPRC2", 102, 176), _PWG_MEDIA_MM("prc_4_110x208mm", NULL, "EnvPRC4", 110, 208), _PWG_MEDIA_MM("prc_8_120x309mm", NULL, "EnvPRC8", 120, 309), _PWG_MEDIA_MM("prc_6_120x320mm", NULL, NULL, 120, 320), _PWG_MEDIA_MM("prc_16k_146x215mm", NULL, "PRC16K", 146, 215), _PWG_MEDIA_MM("prc_7_160x230mm", NULL, "EnvPRC7", 160, 230), _PWG_MEDIA_MM("om_juuro-ku-kai_198x275mm", NULL, "198x275mm", 198, 275), _PWG_MEDIA_MM("om_pa-kai_267x389mm", NULL, "267x389mm", 267, 389), _PWG_MEDIA_MM("om_dai-pa-kai_275x395mm", NULL, "275x395mm", 275, 395), /* Chinese Standard Sheet Media Inch Sizes */ _PWG_MEDIA_IN("roc_16k_7.75x10.75in", NULL, "roc16k", 7.75, 10.75), _PWG_MEDIA_IN("roc_8k_10.75x15.5in", NULL, "roc8k", 10.75, 15.5), /* Other English Standard Sheet Media Sizes */ _PWG_MEDIA_IN("oe_photo-l_3.5x5in", NULL, "3.5x5", 3.5, 5), /* Other Metric Standard Sheet Media Sizes */ _PWG_MEDIA_MM("om_small-photo_100x150mm", NULL, "100x150mm", 100, 150), _PWG_MEDIA_MM("om_italian_110x230mm", NULL, "EnvItalian", 110, 230), _PWG_MEDIA_MM("om_large-photo_200x300", NULL, "200x300mm", 200, 300), _PWG_MEDIA_MM("om_folio_210x330mm", "folio", "Folio", 210, 330), _PWG_MEDIA_MM("om_folio-sp_215x315mm", NULL, "FolioSP", 215, 315), _PWG_MEDIA_MM("om_invite_220x220mm", NULL, "EnvInvite", 220, 220), _PWG_MEDIA_MM("om_small-photo_100x200mm", NULL, "100x200mm", 100, 200), /* Disc Sizes */ _PWG_MEDIA_MM("disc_standard_40x118mm", NULL, "Disc", 118, 118) }; /* * 'pwgFormatSizeName()' - Generate a PWG self-describing media size name. * * This function generates a PWG self-describing media size name of the form * "prefix_name_WIDTHxLENGTHunits". The prefix is typically "custom" or "roll" * for user-supplied sizes but can also be "disc", "iso", "jis", "jpn", "na", * "oe", "om", "prc", or "roc". A value of @code NULL@ automatically chooses * "oe" or "om" depending on the units. * * The size name may only contain lowercase letters, numbers, "-", and ".". If * @code NULL@ is passed, the size name will contain the formatted dimensions. * * The width and length are specified in hundredths of millimeters, equivalent * to 1/100000th of a meter or 1/2540th of an inch. The width, length, and * units used for the generated size name are calculated automatically if the * units string is @code NULL@, otherwise inches ("in") or millimeters ("mm") * are used. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - 1 on success, 0 on failure */ pwgFormatSizeName(char *keyword, /* I - Keyword buffer */ size_t keysize, /* I - Size of keyword buffer */ const char *prefix, /* I - Prefix for PWG size or @code NULL@ for automatic */ const char *name, /* I - Size name or @code NULL@ */ int width, /* I - Width of page in 2540ths */ int length, /* I - Length of page in 2540ths */ const char *units) /* I - Units - "in", "mm", or @code NULL@ for automatic */ { char usize[12 + 1 + 12 + 3], /* Unit size: NNNNNNNNNNNNxNNNNNNNNNNNNuu */ *uptr; /* Pointer into unit size */ char *(*format)(char *, size_t, int); /* Formatting function */ /* * Range check input... */ DEBUG_printf(("pwgFormatSize(keyword=%p, keysize=" CUPS_LLFMT ", prefix=\"%s\", name=\"%s\", width=%d, length=%d, units=\"%s\")", (void *)keyword, CUPS_LLCAST keysize, prefix, name, width, length, units)); if (keyword) *keyword = '\0'; if (!keyword || keysize < 32 || width < 0 || length < 0 || (units && strcmp(units, "in") && strcmp(units, "mm"))) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid media name arguments."), 1); return (0); } if (name) { /* * Validate name... */ const char *nameptr; /* Pointer into name */ for (nameptr = name; *nameptr; nameptr ++) if (!(*nameptr >= 'a' && *nameptr <= 'z') && !(*nameptr >= '0' && *nameptr <= '9') && *nameptr != '.' && *nameptr != '-') { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid media name arguments."), 1); return (0); } } else name = usize; if (prefix && !strcmp(prefix, "disc")) width = 4000; /* Disc sizes use hardcoded 40mm inner diameter */ if (!units) { if ((width % 635) == 0 && (length % 635) == 0) { /* * Use inches since the size is a multiple of 1/4 inch. */ units = "in"; } else { /* * Use millimeters since the size is not a multiple of 1/4 inch. */ units = "mm"; } } if (!strcmp(units, "in")) { format = pwg_format_inches; if (!prefix) prefix = "oe"; } else { format = pwg_format_millimeters; if (!prefix) prefix = "om"; } /* * Format the size string... */ uptr = usize; (*format)(uptr, sizeof(usize) - (size_t)(uptr - usize), width); uptr += strlen(uptr); *uptr++ = 'x'; (*format)(uptr, sizeof(usize) - (size_t)(uptr - usize), length); uptr += strlen(uptr); /* * Safe because usize can hold up to 12 + 1 + 12 + 4 bytes. */ memcpy(uptr, units, 3); /* * Format the name... */ snprintf(keyword, keysize, "%s_%s_%s", prefix, name, usize); return (1); } /* * 'pwgInitSize()' - Initialize a pwg_size_t structure using IPP Job Template * attributes. * * This function initializes a pwg_size_t structure from an IPP "media" or * "media-col" attribute in the specified IPP message. 0 is returned if neither * attribute is found in the message or the values are not valid. * * The "margins_set" variable is initialized to 1 if any "media-xxx-margin" * member attribute was specified in the "media-col" Job Template attribute, * otherwise it is initialized to 0. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - 1 if size was initialized, 0 otherwise */ pwgInitSize(pwg_size_t *size, /* I - Size to initialize */ ipp_t *job, /* I - Job template attributes */ int *margins_set) /* O - 1 if margins were set, 0 otherwise */ { ipp_attribute_t *media, /* media attribute */ *media_bottom_margin, /* media-bottom-margin member attribute */ *media_col, /* media-col attribute */ *media_left_margin, /* media-left-margin member attribute */ *media_right_margin, /* media-right-margin member attribute */ *media_size, /* media-size member attribute */ *media_top_margin, /* media-top-margin member attribute */ *x_dimension, /* x-dimension member attribute */ *y_dimension; /* y-dimension member attribute */ pwg_media_t *pwg; /* PWG media value */ /* * Range check input... */ if (!size || !job || !margins_set) return (0); /* * Look for media-col and then media... */ memset(size, 0, sizeof(pwg_size_t)); *margins_set = 0; if ((media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION)) != NULL) { /* * Got media-col, look for media-size member attribute... */ if ((media_size = ippFindAttribute(media_col->values[0].collection, "media-size", IPP_TAG_BEGIN_COLLECTION)) != NULL) { /* * Got media-size, look for x-dimension and y-dimension member * attributes... */ x_dimension = ippFindAttribute(media_size->values[0].collection, "x-dimension", IPP_TAG_INTEGER); y_dimension = ippFindAttribute(media_size->values[0].collection, "y-dimension", IPP_TAG_INTEGER); if (x_dimension && y_dimension) { size->width = x_dimension->values[0].integer; size->length = y_dimension->values[0].integer; } else if (!x_dimension) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Missing x-dimension in media-size."), 1); return (0); } else if (!y_dimension) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Missing y-dimension in media-size."), 1); return (0); } } else { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Missing media-size in media-col."), 1); return (0); } /* media-*-margin */ media_bottom_margin = ippFindAttribute(media_col->values[0].collection, "media-bottom-margin", IPP_TAG_INTEGER); media_left_margin = ippFindAttribute(media_col->values[0].collection, "media-left-margin", IPP_TAG_INTEGER); media_right_margin = ippFindAttribute(media_col->values[0].collection, "media-right-margin", IPP_TAG_INTEGER); media_top_margin = ippFindAttribute(media_col->values[0].collection, "media-top-margin", IPP_TAG_INTEGER); if (media_bottom_margin && media_left_margin && media_right_margin && media_top_margin) { *margins_set = 1; size->bottom = media_bottom_margin->values[0].integer; size->left = media_left_margin->values[0].integer; size->right = media_right_margin->values[0].integer; size->top = media_top_margin->values[0].integer; } } else { if ((media = ippFindAttribute(job, "media", IPP_TAG_NAME)) == NULL) if ((media = ippFindAttribute(job, "media", IPP_TAG_KEYWORD)) == NULL) if ((media = ippFindAttribute(job, "PageSize", IPP_TAG_NAME)) == NULL) media = ippFindAttribute(job, "PageRegion", IPP_TAG_NAME); if (media && media->values[0].string.text) { const char *name = media->values[0].string.text; /* Name string */ if ((pwg = pwgMediaForPWG(name)) == NULL) { /* * Not a PWG name, try a legacy name... */ if ((pwg = pwgMediaForLegacy(name)) == NULL) { /* * Not a legacy name, try a PPD name... */ const char *suffix; /* Suffix on media string */ pwg = pwgMediaForPPD(name); if (pwg && (suffix = name + strlen(name) - 10 /* .FullBleed */) > name && !_cups_strcasecmp(suffix, ".FullBleed")) { /* * Indicate that margins are set with the default values of 0. */ *margins_set = 1; } } } if (pwg) { size->width = pwg->width; size->length = pwg->length; } else { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unsupported media value."), 1); return (0); } } else { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Missing media or media-col."), 1); return (0); } } return (1); } /* * 'pwgMediaForLegacy()' - Find a PWG media size by ISO/IPP legacy name. * * The "name" argument specifies the legacy ISO media size name, for example * "iso-a4" or "na-letter". * * @since CUPS 1.7/macOS 10.9@ */ pwg_media_t * /* O - Matching size or NULL */ pwgMediaForLegacy(const char *legacy) /* I - Legacy size name */ { pwg_media_t key; /* Search key */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ /* * Range check input... */ if (!legacy) return (NULL); /* * Build the lookup table for PWG names as needed... */ if (!cg->leg_size_lut) { int i; /* Looping var */ pwg_media_t *size; /* Current size */ cg->leg_size_lut = cupsArrayNew((cups_array_func_t)pwg_compare_legacy, NULL); for (i = (int)(sizeof(cups_pwg_media) / sizeof(cups_pwg_media[0])), size = (pwg_media_t *)cups_pwg_media; i > 0; i --, size ++) if (size->legacy) cupsArrayAdd(cg->leg_size_lut, size); } /* * Lookup the name... */ key.legacy = legacy; return ((pwg_media_t *)cupsArrayFind(cg->leg_size_lut, &key)); } /* * 'pwgMediaForPPD()' - Find a PWG media size by Adobe PPD name. * * The "ppd" argument specifies an Adobe page size name as defined in Table B.1 * of the Adobe PostScript Printer Description File Format Specification Version * 4.3. * * If the name is non-standard, the returned PWG media size is stored in * thread-local storage and is overwritten by each call to the function in the * thread. Custom names can be of the form "Custom.WIDTHxLENGTH[units]" or * "WIDTHxLENGTH[units]". * * @since CUPS 1.7/macOS 10.9@ */ pwg_media_t * /* O - Matching size or NULL */ pwgMediaForPPD(const char *ppd) /* I - PPD size name */ { pwg_media_t key, /* Search key */ *size; /* Matching size */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ /* * Range check input... */ if (!ppd) return (NULL); /* * Build the lookup table for PWG names as needed... */ if (!cg->ppd_size_lut) { int i; /* Looping var */ cg->ppd_size_lut = cupsArrayNew((cups_array_func_t)pwg_compare_ppd, NULL); for (i = (int)(sizeof(cups_pwg_media) / sizeof(cups_pwg_media[0])), size = (pwg_media_t *)cups_pwg_media; i > 0; i --, size ++) if (size->ppd) cupsArrayAdd(cg->ppd_size_lut, size); } /* * Lookup the name... */ key.ppd = ppd; if ((size = (pwg_media_t *)cupsArrayFind(cg->ppd_size_lut, &key)) == NULL) { /* * See if the name is of the form: * * [Custom.]WIDTHxLENGTH[.FullBleed] - Size in points/inches [borderless] * [Custom.]WIDTHxLENGTHcm[.FullBleed] - Size in centimeters [borderless] * [Custom.]WIDTHxLENGTHft[.FullBleed] - Size in feet [borderless] * [Custom.]WIDTHxLENGTHin[.FullBleed] - Size in inches [borderless] * [Custom.]WIDTHxLENGTHm[.FullBleed] - Size in meters [borderless] * [Custom.]WIDTHxLENGTHmm[.FullBleed] - Size in millimeters [borderless] * [Custom.]WIDTHxLENGTHpt[.FullBleed] - Size in points [borderless] */ int w, l, /* Width and length of page */ numer, /* Unit scaling factor */ denom; /* ... */ char *ptr; /* Pointer into name */ const char *units; /* Pointer to units */ int custom; /* Custom page size? */ if (!_cups_strncasecmp(ppd, "Custom.", 7)) { custom = 1; numer = 2540; denom = 72; ptr = (char *)ppd + 7; } else { custom = 0; numer = 2540; denom = 1; ptr = (char *)ppd; } /* * Find any units in the size... */ units = strchr(ptr, '.'); while (units && isdigit(units[1] & 255)) units = strchr(units + 1, '.'); if (units) units -= 2; else units = ptr + strlen(ptr) - 2; if (units > ptr) { if (isdigit(*units & 255) || *units == '.') units ++; if (!_cups_strncasecmp(units, "cm", 2)) { numer = 1000; denom = 1; } else if (!_cups_strncasecmp(units, "ft", 2)) { numer = 2540 * 12; denom = 1; } else if (!_cups_strncasecmp(units, "in", 2)) { numer = 2540; denom = 1; } else if (!_cups_strncasecmp(units, "mm", 2)) { numer = 100; denom = 1; } else if (*units == 'm' || *units == 'M') { numer = 100000; denom = 1; } else if (!_cups_strncasecmp(units, "pt", 2)) { numer = 2540; denom = 72; } } w = pwg_scan_measurement(ptr, &ptr, numer, denom); if (ptr && ptr > ppd && *ptr == 'x') { l = pwg_scan_measurement(ptr + 1, &ptr, numer, denom); if (ptr) { /* * Not a standard size; convert it to a PWG custom name of the form: * * [oe|om]_WIDTHxHEIGHTuu_WIDTHxHEIGHTuu */ char wstr[32], lstr[32]; /* Width and length as strings */ size = &(cg->pwg_media); size->width = w; size->length = l; size->pwg = cg->pwg_name; pwgFormatSizeName(cg->pwg_name, sizeof(cg->pwg_name), custom ? "custom" : NULL, custom ? ppd + 7 : NULL, size->width, size->length, NULL); if ((w % 635) == 0 && (l % 635) == 0) snprintf(cg->ppd_name, sizeof(cg->ppd_name), "%sx%s", pwg_format_inches(wstr, sizeof(wstr), w), pwg_format_inches(lstr, sizeof(lstr), l)); else snprintf(cg->ppd_name, sizeof(cg->ppd_name), "%sx%smm", pwg_format_millimeters(wstr, sizeof(wstr), w), pwg_format_millimeters(lstr, sizeof(lstr), l)); size->ppd = cg->ppd_name; } } } return (size); } /* * 'pwgMediaForPWG()' - Find a PWG media size by 5101.1 self-describing name. * * The "pwg" argument specifies a self-describing media size name of the form * "prefix_name_WIDTHxLENGTHunits" as defined in PWG 5101.1. * * If the name is non-standard, the returned PWG media size is stored in * thread-local storage and is overwritten by each call to the function in the * thread. * * @since CUPS 1.7/macOS 10.9@ */ pwg_media_t * /* O - Matching size or NULL */ pwgMediaForPWG(const char *pwg) /* I - PWG size name */ { char *ptr; /* Pointer into name */ pwg_media_t key, /* Search key */ *size; /* Matching size */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ /* * Range check input... */ if (!pwg) return (NULL); /* * Build the lookup table for PWG names as needed... */ if (!cg->pwg_size_lut) { int i; /* Looping var */ cg->pwg_size_lut = cupsArrayNew((cups_array_func_t)pwg_compare_pwg, NULL); for (i = (int)(sizeof(cups_pwg_media) / sizeof(cups_pwg_media[0])), size = (pwg_media_t *)cups_pwg_media; i > 0; i --, size ++) cupsArrayAdd(cg->pwg_size_lut, size); } /* * Lookup the name... */ key.pwg = pwg; if ((size = (pwg_media_t *)cupsArrayFind(cg->pwg_size_lut, &key)) == NULL && (ptr = (char *)strchr(pwg, '_')) != NULL && (ptr = (char *)strchr(ptr + 1, '_')) != NULL) { /* * Try decoding the self-describing name of the form: * * class_name_WWWxHHHin[_something] * class_name_WWWxHHHmm[_something] */ int w, l; /* Width and length of page */ int numer; /* Scale factor for units */ const char *units; /* Units from size */ if ((units = strchr(ptr + 1, '_')) != NULL) units -= 2; else units = ptr + strlen(ptr) - 2; ptr ++; if (units >= ptr && (!strcmp(units, "in") || !strncmp(units, "in_", 3))) numer = 2540; else numer = 100; w = pwg_scan_measurement(ptr, &ptr, numer, 1); if (ptr && *ptr == 'x') { l = pwg_scan_measurement(ptr + 1, &ptr, numer, 1); if (ptr) { char wstr[32], lstr[32]; /* Width and length strings */ if (!strncmp(pwg, "disc_", 5)) w = l; /* Make the media size OUTERxOUTER */ size = &(cg->pwg_media); size->width = w; size->length = l; strlcpy(cg->pwg_name, pwg, sizeof(cg->pwg_name)); size->pwg = cg->pwg_name; if (numer == 100) snprintf(cg->ppd_name, sizeof(cg->ppd_name), "%sx%smm", pwg_format_millimeters(wstr, sizeof(wstr), w), pwg_format_millimeters(lstr, sizeof(lstr), l)); else snprintf(cg->ppd_name, sizeof(cg->ppd_name), "%sx%s", pwg_format_inches(wstr, sizeof(wstr), w), pwg_format_inches(lstr, sizeof(lstr), l)); size->ppd = cg->ppd_name; } } } return (size); } /* * 'pwgMediaForSize()' - Get the PWG media size for the given dimensions. * * The "width" and "length" are in hundredths of millimeters, equivalent to * 1/100000th of a meter or 1/2540th of an inch. * * If the dimensions are non-standard, the returned PWG media size is stored in * thread-local storage and is overwritten by each call to the function in the * thread. * * @since CUPS 1.7/macOS 10.9@ */ pwg_media_t * /* O - PWG media name */ pwgMediaForSize(int width, /* I - Width in hundredths of millimeters */ int length) /* I - Length in hundredths of millimeters */ { /* * Adobe uses a size matching algorithm with an epsilon of 5 points, which * is just about 176/2540ths... */ return (_pwgMediaNearSize(width, length, 176)); } /* * '_pwgMediaNearSize()' - Get the PWG media size within the given tolerance. */ pwg_media_t * /* O - PWG media name */ _pwgMediaNearSize(int width, /* I - Width in hundredths of millimeters */ int length, /* I - Length in hundredths of millimeters */ int epsilon) /* I - Match within this tolernace. PWG units */ { int i; /* Looping var */ pwg_media_t *media, /* Current media */ *best_media = NULL; /* Best match */ int dw, dl, /* Difference in width and length */ best_dw = 999, /* Best difference in width and length */ best_dl = 999; char wstr[32], lstr[32]; /* Width and length as strings */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ /* * Range check input... */ if (width <= 0 || length <= 0) return (NULL); /* * Look for a standard size... */ for (i = (int)(sizeof(cups_pwg_media) / sizeof(cups_pwg_media[0])), media = (pwg_media_t *)cups_pwg_media; i > 0; i --, media ++) { dw = abs(media->width - width); dl = abs(media->length - length); if (!dw && !dl) return (media); else if (dw <= epsilon && dl <= epsilon) { if (dw <= best_dw && dl <= best_dl) { best_media = media; best_dw = dw; best_dl = dl; } } } if (best_media) return (best_media); /* * Not a standard size; convert it to a PWG custom name of the form: * * custom_WIDTHxHEIGHTuu_WIDTHxHEIGHTuu */ pwgFormatSizeName(cg->pwg_name, sizeof(cg->pwg_name), "custom", NULL, width, length, NULL); cg->pwg_media.pwg = cg->pwg_name; cg->pwg_media.width = width; cg->pwg_media.length = length; if ((width % 635) == 0 && (length % 635) == 0) snprintf(cg->ppd_name, sizeof(cg->ppd_name), "%sx%s", pwg_format_inches(wstr, sizeof(wstr), width), pwg_format_inches(lstr, sizeof(lstr), length)); else snprintf(cg->ppd_name, sizeof(cg->ppd_name), "%sx%smm", pwg_format_millimeters(wstr, sizeof(wstr), width), pwg_format_millimeters(lstr, sizeof(lstr), length)); cg->pwg_media.ppd = cg->ppd_name; return (&(cg->pwg_media)); } /* * '_pwgMediaTable()' - Return the internal media size table. */ const pwg_media_t * /* O - Pointer to first entry */ _pwgMediaTable(size_t *num_media) /* O - Number of entries */ { *num_media = sizeof(cups_pwg_media) / sizeof(cups_pwg_media[0]); return (cups_pwg_media); } /* * 'pwg_compare_legacy()' - Compare two sizes using the legacy names. */ static int /* O - Result of comparison */ pwg_compare_legacy(pwg_media_t *a, /* I - First size */ pwg_media_t *b) /* I - Second size */ { return (strcmp(a->legacy, b->legacy)); } /* * 'pwg_compare_ppd()' - Compare two sizes using the PPD names. */ static int /* O - Result of comparison */ pwg_compare_ppd(pwg_media_t *a, /* I - First size */ pwg_media_t *b) /* I - Second size */ { return (strcmp(a->ppd, b->ppd)); } /* * 'pwg_compare_pwg()' - Compare two sizes using the PWG names. */ static int /* O - Result of comparison */ pwg_compare_pwg(pwg_media_t *a, /* I - First size */ pwg_media_t *b) /* I - Second size */ { return (strcmp(a->pwg, b->pwg)); } /* * 'pwg_format_inches()' - Convert and format PWG units as inches. */ static char * /* O - String */ pwg_format_inches(char *buf, /* I - Buffer */ size_t bufsize, /* I - Size of buffer */ int val) /* I - Value in hundredths of millimeters */ { int thousandths, /* Thousandths of inches */ integer, /* Integer portion */ fraction; /* Fractional portion */ /* * Convert hundredths of millimeters to thousandths of inches and round to * the nearest thousandth. */ thousandths = (val * 1000 + 1270) / 2540; integer = thousandths / 1000; fraction = thousandths % 1000; /* * Format as a pair of integers (avoids locale stuff), avoiding trailing * zeros... */ if (fraction == 0) snprintf(buf, bufsize, "%d", integer); else if (fraction % 10) snprintf(buf, bufsize, "%d.%03d", integer, fraction); else if (fraction % 100) snprintf(buf, bufsize, "%d.%02d", integer, fraction / 10); else snprintf(buf, bufsize, "%d.%01d", integer, fraction / 100); return (buf); } /* * 'pwg_format_millimeters()' - Convert and format PWG units as millimeters. */ static char * /* O - String */ pwg_format_millimeters(char *buf, /* I - Buffer */ size_t bufsize, /* I - Size of buffer */ int val) /* I - Value in hundredths of millimeters */ { int integer, /* Integer portion */ fraction; /* Fractional portion */ /* * Convert hundredths of millimeters to integer and fractional portions. */ integer = val / 100; fraction = val % 100; /* * Format as a pair of integers (avoids locale stuff), avoiding trailing * zeros... */ if (fraction == 0) snprintf(buf, bufsize, "%d", integer); else if (fraction % 10) snprintf(buf, bufsize, "%d.%02d", integer, fraction); else snprintf(buf, bufsize, "%d.%01d", integer, fraction / 10); return (buf); } /* * 'pwg_scan_measurement()' - Scan a measurement in inches or millimeters. * * The "factor" argument specifies the scale factor for the units to convert to * hundredths of millimeters. The returned value is NOT rounded but is an * exact conversion of the fraction value (no floating point is used). */ static int /* O - Hundredths of millimeters */ pwg_scan_measurement( const char *buf, /* I - Number string */ char **bufptr, /* O - First byte after the number */ int numer, /* I - Numerator from units */ int denom) /* I - Denominator from units */ { int value = 0, /* Measurement value */ fractional = 0, /* Fractional value */ divisor = 1, /* Fractional divisor */ digits = 10 * numer * denom; /* Maximum fractional value to read */ /* * Scan integer portion... */ while (*buf >= '0' && *buf <= '9') value = value * 10 + (*buf++) - '0'; if (*buf == '.') { /* * Scan fractional portion... */ buf ++; while (divisor < digits && *buf >= '0' && *buf <= '9') { fractional = fractional * 10 + (*buf++) - '0'; divisor *= 10; } /* * Skip trailing digits that won't contribute... */ while (*buf >= '0' && *buf <= '9') buf ++; } if (bufptr) *bufptr = (char *)buf; return (value * numer / denom + fractional * numer / denom / divisor); } ippsample/cups/ipp.c0000644000175000017500000055555613240604116013472 0ustar tilltill/* * Internet Printing Protocol functions for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #include #ifdef WIN32 # include #endif /* WIN32 */ /* * Local functions... */ static ipp_attribute_t *ipp_add_attr(ipp_t *ipp, const char *name, ipp_tag_t group_tag, ipp_tag_t value_tag, int num_values); static void ipp_free_values(ipp_attribute_t *attr, int element, int count); static char *ipp_get_code(const char *locale, char *buffer, size_t bufsize) __attribute__((nonnull(1,2))); static char *ipp_lang_code(const char *locale, char *buffer, size_t bufsize) __attribute__((nonnull(1,2))); static size_t ipp_length(ipp_t *ipp, int collection); static ssize_t ipp_read_http(http_t *http, ipp_uchar_t *buffer, size_t length); static ssize_t ipp_read_file(int *fd, ipp_uchar_t *buffer, size_t length); static void ipp_set_error(ipp_status_t status, const char *format, ...); static _ipp_value_t *ipp_set_value(ipp_t *ipp, ipp_attribute_t **attr, int element); static ssize_t ipp_write_file(int *fd, ipp_uchar_t *buffer, size_t length); /* * '_cupsBufferGet()' - Get a read/write buffer. */ char * /* O - Buffer */ _cupsBufferGet(size_t size) /* I - Size required */ { _cups_buffer_t *buffer; /* Current buffer */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ for (buffer = cg->cups_buffers; buffer; buffer = buffer->next) if (!buffer->used && buffer->size >= size) break; if (!buffer) { if ((buffer = malloc(sizeof(_cups_buffer_t) + size - 1)) == NULL) return (NULL); buffer->next = cg->cups_buffers; buffer->size = size; cg->cups_buffers = buffer; } buffer->used = 1; return (buffer->d); } /* * '_cupsBufferRelease()' - Release a read/write buffer. */ void _cupsBufferRelease(char *b) /* I - Buffer to release */ { _cups_buffer_t *buffer; /* Buffer */ /* * Mark this buffer as unused... */ buffer = (_cups_buffer_t *)(b - offsetof(_cups_buffer_t, d)); buffer->used = 0; } /* * 'ippAddBoolean()' - Add a boolean attribute to an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). */ ipp_attribute_t * /* O - New attribute */ ippAddBoolean(ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ const char *name, /* I - Name of attribute */ char value) /* I - Value of attribute */ { ipp_attribute_t *attr; /* New attribute */ DEBUG_printf(("ippAddBoolean(ipp=%p, group=%02x(%s), name=\"%s\", value=%d)", (void *)ipp, group, ippTagString(group), name, value)); /* * Range check input... */ if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE) return (NULL); /* * Create the attribute... */ if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BOOLEAN, 1)) == NULL) return (NULL); attr->values[0].boolean = value; return (attr); } /* * 'ippAddBooleans()' - Add an array of boolean values. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). */ ipp_attribute_t * /* O - New attribute */ ippAddBooleans(ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ const char *name, /* I - Name of attribute */ int num_values, /* I - Number of values */ const char *values) /* I - Values */ { int i; /* Looping var */ ipp_attribute_t *attr; /* New attribute */ _ipp_value_t *value; /* Current value */ DEBUG_printf(("ippAddBooleans(ipp=%p, group=%02x(%s), name=\"%s\", num_values=%d, values=%p)", (void *)ipp, group, ippTagString(group), name, num_values, (void *)values)); /* * Range check input... */ if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || num_values < 1) return (NULL); /* * Create the attribute... */ if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BOOLEAN, num_values)) == NULL) return (NULL); if (values) { for (i = num_values, value = attr->values; i > 0; i --, value ++) value->boolean = *values++; } return (attr); } /* * 'ippAddCollection()' - Add a collection value. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). * * @since CUPS 1.1.19/macOS 10.3@ */ ipp_attribute_t * /* O - New attribute */ ippAddCollection(ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ const char *name, /* I - Name of attribute */ ipp_t *value) /* I - Value */ { ipp_attribute_t *attr; /* New attribute */ DEBUG_printf(("ippAddCollection(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)", (void *)ipp, group, ippTagString(group), name, (void *)value)); /* * Range check input... */ if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE) return (NULL); /* * Create the attribute... */ if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BEGIN_COLLECTION, 1)) == NULL) return (NULL); attr->values[0].collection = value; if (value) value->use ++; return (attr); } /* * 'ippAddCollections()' - Add an array of collection values. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). * * @since CUPS 1.1.19/macOS 10.3@ */ ipp_attribute_t * /* O - New attribute */ ippAddCollections( ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ const char *name, /* I - Name of attribute */ int num_values, /* I - Number of values */ const ipp_t **values) /* I - Values */ { int i; /* Looping var */ ipp_attribute_t *attr; /* New attribute */ _ipp_value_t *value; /* Current value */ DEBUG_printf(("ippAddCollections(ipp=%p, group=%02x(%s), name=\"%s\", num_values=%d, values=%p)", (void *)ipp, group, ippTagString(group), name, num_values, (void *)values)); /* * Range check input... */ if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || num_values < 1) return (NULL); /* * Create the attribute... */ if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BEGIN_COLLECTION, num_values)) == NULL) return (NULL); if (values) { for (i = num_values, value = attr->values; i > 0; i --, value ++) { value->collection = (ipp_t *)*values++; value->collection->use ++; } } return (attr); } /* * 'ippAddDate()' - Add a dateTime attribute to an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). */ ipp_attribute_t * /* O - New attribute */ ippAddDate(ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ const char *name, /* I - Name of attribute */ const ipp_uchar_t *value) /* I - Value */ { ipp_attribute_t *attr; /* New attribute */ DEBUG_printf(("ippAddDate(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)", (void *)ipp, group, ippTagString(group), name, (void *)value)); /* * Range check input... */ if (!ipp || !name || !value || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE) return (NULL); /* * Create the attribute... */ if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_DATE, 1)) == NULL) return (NULL); memcpy(attr->values[0].date, value, 11); return (attr); } /* * 'ippAddInteger()' - Add a integer attribute to an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). * * Supported values include enum (@code IPP_TAG_ENUM@) and integer * (@code IPP_TAG_INTEGER@). */ ipp_attribute_t * /* O - New attribute */ ippAddInteger(ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ ipp_tag_t value_tag, /* I - Type of attribute */ const char *name, /* I - Name of attribute */ int value) /* I - Value of attribute */ { ipp_attribute_t *attr; /* New attribute */ DEBUG_printf(("ippAddInteger(ipp=%p, group=%02x(%s), type=%02x(%s), name=\"%s\", value=%d)", (void *)ipp, group, ippTagString(group), value_tag, ippTagString(value_tag), name, value)); value_tag &= IPP_TAG_CUPS_MASK; /* * Special-case for legacy usage: map out-of-band attributes to new ippAddOutOfBand * function... */ if (value_tag >= IPP_TAG_UNSUPPORTED_VALUE && value_tag <= IPP_TAG_ADMINDEFINE) return (ippAddOutOfBand(ipp, group, value_tag, name)); /* * Range check input... */ #if 0 if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || (value_tag != IPP_TAG_INTEGER && value_tag != IPP_TAG_ENUM)) return (NULL); #else if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE) return (NULL); #endif /* 0 */ /* * Create the attribute... */ if ((attr = ipp_add_attr(ipp, name, group, value_tag, 1)) == NULL) return (NULL); attr->values[0].integer = value; return (attr); } /* * 'ippAddIntegers()' - Add an array of integer values. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). * * Supported values include enum (@code IPP_TAG_ENUM@) and integer * (@code IPP_TAG_INTEGER@). */ ipp_attribute_t * /* O - New attribute */ ippAddIntegers(ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ ipp_tag_t value_tag, /* I - Type of attribute */ const char *name, /* I - Name of attribute */ int num_values, /* I - Number of values */ const int *values) /* I - Values */ { int i; /* Looping var */ ipp_attribute_t *attr; /* New attribute */ _ipp_value_t *value; /* Current value */ DEBUG_printf(("ippAddIntegers(ipp=%p, group=%02x(%s), type=%02x(%s), name=\"%s\", num_values=%d, values=%p)", (void *)ipp, group, ippTagString(group), value_tag, ippTagString(value_tag), name, num_values, (void *)values)); value_tag &= IPP_TAG_CUPS_MASK; /* * Range check input... */ #if 0 if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || (value_tag != IPP_TAG_INTEGER && value_tag != IPP_TAG_ENUM) || num_values < 1) return (NULL); #else if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || num_values < 1) return (NULL); #endif /* 0 */ /* * Create the attribute... */ if ((attr = ipp_add_attr(ipp, name, group, value_tag, num_values)) == NULL) return (NULL); if (values) { for (i = num_values, value = attr->values; i > 0; i --, value ++) value->integer = *values++; } return (attr); } /* * 'ippAddOctetString()' - Add an octetString value to an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). * * @since CUPS 1.2/macOS 10.5@ */ ipp_attribute_t * /* O - New attribute */ ippAddOctetString(ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ const char *name, /* I - Name of attribute */ const void *data, /* I - octetString data */ int datalen) /* I - Length of data in bytes */ { ipp_attribute_t *attr; /* New attribute */ if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || datalen < 0 || datalen > IPP_MAX_LENGTH) return (NULL); if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_STRING, 1)) == NULL) return (NULL); /* * Initialize the attribute data... */ attr->values[0].unknown.length = datalen; if (data) { if ((attr->values[0].unknown.data = malloc((size_t)datalen)) == NULL) { ippDeleteAttribute(ipp, attr); return (NULL); } memcpy(attr->values[0].unknown.data, data, (size_t)datalen); } /* * Return the new attribute... */ return (attr); } /* * 'ippAddOutOfBand()' - Add an out-of-band value to an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). * * Supported out-of-band values include unsupported-value * (@code IPP_TAG_UNSUPPORTED_VALUE@), default (@code IPP_TAG_DEFAULT@), unknown * (@code IPP_TAG_UNKNOWN@), no-value (@code IPP_TAG_NOVALUE@), not-settable * (@code IPP_TAG_NOTSETTABLE@), delete-attribute (@code IPP_TAG_DELETEATTR@), and * admin-define (@code IPP_TAG_ADMINDEFINE@). * * @since CUPS 1.6/macOS 10.8@ */ ipp_attribute_t * /* O - New attribute */ ippAddOutOfBand(ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ ipp_tag_t value_tag, /* I - Type of attribute */ const char *name) /* I - Name of attribute */ { DEBUG_printf(("ippAddOutOfBand(ipp=%p, group=%02x(%s), value_tag=%02x(%s), name=\"%s\")", (void *)ipp, group, ippTagString(group), value_tag, ippTagString(value_tag), name)); value_tag &= IPP_TAG_CUPS_MASK; /* * Range check input... */ if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || (value_tag != IPP_TAG_UNSUPPORTED_VALUE && value_tag != IPP_TAG_DEFAULT && value_tag != IPP_TAG_UNKNOWN && value_tag != IPP_TAG_NOVALUE && value_tag != IPP_TAG_NOTSETTABLE && value_tag != IPP_TAG_DELETEATTR && value_tag != IPP_TAG_ADMINDEFINE)) return (NULL); /* * Create the attribute... */ return (ipp_add_attr(ipp, name, group, value_tag, 1)); } /* * 'ippAddRange()' - Add a range of values to an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). * * The @code lower@ parameter must be less than or equal to the @code upper@ parameter. */ ipp_attribute_t * /* O - New attribute */ ippAddRange(ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ const char *name, /* I - Name of attribute */ int lower, /* I - Lower value */ int upper) /* I - Upper value */ { ipp_attribute_t *attr; /* New attribute */ DEBUG_printf(("ippAddRange(ipp=%p, group=%02x(%s), name=\"%s\", lower=%d, upper=%d)", (void *)ipp, group, ippTagString(group), name, lower, upper)); /* * Range check input... */ if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE) return (NULL); /* * Create the attribute... */ if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RANGE, 1)) == NULL) return (NULL); attr->values[0].range.lower = lower; attr->values[0].range.upper = upper; return (attr); } /* * 'ippAddRanges()' - Add ranges of values to an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). */ ipp_attribute_t * /* O - New attribute */ ippAddRanges(ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ const char *name, /* I - Name of attribute */ int num_values, /* I - Number of values */ const int *lower, /* I - Lower values */ const int *upper) /* I - Upper values */ { int i; /* Looping var */ ipp_attribute_t *attr; /* New attribute */ _ipp_value_t *value; /* Current value */ DEBUG_printf(("ippAddRanges(ipp=%p, group=%02x(%s), name=\"%s\", num_values=%d, lower=%p, upper=%p)", (void *)ipp, group, ippTagString(group), name, num_values, (void *)lower, (void *)upper)); /* * Range check input... */ if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || num_values < 1) return (NULL); /* * Create the attribute... */ if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RANGE, num_values)) == NULL) return (NULL); if (lower && upper) { for (i = num_values, value = attr->values; i > 0; i --, value ++) { value->range.lower = *lower++; value->range.upper = *upper++; } } return (attr); } /* * 'ippAddResolution()' - Add a resolution value to an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). */ ipp_attribute_t * /* O - New attribute */ ippAddResolution(ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ const char *name, /* I - Name of attribute */ ipp_res_t units, /* I - Units for resolution */ int xres, /* I - X resolution */ int yres) /* I - Y resolution */ { ipp_attribute_t *attr; /* New attribute */ DEBUG_printf(("ippAddResolution(ipp=%p, group=%02x(%s), name=\"%s\", units=%d, xres=%d, yres=%d)", (void *)ipp, group, ippTagString(group), name, units, xres, yres)); /* * Range check input... */ if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || units < IPP_RES_PER_INCH || units > IPP_RES_PER_CM || xres < 0 || yres < 0) return (NULL); /* * Create the attribute... */ if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RESOLUTION, 1)) == NULL) return (NULL); attr->values[0].resolution.xres = xres; attr->values[0].resolution.yres = yres; attr->values[0].resolution.units = units; return (attr); } /* * 'ippAddResolutions()' - Add resolution values to an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). */ ipp_attribute_t * /* O - New attribute */ ippAddResolutions(ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ const char *name, /* I - Name of attribute */ int num_values,/* I - Number of values */ ipp_res_t units, /* I - Units for resolution */ const int *xres, /* I - X resolutions */ const int *yres) /* I - Y resolutions */ { int i; /* Looping var */ ipp_attribute_t *attr; /* New attribute */ _ipp_value_t *value; /* Current value */ DEBUG_printf(("ippAddResolutions(ipp=%p, group=%02x(%s), name=\"%s\", num_value=%d, units=%d, xres=%p, yres=%p)", (void *)ipp, group, ippTagString(group), name, num_values, units, (void *)xres, (void *)yres)); /* * Range check input... */ if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || num_values < 1 || units < IPP_RES_PER_INCH || units > IPP_RES_PER_CM) return (NULL); /* * Create the attribute... */ if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RESOLUTION, num_values)) == NULL) return (NULL); if (xres && yres) { for (i = num_values, value = attr->values; i > 0; i --, value ++) { value->resolution.xres = *xres++; value->resolution.yres = *yres++; value->resolution.units = units; } } return (attr); } /* * 'ippAddSeparator()' - Add a group separator to an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. */ ipp_attribute_t * /* O - New attribute */ ippAddSeparator(ipp_t *ipp) /* I - IPP message */ { DEBUG_printf(("ippAddSeparator(ipp=%p)", (void *)ipp)); /* * Range check input... */ if (!ipp) return (NULL); /* * Create the attribute... */ return (ipp_add_attr(ipp, NULL, IPP_TAG_ZERO, IPP_TAG_ZERO, 0)); } /* * 'ippAddString()' - Add a language-encoded string to an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). * * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme * (@code IPP_TAG_URISCHEME@). * * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and * textWithLanguage string values and must be @code NULL@ for all other string values. */ ipp_attribute_t * /* O - New attribute */ ippAddString(ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ ipp_tag_t value_tag, /* I - Type of attribute */ const char *name, /* I - Name of attribute */ const char *language, /* I - Language code */ const char *value) /* I - Value */ { ipp_tag_t temp_tag; /* Temporary value tag (masked) */ ipp_attribute_t *attr; /* New attribute */ char code[IPP_MAX_LANGUAGE]; /* Charset/language code buffer */ DEBUG_printf(("ippAddString(ipp=%p, group=%02x(%s), value_tag=%02x(%s), name=\"%s\", language=\"%s\", value=\"%s\")", (void *)ipp, group, ippTagString(group), value_tag, ippTagString(value_tag), name, language, value)); /* * Range check input... */ temp_tag = (ipp_tag_t)((int)value_tag & IPP_TAG_CUPS_MASK); #if 0 if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || (temp_tag < IPP_TAG_TEXT && temp_tag != IPP_TAG_TEXTLANG && temp_tag != IPP_TAG_NAMELANG) || temp_tag > IPP_TAG_MIMETYPE) return (NULL); if ((temp_tag == IPP_TAG_TEXTLANG || temp_tag == IPP_TAG_NAMELANG) != (language != NULL)) return (NULL); #else if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE) return (NULL); #endif /* 0 */ /* * See if we need to map charset, language, or locale values... */ if (language && ((int)value_tag & IPP_TAG_CUPS_CONST) && strcmp(language, ipp_lang_code(language, code, sizeof(code)))) value_tag = temp_tag; /* Don't do a fast copy */ else if (value && value_tag == (ipp_tag_t)(IPP_TAG_CHARSET | IPP_TAG_CUPS_CONST) && strcmp(value, ipp_get_code(value, code, sizeof(code)))) value_tag = temp_tag; /* Don't do a fast copy */ else if (value && value_tag == (ipp_tag_t)(IPP_TAG_LANGUAGE | IPP_TAG_CUPS_CONST) && strcmp(value, ipp_lang_code(value, code, sizeof(code)))) value_tag = temp_tag; /* Don't do a fast copy */ /* * Create the attribute... */ if ((attr = ipp_add_attr(ipp, name, group, value_tag, 1)) == NULL) return (NULL); /* * Initialize the attribute data... */ if ((int)value_tag & IPP_TAG_CUPS_CONST) { attr->values[0].string.language = (char *)language; attr->values[0].string.text = (char *)value; } else { if (language) attr->values[0].string.language = _cupsStrAlloc(ipp_lang_code(language, code, sizeof(code))); if (value) { if (value_tag == IPP_TAG_CHARSET) attr->values[0].string.text = _cupsStrAlloc(ipp_get_code(value, code, sizeof(code))); else if (value_tag == IPP_TAG_LANGUAGE) attr->values[0].string.text = _cupsStrAlloc(ipp_lang_code(value, code, sizeof(code))); else attr->values[0].string.text = _cupsStrAlloc(value); } } return (attr); } /* * 'ippAddStringf()' - Add a formatted string to an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document * (@code IPP_TAG_DOCUMENT@), event notification * (@code IPP_TAG_EVENT_NOTIFICATION@), operation (@code IPP_TAG_OPERATION@), * printer (@code IPP_TAG_PRINTER@), subscription (@code IPP_TAG_SUBSCRIPTION@), * or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). * * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme * (@code IPP_TAG_URISCHEME@). * * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage * and textWithLanguage string values and must be @code NULL@ for all other * string values. * * The @code format@ parameter uses formatting characters compatible with the * printf family of standard functions. Additional arguments follow it as * needed. The formatted string is truncated as needed to the maximum length of * the corresponding value type. * * @since CUPS 1.7/macOS 10.9@ */ ipp_attribute_t * /* O - New attribute */ ippAddStringf(ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ ipp_tag_t value_tag, /* I - Type of attribute */ const char *name, /* I - Name of attribute */ const char *language, /* I - Language code (@code NULL@ for default) */ const char *format, /* I - Printf-style format string */ ...) /* I - Additional arguments as needed */ { ipp_attribute_t *attr; /* New attribute */ va_list ap; /* Argument pointer */ va_start(ap, format); attr = ippAddStringfv(ipp, group, value_tag, name, language, format, ap); va_end(ap); return (attr); } /* * 'ippAddStringfv()' - Add a formatted string to an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document * (@code IPP_TAG_DOCUMENT@), event notification * (@code IPP_TAG_EVENT_NOTIFICATION@), operation (@code IPP_TAG_OPERATION@), * printer (@code IPP_TAG_PRINTER@), subscription (@code IPP_TAG_SUBSCRIPTION@), * or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). * * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme * (@code IPP_TAG_URISCHEME@). * * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage * and textWithLanguage string values and must be @code NULL@ for all other * string values. * * The @code format@ parameter uses formatting characters compatible with the * printf family of standard functions. Additional arguments are passed in the * stdarg pointer @code ap@. The formatted string is truncated as needed to the * maximum length of the corresponding value type. * * @since CUPS 1.7/macOS 10.9@ */ ipp_attribute_t * /* O - New attribute */ ippAddStringfv(ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ ipp_tag_t value_tag, /* I - Type of attribute */ const char *name, /* I - Name of attribute */ const char *language, /* I - Language code (@code NULL@ for default) */ const char *format, /* I - Printf-style format string */ va_list ap) /* I - Additional arguments */ { char buffer[IPP_MAX_TEXT + 4]; /* Formatted text string */ ssize_t bytes, /* Length of formatted value */ max_bytes; /* Maximum number of bytes for value */ /* * Range check input... */ if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG && value_tag != IPP_TAG_NAMELANG) || value_tag > IPP_TAG_MIMETYPE || !format) return (NULL); if ((value_tag == IPP_TAG_TEXTLANG || value_tag == IPP_TAG_NAMELANG) != (language != NULL)) return (NULL); /* * Format the string... */ if (!strcmp(format, "%s")) { /* * Optimize the simple case... */ const char *s = va_arg(ap, char *); if (!s) s = "(null)"; bytes = (ssize_t)strlen(s); strlcpy(buffer, s, sizeof(buffer)); } else { /* * Do a full formatting of the message... */ if ((bytes = vsnprintf(buffer, sizeof(buffer), format, ap)) < 0) return (NULL); } /* * Limit the length of the string... */ switch (value_tag) { default : case IPP_TAG_TEXT : case IPP_TAG_TEXTLANG : max_bytes = IPP_MAX_TEXT; break; case IPP_TAG_NAME : case IPP_TAG_NAMELANG : max_bytes = IPP_MAX_NAME; break; case IPP_TAG_CHARSET : max_bytes = IPP_MAX_CHARSET; break; case IPP_TAG_KEYWORD : max_bytes = IPP_MAX_KEYWORD; break; case IPP_TAG_LANGUAGE : max_bytes = IPP_MAX_LANGUAGE; break; case IPP_TAG_MIMETYPE : max_bytes = IPP_MAX_MIMETYPE; break; case IPP_TAG_URI : max_bytes = IPP_MAX_URI; break; case IPP_TAG_URISCHEME : max_bytes = IPP_MAX_URISCHEME; break; } if (bytes >= max_bytes) { char *bufmax, /* Buffer at max_bytes */ *bufptr; /* Pointer into buffer */ bufptr = buffer + strlen(buffer) - 1; bufmax = buffer + max_bytes - 1; while (bufptr > bufmax) { if (*bufptr & 0x80) { while ((*bufptr & 0xc0) == 0x80 && bufptr > buffer) bufptr --; } bufptr --; } *bufptr = '\0'; } /* * Add the formatted string and return... */ return (ippAddString(ipp, group, value_tag, name, language, buffer)); } /* * 'ippAddStrings()' - Add language-encoded strings to an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). * * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme * (@code IPP_TAG_URISCHEME@). * * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and * textWithLanguage string values and must be @code NULL@ for all other string values. */ ipp_attribute_t * /* O - New attribute */ ippAddStrings( ipp_t *ipp, /* I - IPP message */ ipp_tag_t group, /* I - IPP group */ ipp_tag_t value_tag, /* I - Type of attribute */ const char *name, /* I - Name of attribute */ int num_values, /* I - Number of values */ const char *language, /* I - Language code (@code NULL@ for default) */ const char * const *values) /* I - Values */ { int i; /* Looping var */ ipp_tag_t temp_tag; /* Temporary value tag (masked) */ ipp_attribute_t *attr; /* New attribute */ _ipp_value_t *value; /* Current value */ char code[32]; /* Language/charset value buffer */ DEBUG_printf(("ippAddStrings(ipp=%p, group=%02x(%s), value_tag=%02x(%s), name=\"%s\", num_values=%d, language=\"%s\", values=%p)", (void *)ipp, group, ippTagString(group), value_tag, ippTagString(value_tag), name, num_values, language, (void *)values)); /* * Range check input... */ temp_tag = (ipp_tag_t)((int)value_tag & IPP_TAG_CUPS_MASK); #if 0 if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || (temp_tag < IPP_TAG_TEXT && temp_tag != IPP_TAG_TEXTLANG && temp_tag != IPP_TAG_NAMELANG) || temp_tag > IPP_TAG_MIMETYPE || num_values < 1) return (NULL); if ((temp_tag == IPP_TAG_TEXTLANG || temp_tag == IPP_TAG_NAMELANG) != (language != NULL)) return (NULL); #else if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || num_values < 1) return (NULL); #endif /* 0 */ /* * See if we need to map charset, language, or locale values... */ if (language && ((int)value_tag & IPP_TAG_CUPS_CONST) && strcmp(language, ipp_lang_code(language, code, sizeof(code)))) value_tag = temp_tag; /* Don't do a fast copy */ else if (values && value_tag == (ipp_tag_t)(IPP_TAG_CHARSET | IPP_TAG_CUPS_CONST)) { for (i = 0; i < num_values; i ++) if (strcmp(values[i], ipp_get_code(values[i], code, sizeof(code)))) { value_tag = temp_tag; /* Don't do a fast copy */ break; } } else if (values && value_tag == (ipp_tag_t)(IPP_TAG_LANGUAGE | IPP_TAG_CUPS_CONST)) { for (i = 0; i < num_values; i ++) if (strcmp(values[i], ipp_lang_code(values[i], code, sizeof(code)))) { value_tag = temp_tag; /* Don't do a fast copy */ break; } } /* * Create the attribute... */ if ((attr = ipp_add_attr(ipp, name, group, value_tag, num_values)) == NULL) return (NULL); /* * Initialize the attribute data... */ for (i = num_values, value = attr->values; i > 0; i --, value ++) { if (language) { if (value == attr->values) { if ((int)value_tag & IPP_TAG_CUPS_CONST) value->string.language = (char *)language; else value->string.language = _cupsStrAlloc(ipp_lang_code(language, code, sizeof(code))); } else value->string.language = attr->values[0].string.language; } if (values) { if ((int)value_tag & IPP_TAG_CUPS_CONST) value->string.text = (char *)*values++; else if (value_tag == IPP_TAG_CHARSET) value->string.text = _cupsStrAlloc(ipp_get_code(*values++, code, sizeof(code))); else if (value_tag == IPP_TAG_LANGUAGE) value->string.text = _cupsStrAlloc(ipp_lang_code(*values++, code, sizeof(code))); else value->string.text = _cupsStrAlloc(*values++); } } return (attr); } /* * 'ippContainsInteger()' - Determine whether an attribute contains the * specified value or is within the list of ranges. * * Returns non-zero when the attribute contains either a matching integer or * enum value, or the value falls within one of the rangeOfInteger values for * the attribute. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - 1 on a match, 0 on no match */ ippContainsInteger( ipp_attribute_t *attr, /* I - Attribute */ int value) /* I - Integer/enum value */ { int i; /* Looping var */ _ipp_value_t *avalue; /* Current attribute value */ /* * Range check input... */ if (!attr) return (0); if (attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM && attr->value_tag != IPP_TAG_RANGE) return (0); /* * Compare... */ if (attr->value_tag == IPP_TAG_RANGE) { for (i = attr->num_values, avalue = attr->values; i > 0; i --, avalue ++) if (value >= avalue->range.lower && value <= avalue->range.upper) return (1); } else { for (i = attr->num_values, avalue = attr->values; i > 0; i --, avalue ++) if (value == avalue->integer) return (1); } return (0); } /* * 'ippContainsString()' - Determine whether an attribute contains the * specified string value. * * Returns non-zero when the attribute contains a matching charset, keyword, * naturalLanguage, mimeMediaType, name, text, uri, or uriScheme value. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - 1 on a match, 0 on no match */ ippContainsString( ipp_attribute_t *attr, /* I - Attribute */ const char *value) /* I - String value */ { int i; /* Looping var */ _ipp_value_t *avalue; /* Current attribute value */ DEBUG_printf(("ippContainsString(attr=%p, value=\"%s\")", (void *)attr, value)); /* * Range check input... */ if (!attr || !value) { DEBUG_puts("1ippContainsString: Returning 0 (bad input)"); return (0); } /* * Compare... */ DEBUG_printf(("1ippContainsString: attr %s, %s with %d values.", attr->name, ippTagString(attr->value_tag), attr->num_values)); switch (attr->value_tag & IPP_TAG_CUPS_MASK) { case IPP_TAG_CHARSET : case IPP_TAG_KEYWORD : case IPP_TAG_LANGUAGE : case IPP_TAG_URI : case IPP_TAG_URISCHEME : for (i = attr->num_values, avalue = attr->values; i > 0; i --, avalue ++) { DEBUG_printf(("1ippContainsString: value[%d]=\"%s\"", attr->num_values - i, avalue->string.text)); if (!strcmp(value, avalue->string.text)) { DEBUG_puts("1ippContainsString: Returning 1 (match)"); return (1); } } case IPP_TAG_MIMETYPE : case IPP_TAG_NAME : case IPP_TAG_NAMELANG : case IPP_TAG_TEXT : case IPP_TAG_TEXTLANG : for (i = attr->num_values, avalue = attr->values; i > 0; i --, avalue ++) { DEBUG_printf(("1ippContainsString: value[%d]=\"%s\"", attr->num_values - i, avalue->string.text)); if (!_cups_strcasecmp(value, avalue->string.text)) { DEBUG_puts("1ippContainsString: Returning 1 (match)"); return (1); } } default : break; } DEBUG_puts("1ippContainsString: Returning 0 (no match)"); return (0); } /* * 'ippCopyAttribute()' - Copy an attribute. * * The specified attribute, @code attr@, is copied to the destination IPP message. * When @code quickcopy@ is non-zero, a "shallow" reference copy of the attribute is * created - this should only be done as long as the original source IPP message will * not be freed for the life of the destination. * * @since CUPS 1.6/macOS 10.8@ */ ipp_attribute_t * /* O - New attribute */ ippCopyAttribute( ipp_t *dst, /* I - Destination IPP message */ ipp_attribute_t *srcattr, /* I - Attribute to copy */ int quickcopy) /* I - 1 for a referenced copy, 0 for normal */ { int i; /* Looping var */ ipp_attribute_t *dstattr; /* Destination attribute */ _ipp_value_t *srcval, /* Source value */ *dstval; /* Destination value */ DEBUG_printf(("ippCopyAttribute(dst=%p, srcattr=%p, quickcopy=%d)", (void *)dst, (void *)srcattr, quickcopy)); /* * Range check input... */ if (!dst || !srcattr) return (NULL); /* * Copy it... */ quickcopy = quickcopy ? IPP_TAG_CUPS_CONST : 0; switch (srcattr->value_tag & ~IPP_TAG_CUPS_CONST) { case IPP_TAG_ZERO : dstattr = ippAddSeparator(dst); break; case IPP_TAG_UNSUPPORTED_VALUE : case IPP_TAG_DEFAULT : case IPP_TAG_UNKNOWN : case IPP_TAG_NOVALUE : case IPP_TAG_NOTSETTABLE : case IPP_TAG_DELETEATTR : case IPP_TAG_ADMINDEFINE : dstattr = ippAddOutOfBand(dst, srcattr->group_tag, srcattr->value_tag & ~IPP_TAG_CUPS_CONST, srcattr->name); break; case IPP_TAG_INTEGER : case IPP_TAG_ENUM : dstattr = ippAddIntegers(dst, srcattr->group_tag, srcattr->value_tag, srcattr->name, srcattr->num_values, NULL); if (!dstattr) break; for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) dstval->integer = srcval->integer; break; case IPP_TAG_BOOLEAN : dstattr = ippAddBooleans(dst, srcattr->group_tag, srcattr->name, srcattr->num_values, NULL); if (!dstattr) break; for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) dstval->boolean = srcval->boolean; break; case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : dstattr = ippAddStrings(dst, srcattr->group_tag, (ipp_tag_t)(srcattr->value_tag | quickcopy), srcattr->name, srcattr->num_values, NULL, NULL); if (!dstattr) break; if (quickcopy) { for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) dstval->string.text = srcval->string.text; } else if (srcattr->value_tag & IPP_TAG_CUPS_CONST) { for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) dstval->string.text = _cupsStrAlloc(srcval->string.text); } else { for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) dstval->string.text = _cupsStrRetain(srcval->string.text); } break; case IPP_TAG_DATE : if (srcattr->num_values != 1) return (NULL); dstattr = ippAddDate(dst, srcattr->group_tag, srcattr->name, srcattr->values[0].date); break; case IPP_TAG_RESOLUTION : dstattr = ippAddResolutions(dst, srcattr->group_tag, srcattr->name, srcattr->num_values, IPP_RES_PER_INCH, NULL, NULL); if (!dstattr) break; for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) { dstval->resolution.xres = srcval->resolution.xres; dstval->resolution.yres = srcval->resolution.yres; dstval->resolution.units = srcval->resolution.units; } break; case IPP_TAG_RANGE : dstattr = ippAddRanges(dst, srcattr->group_tag, srcattr->name, srcattr->num_values, NULL, NULL); if (!dstattr) break; for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) { dstval->range.lower = srcval->range.lower; dstval->range.upper = srcval->range.upper; } break; case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : dstattr = ippAddStrings(dst, srcattr->group_tag, (ipp_tag_t)(srcattr->value_tag | quickcopy), srcattr->name, srcattr->num_values, NULL, NULL); if (!dstattr) break; if (quickcopy) { for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) { dstval->string.language = srcval->string.language; dstval->string.text = srcval->string.text; } } else if (srcattr->value_tag & IPP_TAG_CUPS_CONST) { for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) { if (srcval == srcattr->values) dstval->string.language = _cupsStrAlloc(srcval->string.language); else dstval->string.language = dstattr->values[0].string.language; dstval->string.text = _cupsStrAlloc(srcval->string.text); } } else { for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) { if (srcval == srcattr->values) dstval->string.language = _cupsStrRetain(srcval->string.language); else dstval->string.language = dstattr->values[0].string.language; dstval->string.text = _cupsStrRetain(srcval->string.text); } } break; case IPP_TAG_BEGIN_COLLECTION : dstattr = ippAddCollections(dst, srcattr->group_tag, srcattr->name, srcattr->num_values, NULL); if (!dstattr) break; for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) { dstval->collection = srcval->collection; srcval->collection->use ++; } break; case IPP_TAG_STRING : default : /* TODO: Implement quick copy for unknown/octetString values */ dstattr = ippAddIntegers(dst, srcattr->group_tag, srcattr->value_tag, srcattr->name, srcattr->num_values, NULL); if (!dstattr) break; for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) { dstval->unknown.length = srcval->unknown.length; if (dstval->unknown.length > 0) { if ((dstval->unknown.data = malloc((size_t)dstval->unknown.length)) == NULL) dstval->unknown.length = 0; else memcpy(dstval->unknown.data, srcval->unknown.data, (size_t)dstval->unknown.length); } } break; /* anti-compiler-warning-code */ } return (dstattr); } /* * 'ippCopyAttributes()' - Copy attributes from one IPP message to another. * * Zero or more attributes are copied from the source IPP message, @code src@, to the * destination IPP message, @code dst@. When @code quickcopy@ is non-zero, a "shallow" * reference copy of the attribute is created - this should only be done as long as the * original source IPP message will not be freed for the life of the destination. * * The @code cb@ and @code context@ parameters provide a generic way to "filter" the * attributes that are copied - the function must return 1 to copy the attribute or * 0 to skip it. The function may also choose to do a partial copy of the source attribute * itself. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on error */ ippCopyAttributes( ipp_t *dst, /* I - Destination IPP message */ ipp_t *src, /* I - Source IPP message */ int quickcopy, /* I - 1 for a referenced copy, 0 for normal */ ipp_copycb_t cb, /* I - Copy callback or @code NULL@ for none */ void *context) /* I - Context pointer */ { ipp_attribute_t *srcattr; /* Source attribute */ DEBUG_printf(("ippCopyAttributes(dst=%p, src=%p, quickcopy=%d, cb=%p, context=%p)", (void *)dst, (void *)src, quickcopy, (void *)cb, context)); /* * Range check input... */ if (!dst || !src) return (0); /* * Loop through source attributes and copy as needed... */ for (srcattr = src->attrs; srcattr; srcattr = srcattr->next) if (!cb || (*cb)(context, dst, srcattr)) if (!ippCopyAttribute(dst, srcattr, quickcopy)) return (0); return (1); } /* * 'ippDateToTime()' - Convert from RFC 2579 Date/Time format to time in * seconds. */ time_t /* O - UNIX time value */ ippDateToTime(const ipp_uchar_t *date) /* I - RFC 2579 date info */ { struct tm unixdate; /* UNIX date/time info */ time_t t; /* Computed time */ if (!date) return (0); memset(&unixdate, 0, sizeof(unixdate)); /* * RFC-2579 date/time format is: * * Byte(s) Description * ------- ----------- * 0-1 Year (0 to 65535) * 2 Month (1 to 12) * 3 Day (1 to 31) * 4 Hours (0 to 23) * 5 Minutes (0 to 59) * 6 Seconds (0 to 60, 60 = "leap second") * 7 Deciseconds (0 to 9) * 8 +/- UTC * 9 UTC hours (0 to 11) * 10 UTC minutes (0 to 59) */ unixdate.tm_year = ((date[0] << 8) | date[1]) - 1900; unixdate.tm_mon = date[2] - 1; unixdate.tm_mday = date[3]; unixdate.tm_hour = date[4]; unixdate.tm_min = date[5]; unixdate.tm_sec = date[6]; t = mktime(&unixdate); if (date[8] == '-') t += date[9] * 3600 + date[10] * 60; else t -= date[9] * 3600 + date[10] * 60; return (t); } /* * 'ippDelete()' - Delete an IPP message. */ void ippDelete(ipp_t *ipp) /* I - IPP message */ { ipp_attribute_t *attr, /* Current attribute */ *next; /* Next attribute */ DEBUG_printf(("ippDelete(ipp=%p)", (void *)ipp)); if (!ipp) return; ipp->use --; if (ipp->use > 0) { DEBUG_printf(("4debug_retain: %p IPP message (use=%d)", (void *)ipp, ipp->use)); return; } DEBUG_printf(("4debug_free: %p IPP message", (void *)ipp)); for (attr = ipp->attrs; attr != NULL; attr = next) { next = attr->next; DEBUG_printf(("4debug_free: %p %s %s%s (%d values)", (void *)attr, attr->name, attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag), attr->num_values)); ipp_free_values(attr, 0, attr->num_values); if (attr->name) _cupsStrFree(attr->name); free(attr); } free(ipp); } /* * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message. * * @since CUPS 1.1.19/macOS 10.3@ */ void ippDeleteAttribute( ipp_t *ipp, /* I - IPP message */ ipp_attribute_t *attr) /* I - Attribute to delete */ { ipp_attribute_t *current, /* Current attribute */ *prev; /* Previous attribute */ DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p(%s))", (void *)ipp, (void *)attr, attr ? attr->name : "(null)")); /* * Range check input... */ if (!attr) return; DEBUG_printf(("4debug_free: %p %s %s%s (%d values)", (void *)attr, attr->name, attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag), attr->num_values)); /* * Find the attribute in the list... */ if (ipp) { for (current = ipp->attrs, prev = NULL; current; prev = current, current = current->next) if (current == attr) { /* * Found it, remove the attribute from the list... */ if (prev) prev->next = current->next; else ipp->attrs = current->next; if (current == ipp->last) ipp->last = prev; break; } if (!current) return; } /* * Free memory used by the attribute... */ ipp_free_values(attr, 0, attr->num_values); if (attr->name) _cupsStrFree(attr->name); free(attr); } /* * 'ippDeleteValues()' - Delete values in an attribute. * * The @code element@ parameter specifies the first value to delete, starting at * 0. It must be less than the number of values returned by @link ippGetCount@. * * The @code attr@ parameter may be modified as a result of setting the value. * * Deleting all values in an attribute deletes the attribute. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippDeleteValues( ipp_t *ipp, /* I - IPP message */ ipp_attribute_t **attr, /* IO - Attribute */ int element, /* I - Index of first value to delete (0-based) */ int count) /* I - Number of values to delete */ { /* * Range check input... */ if (!ipp || !attr || !*attr || element < 0 || element >= (*attr)->num_values || count <= 0 || (element + count) >= (*attr)->num_values) return (0); /* * If we are deleting all values, just delete the attribute entirely. */ if (count == (*attr)->num_values) { ippDeleteAttribute(ipp, *attr); *attr = NULL; return (1); } /* * Otherwise free the values in question and return. */ ipp_free_values(*attr, element, count); return (1); } /* * 'ippFindAttribute()' - Find a named attribute in a request. * * Starting with CUPS 2.0, the attribute name can contain a hierarchical list * of attribute and member names separated by slashes, for example * "media-col/media-size". */ ipp_attribute_t * /* O - Matching attribute */ ippFindAttribute(ipp_t *ipp, /* I - IPP message */ const char *name, /* I - Name of attribute */ ipp_tag_t type) /* I - Type of attribute */ { DEBUG_printf(("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", (void *)ipp, name, type, ippTagString(type))); if (!ipp || !name) return (NULL); /* * Reset the current pointer... */ ipp->current = NULL; ipp->atend = 0; /* * Search for the attribute... */ return (ippFindNextAttribute(ipp, name, type)); } /* * 'ippFindNextAttribute()' - Find the next named attribute in a request. * * Starting with CUPS 2.0, the attribute name can contain a hierarchical list * of attribute and member names separated by slashes, for example * "media-col/media-size". */ ipp_attribute_t * /* O - Matching attribute */ ippFindNextAttribute(ipp_t *ipp, /* I - IPP message */ const char *name, /* I - Name of attribute */ ipp_tag_t type) /* I - Type of attribute */ { ipp_attribute_t *attr, /* Current atttribute */ *childattr; /* Child attribute */ ipp_tag_t value_tag; /* Value tag */ char parent[1024], /* Parent attribute name */ *child = NULL; /* Child attribute name */ DEBUG_printf(("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", (void *)ipp, name, type, ippTagString(type))); if (!ipp || !name) return (NULL); DEBUG_printf(("3ippFindNextAttribute: atend=%d", ipp->atend)); if (ipp->atend) return (NULL); if (strchr(name, '/')) { /* * Search for child attribute... */ strlcpy(parent, name, sizeof(parent)); if ((child = strchr(parent, '/')) == NULL) { DEBUG_puts("3ippFindNextAttribute: Attribute name too long."); return (NULL); } *child++ = '\0'; if (ipp->current && ipp->current->name && ipp->current->value_tag == IPP_TAG_BEGIN_COLLECTION && !strcmp(parent, ipp->current->name)) { while (ipp->curindex < ipp->current->num_values) { if ((childattr = ippFindNextAttribute(ipp->current->values[ipp->curindex].collection, child, type)) != NULL) return (childattr); ipp->curindex ++; if (ipp->curindex < ipp->current->num_values && ipp->current->values[ipp->curindex].collection) ipp->current->values[ipp->curindex].collection->current = NULL; } ipp->prev = ipp->current; ipp->current = ipp->current->next; ipp->curindex = 0; if (!ipp->current) { ipp->atend = 1; return (NULL); } } if (!ipp->current) { ipp->prev = NULL; ipp->current = ipp->attrs; ipp->curindex = 0; } name = parent; attr = ipp->current; } else if (ipp->current) { ipp->prev = ipp->current; attr = ipp->current->next; } else { ipp->prev = NULL; attr = ipp->attrs; } for (; attr != NULL; ipp->prev = attr, attr = attr->next) { DEBUG_printf(("4ippFindAttribute: attr=%p, name=\"%s\"", (void *)attr, attr->name)); value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_CUPS_MASK); if (attr->name != NULL && _cups_strcasecmp(attr->name, name) == 0 && (value_tag == type || type == IPP_TAG_ZERO || name == parent || (value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) || (value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME))) { ipp->current = attr; if (name == parent && attr->value_tag == IPP_TAG_BEGIN_COLLECTION) { int i; /* Looping var */ for (i = 0; i < attr->num_values; i ++) { if ((childattr = ippFindAttribute(attr->values[i].collection, child, type)) != NULL) { attr->values[0].collection->curindex = i; return (childattr); } } } else return (attr); } } ipp->current = NULL; ipp->prev = NULL; ipp->atend = 1; return (NULL); } /* * 'ippFirstAttribute()' - Return the first attribute in the message. * * @since CUPS 1.6/macOS 10.8@ */ ipp_attribute_t * /* O - First attribute or @code NULL@ if none */ ippFirstAttribute(ipp_t *ipp) /* I - IPP message */ { /* * Range check input... */ if (!ipp) return (NULL); /* * Return the first attribute... */ return (ipp->current = ipp->attrs); } /* * 'ippGetBoolean()' - Get a boolean value for an attribute. * * The @code element@ parameter specifies which value to get from 0 to * @code ippGetCount(attr)@ - 1. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - Boolean value or 0 on error */ ippGetBoolean(ipp_attribute_t *attr, /* I - IPP attribute */ int element) /* I - Value number (0-based) */ { /* * Range check input... */ if (!attr || attr->value_tag != IPP_TAG_BOOLEAN || element < 0 || element >= attr->num_values) return (0); /* * Return the value... */ return (attr->values[element].boolean); } /* * 'ippGetCollection()' - Get a collection value for an attribute. * * The @code element@ parameter specifies which value to get from 0 to * @code ippGetCount(attr)@ - 1. * * @since CUPS 1.6/macOS 10.8@ */ ipp_t * /* O - Collection value or @code NULL@ on error */ ippGetCollection( ipp_attribute_t *attr, /* I - IPP attribute */ int element) /* I - Value number (0-based) */ { /* * Range check input... */ if (!attr || attr->value_tag != IPP_TAG_BEGIN_COLLECTION || element < 0 || element >= attr->num_values) return (NULL); /* * Return the value... */ return (attr->values[element].collection); } /* * 'ippGetCount()' - Get the number of values in an attribute. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - Number of values or 0 on error */ ippGetCount(ipp_attribute_t *attr) /* I - IPP attribute */ { /* * Range check input... */ if (!attr) return (0); /* * Return the number of values... */ return (attr->num_values); } /* * 'ippGetDate()' - Get a dateTime value for an attribute. * * The @code element@ parameter specifies which value to get from 0 to * @code ippGetCount(attr)@ - 1. * * @since CUPS 1.6/macOS 10.8@ */ const ipp_uchar_t * /* O - dateTime value or @code NULL@ */ ippGetDate(ipp_attribute_t *attr, /* I - IPP attribute */ int element) /* I - Value number (0-based) */ { /* * Range check input... */ if (!attr || attr->value_tag != IPP_TAG_DATE || element < 0 || element >= attr->num_values) return (NULL); /* * Return the value... */ return (attr->values[element].date); } /* * 'ippGetGroupTag()' - Get the group associated with an attribute. * * @since CUPS 1.6/macOS 10.8@ */ ipp_tag_t /* O - Group tag or @code IPP_TAG_ZERO@ on error */ ippGetGroupTag(ipp_attribute_t *attr) /* I - IPP attribute */ { /* * Range check input... */ if (!attr) return (IPP_TAG_ZERO); /* * Return the group... */ return (attr->group_tag); } /* * 'ippGetInteger()' - Get the integer/enum value for an attribute. * * The @code element@ parameter specifies which value to get from 0 to * @code ippGetCount(attr)@ - 1. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - Value or 0 on error */ ippGetInteger(ipp_attribute_t *attr, /* I - IPP attribute */ int element) /* I - Value number (0-based) */ { /* * Range check input... */ if (!attr || (attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM) || element < 0 || element >= attr->num_values) return (0); /* * Return the value... */ return (attr->values[element].integer); } /* * 'ippGetName()' - Get the attribute name. * * @since CUPS 1.6/macOS 10.8@ */ const char * /* O - Attribute name or @code NULL@ for separators */ ippGetName(ipp_attribute_t *attr) /* I - IPP attribute */ { /* * Range check input... */ if (!attr) return (NULL); /* * Return the name... */ return (attr->name); } /* * 'ippGetOctetString()' - Get an octetString value from an IPP attribute. * * The @code element@ parameter specifies which value to get from 0 to * @code ippGetCount(attr)@ - 1. * * @since CUPS 1.7/macOS 10.9@ */ void * /* O - Pointer to octetString data */ ippGetOctetString( ipp_attribute_t *attr, /* I - IPP attribute */ int element, /* I - Value number (0-based) */ int *datalen) /* O - Length of octetString data */ { /* * Range check input... */ if (!attr || attr->value_tag != IPP_TAG_STRING || element < 0 || element >= attr->num_values) { if (datalen) *datalen = 0; return (NULL); } /* * Return the values... */ if (datalen) *datalen = attr->values[element].unknown.length; return (attr->values[element].unknown.data); } /* * 'ippGetOperation()' - Get the operation ID in an IPP message. * * @since CUPS 1.6/macOS 10.8@ */ ipp_op_t /* O - Operation ID or 0 on error */ ippGetOperation(ipp_t *ipp) /* I - IPP request message */ { /* * Range check input... */ if (!ipp) return ((ipp_op_t)0); /* * Return the value... */ return (ipp->request.op.operation_id); } /* * 'ippGetRange()' - Get a rangeOfInteger value from an attribute. * * The @code element@ parameter specifies which value to get from 0 to * @code ippGetCount(attr)@ - 1. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - Lower value of range or 0 */ ippGetRange(ipp_attribute_t *attr, /* I - IPP attribute */ int element, /* I - Value number (0-based) */ int *uppervalue)/* O - Upper value of range */ { /* * Range check input... */ if (!attr || attr->value_tag != IPP_TAG_RANGE || element < 0 || element >= attr->num_values) { if (uppervalue) *uppervalue = 0; return (0); } /* * Return the values... */ if (uppervalue) *uppervalue = attr->values[element].range.upper; return (attr->values[element].range.lower); } /* * 'ippGetRequestId()' - Get the request ID from an IPP message. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - Request ID or 0 on error */ ippGetRequestId(ipp_t *ipp) /* I - IPP message */ { /* * Range check input... */ if (!ipp) return (0); /* * Return the request ID... */ return (ipp->request.any.request_id); } /* * 'ippGetResolution()' - Get a resolution value for an attribute. * * The @code element@ parameter specifies which value to get from 0 to * @code ippGetCount(attr)@ - 1. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - Horizontal/cross feed resolution or 0 */ ippGetResolution( ipp_attribute_t *attr, /* I - IPP attribute */ int element, /* I - Value number (0-based) */ int *yres, /* O - Vertical/feed resolution */ ipp_res_t *units) /* O - Units for resolution */ { /* * Range check input... */ if (!attr || attr->value_tag != IPP_TAG_RESOLUTION || element < 0 || element >= attr->num_values) { if (yres) *yres = 0; if (units) *units = (ipp_res_t)0; return (0); } /* * Return the value... */ if (yres) *yres = attr->values[element].resolution.yres; if (units) *units = attr->values[element].resolution.units; return (attr->values[element].resolution.xres); } /* * 'ippGetState()' - Get the IPP message state. * * @since CUPS 1.6/macOS 10.8@ */ ipp_state_t /* O - IPP message state value */ ippGetState(ipp_t *ipp) /* I - IPP message */ { /* * Range check input... */ if (!ipp) return (IPP_STATE_IDLE); /* * Return the value... */ return (ipp->state); } /* * 'ippGetStatusCode()' - Get the status code from an IPP response or event message. * * @since CUPS 1.6/macOS 10.8@ */ ipp_status_t /* O - Status code in IPP message */ ippGetStatusCode(ipp_t *ipp) /* I - IPP response or event message */ { /* * Range check input... */ if (!ipp) return (IPP_STATUS_ERROR_INTERNAL); /* * Return the value... */ return (ipp->request.status.status_code); } /* * 'ippGetString()' - Get the string and optionally the language code for an attribute. * * The @code element@ parameter specifies which value to get from 0 to * @code ippGetCount(attr)@ - 1. * * @since CUPS 1.6/macOS 10.8@ */ const char * ippGetString(ipp_attribute_t *attr, /* I - IPP attribute */ int element, /* I - Value number (0-based) */ const char **language)/* O - Language code (@code NULL@ for don't care) */ { ipp_tag_t tag; /* Value tag */ /* * Range check input... */ tag = ippGetValueTag(attr); if (!attr || element < 0 || element >= attr->num_values || (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG && (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE))) return (NULL); /* * Return the value... */ if (language) *language = attr->values[element].string.language; return (attr->values[element].string.text); } /* * 'ippGetValueTag()' - Get the value tag for an attribute. * * @since CUPS 1.6/macOS 10.8@ */ ipp_tag_t /* O - Value tag or @code IPP_TAG_ZERO@ on error */ ippGetValueTag(ipp_attribute_t *attr) /* I - IPP attribute */ { /* * Range check input... */ if (!attr) return (IPP_TAG_ZERO); /* * Return the value... */ return (attr->value_tag & IPP_TAG_CUPS_MASK); } /* * 'ippGetVersion()' - Get the major and minor version number from an IPP message. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - Major version number or 0 on error */ ippGetVersion(ipp_t *ipp, /* I - IPP message */ int *minor) /* O - Minor version number or @code NULL@ for don't care */ { /* * Range check input... */ if (!ipp) { if (minor) *minor = 0; return (0); } /* * Return the value... */ if (minor) *minor = ipp->request.any.version[1]; return (ipp->request.any.version[0]); } /* * 'ippLength()' - Compute the length of an IPP message. */ size_t /* O - Size of IPP message */ ippLength(ipp_t *ipp) /* I - IPP message */ { return (ipp_length(ipp, 0)); } /* * 'ippNextAttribute()' - Return the next attribute in the message. * * @since CUPS 1.6/macOS 10.8@ */ ipp_attribute_t * /* O - Next attribute or @code NULL@ if none */ ippNextAttribute(ipp_t *ipp) /* I - IPP message */ { /* * Range check input... */ if (!ipp || !ipp->current) return (NULL); /* * Return the next attribute... */ return (ipp->current = ipp->current->next); } /* * 'ippNew()' - Allocate a new IPP message. */ ipp_t * /* O - New IPP message */ ippNew(void) { ipp_t *temp; /* New IPP message */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ DEBUG_puts("ippNew()"); if ((temp = (ipp_t *)calloc(1, sizeof(ipp_t))) != NULL) { /* * Set default version - usually 2.0... */ DEBUG_printf(("4debug_alloc: %p IPP message", (void *)temp)); if (cg->server_version == 0) _cupsSetDefaults(); temp->request.any.version[0] = (ipp_uchar_t)(cg->server_version / 10); temp->request.any.version[1] = (ipp_uchar_t)(cg->server_version % 10); temp->use = 1; } DEBUG_printf(("1ippNew: Returning %p", (void *)temp)); return (temp); } /* * 'ippNewRequest()' - Allocate a new IPP request message. * * The new request message is initialized with the "attributes-charset" and * "attributes-natural-language" attributes added. The * "attributes-natural-language" value is derived from the current locale. * * @since CUPS 1.2/macOS 10.5@ */ ipp_t * /* O - IPP request message */ ippNewRequest(ipp_op_t op) /* I - Operation code */ { ipp_t *request; /* IPP request message */ cups_lang_t *language; /* Current language localization */ static int request_id = 0; /* Current request ID */ static _cups_mutex_t request_mutex = _CUPS_MUTEX_INITIALIZER; /* Mutex for request ID */ DEBUG_printf(("ippNewRequest(op=%02x(%s))", op, ippOpString(op))); /* * Create a new IPP message... */ if ((request = ippNew()) == NULL) return (NULL); /* * Set the operation and request ID... */ _cupsMutexLock(&request_mutex); request->request.op.operation_id = op; request->request.op.request_id = ++request_id; _cupsMutexUnlock(&request_mutex); /* * Use UTF-8 as the character set... */ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, "utf-8"); /* * Get the language from the current locale... */ language = cupsLangDefault(); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, language->language); /* * Return the new request... */ return (request); } /* * 'ippNewResponse()' - Allocate a new IPP response message. * * The new response message is initialized with the same "version-number", * "request-id", "attributes-charset", and "attributes-natural-language" as the * provided request message. If the "attributes-charset" or * "attributes-natural-language" attributes are missing from the request, * 'utf-8' and a value derived from the current locale are substituted, * respectively. * * @since CUPS 1.7/macOS 10.9@ */ ipp_t * /* O - IPP response message */ ippNewResponse(ipp_t *request) /* I - IPP request message */ { ipp_t *response; /* IPP response message */ ipp_attribute_t *attr; /* Current attribute */ /* * Range check input... */ if (!request) return (NULL); /* * Create a new IPP message... */ if ((response = ippNew()) == NULL) return (NULL); /* * Copy the request values over to the response... */ response->request.status.version[0] = request->request.op.version[0]; response->request.status.version[1] = request->request.op.version[1]; response->request.status.request_id = request->request.op.request_id; /* * The first attribute MUST be attributes-charset... */ attr = request->attrs; if (attr && attr->name && !strcmp(attr->name, "attributes-charset") && attr->group_tag == IPP_TAG_OPERATION && attr->value_tag == IPP_TAG_CHARSET && attr->num_values == 1) { /* * Copy charset from request... */ ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, attr->values[0].string.text); } else { /* * Use "utf-8" as the default... */ ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, "utf-8"); } /* * Then attributes-natural-language... */ if (attr) attr = attr->next; if (attr && attr->name && !strcmp(attr->name, "attributes-natural-language") && attr->group_tag == IPP_TAG_OPERATION && attr->value_tag == IPP_TAG_LANGUAGE && attr->num_values == 1) { /* * Copy language from request... */ ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, attr->values[0].string.text); } else { /* * Use the language from the current locale... */ cups_lang_t *language = cupsLangDefault(); /* Current locale */ ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, language->language); } return (response); } /* * 'ippRead()' - Read data for an IPP message from a HTTP connection. */ ipp_state_t /* O - Current state */ ippRead(http_t *http, /* I - HTTP connection */ ipp_t *ipp) /* I - IPP data */ { DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT, (void *)http, (void *)ipp, CUPS_LLCAST (http ? http->data_remaining : -1))); if (!http) return (IPP_STATE_ERROR); DEBUG_printf(("2ippRead: http->state=%d, http->used=%d", http->state, http->used)); return (ippReadIO(http, (ipp_iocb_t)ipp_read_http, http->blocking, NULL, ipp)); } /* * 'ippReadFile()' - Read data for an IPP message from a file. * * @since CUPS 1.1.19/macOS 10.3@ */ ipp_state_t /* O - Current state */ ippReadFile(int fd, /* I - HTTP data */ ipp_t *ipp) /* I - IPP data */ { DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)", fd, (void *)ipp)); return (ippReadIO(&fd, (ipp_iocb_t)ipp_read_file, 1, NULL, ipp)); } /* * 'ippReadIO()' - Read data for an IPP message. * * @since CUPS 1.2/macOS 10.5@ */ ipp_state_t /* O - Current state */ ippReadIO(void *src, /* I - Data source */ ipp_iocb_t cb, /* I - Read callback function */ int blocking, /* I - Use blocking IO? */ ipp_t *parent, /* I - Parent request, if any */ ipp_t *ipp) /* I - IPP data */ { int n; /* Length of data */ unsigned char *buffer, /* Data buffer */ string[IPP_MAX_TEXT], /* Small string buffer */ *bufptr; /* Pointer into buffer */ ipp_attribute_t *attr; /* Current attribute */ ipp_tag_t tag; /* Current tag */ ipp_tag_t value_tag; /* Current value tag */ _ipp_value_t *value; /* Current value */ DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)src, (void *)cb, blocking, (void *)parent, (void *)ipp)); DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp ? ipp->state : IPP_STATE_ERROR)); if (!src || !ipp) return (IPP_STATE_ERROR); if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL) { DEBUG_puts("1ippReadIO: Unable to get read buffer."); return (IPP_STATE_ERROR); } switch (ipp->state) { case IPP_STATE_IDLE : ipp->state ++; /* Avoid common problem... */ case IPP_STATE_HEADER : if (parent == NULL) { /* * Get the request header... */ if ((*cb)(src, buffer, 8) < 8) { DEBUG_puts("1ippReadIO: Unable to read header."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } /* * Then copy the request header over... */ ipp->request.any.version[0] = buffer[0]; ipp->request.any.version[1] = buffer[1]; ipp->request.any.op_status = (buffer[2] << 8) | buffer[3]; ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) | buffer[7]; DEBUG_printf(("2ippReadIO: version=%d.%d", buffer[0], buffer[1])); DEBUG_printf(("2ippReadIO: op_status=%04x", ipp->request.any.op_status)); DEBUG_printf(("2ippReadIO: request_id=%d", ipp->request.any.request_id)); } ipp->state = IPP_STATE_ATTRIBUTE; ipp->current = NULL; ipp->curtag = IPP_TAG_ZERO; ipp->prev = ipp->last; /* * If blocking is disabled, stop here... */ if (!blocking) break; case IPP_STATE_ATTRIBUTE : for (;;) { if ((*cb)(src, buffer, 1) < 1) { DEBUG_puts("1ippReadIO: Callback returned EOF/error"); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev)); /* * Read this attribute... */ tag = (ipp_tag_t)buffer[0]; if (tag == IPP_TAG_EXTENSION) { /* * Read 32-bit "extension" tag... */ if ((*cb)(src, buffer, 4) < 1) { DEBUG_puts("1ippReadIO: Callback returned EOF/error"); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } tag = (ipp_tag_t)((((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) | buffer[3]); if (tag & IPP_TAG_CUPS_CONST) { /* * Fail if the high bit is set in the tag... */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP extension tag larger than 0x7FFFFFFF."), 1); DEBUG_printf(("1ippReadIO: bad tag 0x%x.", tag)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } } if (tag == IPP_TAG_END) { /* * No more attributes left... */ DEBUG_puts("2ippReadIO: IPP_TAG_END."); ipp->state = IPP_STATE_DATA; break; } else if (tag < IPP_TAG_UNSUPPORTED_VALUE) { /* * Group tag... Set the current group and continue... */ if (ipp->curtag == tag) ipp->prev = ippAddSeparator(ipp); else if (ipp->current) ipp->prev = ipp->current; ipp->curtag = tag; ipp->current = NULL; DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag, ippTagString(tag), (void *)ipp->prev)); continue; } DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag, ippTagString(tag))); /* * Get the name... */ if ((*cb)(src, buffer, 2) < 2) { DEBUG_puts("1ippReadIO: unable to read name length."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } n = (buffer[0] << 8) | buffer[1]; if (n >= IPP_BUF_SIZE) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP name larger than 32767 bytes."), 1); DEBUG_printf(("1ippReadIO: bad name length %d.", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } DEBUG_printf(("2ippReadIO: name length=%d", n)); if (n == 0 && tag != IPP_TAG_MEMBERNAME && tag != IPP_TAG_END_COLLECTION) { /* * More values for current attribute... */ if (ipp->current == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP attribute has no name."), 1); DEBUG_puts("1ippReadIO: Attribute without name and no current."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } attr = ipp->current; value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_CUPS_MASK); /* * Make sure we aren't adding a new value of a different * type... */ if (value_tag == IPP_TAG_ZERO) { /* * Setting the value of a collection member... */ attr->value_tag = tag; } else if (value_tag == IPP_TAG_TEXTLANG || value_tag == IPP_TAG_NAMELANG || (value_tag >= IPP_TAG_TEXT && value_tag <= IPP_TAG_MIMETYPE)) { /* * String values can sometimes come across in different * forms; accept sets of differing values... */ if (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG && (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE) && tag != IPP_TAG_NOVALUE) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP 1setOf attribute with incompatible value " "tags."), 1); DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)", value_tag, ippTagString(value_tag), tag, ippTagString(tag))); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } if (value_tag != tag) { DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.", attr->name, ippTagString(value_tag), ippTagString(tag))); ippSetValueTag(ipp, &attr, tag); } } else if (value_tag == IPP_TAG_INTEGER || value_tag == IPP_TAG_RANGE) { /* * Integer and rangeOfInteger values can sometimes be mixed; accept * sets of differing values... */ if (tag != IPP_TAG_INTEGER && tag != IPP_TAG_RANGE) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP 1setOf attribute with incompatible value " "tags."), 1); DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)", value_tag, ippTagString(value_tag), tag, ippTagString(tag))); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } if (value_tag == IPP_TAG_INTEGER && tag == IPP_TAG_RANGE) { /* * Convert integer values to rangeOfInteger values... */ DEBUG_printf(("1ippReadIO: Converting %s attribute to " "rangeOfInteger.", attr->name)); ippSetValueTag(ipp, &attr, IPP_TAG_RANGE); } } else if (value_tag != tag) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP 1setOf attribute with incompatible value " "tags."), 1); DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)", value_tag, ippTagString(value_tag), tag, ippTagString(tag))); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } /* * Finally, reallocate the attribute array as needed... */ if ((value = ipp_set_value(ipp, &attr, attr->num_values)) == NULL) { _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } } else if (tag == IPP_TAG_MEMBERNAME) { /* * Name must be length 0! */ if (n) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP member name is not empty."), 1); DEBUG_puts("1ippReadIO: member name not empty."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } if (ipp->current) ipp->prev = ipp->current; attr = ipp->current = ipp_add_attr(ipp, NULL, ipp->curtag, IPP_TAG_ZERO, 1); if (!attr) { _cupsSetHTTPError(HTTP_STATUS_ERROR); DEBUG_puts("1ippReadIO: unable to allocate attribute."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev)); value = attr->values; } else if (tag != IPP_TAG_END_COLLECTION) { /* * New attribute; read the name and add it... */ if ((*cb)(src, buffer, (size_t)n) < n) { DEBUG_puts("1ippReadIO: unable to read name."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } buffer[n] = '\0'; if (ipp->current) ipp->prev = ipp->current; if ((attr = ipp->current = ipp_add_attr(ipp, (char *)buffer, ipp->curtag, tag, 1)) == NULL) { _cupsSetHTTPError(HTTP_STATUS_ERROR); DEBUG_puts("1ippReadIO: unable to allocate attribute."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, ipp->prev=%p", buffer, (void *)ipp->current, (void *)ipp->prev)); value = attr->values; } else { attr = NULL; value = NULL; } if ((*cb)(src, buffer, 2) < 2) { DEBUG_puts("1ippReadIO: unable to read value length."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } n = (buffer[0] << 8) | buffer[1]; DEBUG_printf(("2ippReadIO: value length=%d", n)); if (n >= IPP_BUF_SIZE) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP value larger than 32767 bytes."), 1); DEBUG_printf(("1ippReadIO: bad value length %d.", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } switch (tag) { case IPP_TAG_INTEGER : case IPP_TAG_ENUM : if (n != 4) { if (tag == IPP_TAG_INTEGER) _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP integer value not 4 bytes."), 1); else _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP enum value not 4 bytes."), 1); DEBUG_printf(("1ippReadIO: bad integer value length %d.", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } if ((*cb)(src, buffer, 4) < 4) { DEBUG_puts("1ippReadIO: Unable to read integer value."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) | buffer[3]; if (attr->value_tag == IPP_TAG_RANGE) value->range.lower = value->range.upper = n; else value->integer = n; break; case IPP_TAG_BOOLEAN : if (n != 1) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP boolean value not 1 byte."), 1); DEBUG_printf(("1ippReadIO: bad boolean value length %d.", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } if ((*cb)(src, buffer, 1) < 1) { DEBUG_puts("1ippReadIO: Unable to read boolean value."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } value->boolean = (char)buffer[0]; break; case IPP_TAG_NOVALUE : case IPP_TAG_NOTSETTABLE : case IPP_TAG_DELETEATTR : case IPP_TAG_ADMINDEFINE : /* * These value types are not supposed to have values, however * some vendors (Brother) do not implement IPP correctly and so * we need to map non-empty values to text... */ if (attr->value_tag == tag) { if (n == 0) break; attr->value_tag = IPP_TAG_TEXT; } case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : if (n > 0) { if ((*cb)(src, buffer, (size_t)n) < n) { DEBUG_puts("1ippReadIO: unable to read string value."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } } buffer[n] = '\0'; value->string.text = _cupsStrAlloc((char *)buffer); DEBUG_printf(("2ippReadIO: value=\"%s\"", value->string.text)); break; case IPP_TAG_DATE : if (n != 11) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP date value not 11 bytes."), 1); DEBUG_printf(("1ippReadIO: bad date value length %d.", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } if ((*cb)(src, value->date, 11) < 11) { DEBUG_puts("1ippReadIO: Unable to read date value."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } break; case IPP_TAG_RESOLUTION : if (n != 9) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP resolution value not 9 bytes."), 1); DEBUG_printf(("1ippReadIO: bad resolution value length %d.", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } if ((*cb)(src, buffer, 9) < 9) { DEBUG_puts("1ippReadIO: Unable to read resolution value."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } value->resolution.xres = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) | buffer[3]; value->resolution.yres = (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) | buffer[7]; value->resolution.units = (ipp_res_t)buffer[8]; break; case IPP_TAG_RANGE : if (n != 8) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP rangeOfInteger value not 8 bytes."), 1); DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length " "%d.", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } if ((*cb)(src, buffer, 8) < 8) { DEBUG_puts("1ippReadIO: Unable to read range value."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } value->range.lower = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) | buffer[3]; value->range.upper = (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) | buffer[7]; break; case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : if (n < 4) { if (tag == IPP_TAG_TEXTLANG) _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP textWithLanguage value less than " "minimum 4 bytes."), 1); else _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP nameWithLanguage value less than " "minimum 4 bytes."), 1); DEBUG_printf(("1ippReadIO: bad stringWithLanguage value " "length %d.", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } if ((*cb)(src, buffer, (size_t)n) < n) { DEBUG_puts("1ippReadIO: Unable to read string w/language " "value."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } bufptr = buffer; /* * text-with-language and name-with-language are composite * values: * * language-length * language * text-length * text */ n = (bufptr[0] << 8) | bufptr[1]; if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE) || n >= (int)sizeof(string)) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP language length overflows value."), 1); DEBUG_printf(("1ippReadIO: bad language value length %d.", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } else if (n >= IPP_MAX_LANGUAGE) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP language length too large."), 1); DEBUG_printf(("1ippReadIO: bad language value length %d.", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } memcpy(string, bufptr + 2, (size_t)n); string[n] = '\0'; value->string.language = _cupsStrAlloc((char *)string); bufptr += 2 + n; n = (bufptr[0] << 8) | bufptr[1]; if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE)) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP string length overflows value."), 1); DEBUG_printf(("1ippReadIO: bad string value length %d.", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } bufptr[2 + n] = '\0'; value->string.text = _cupsStrAlloc((char *)bufptr + 2); break; case IPP_TAG_BEGIN_COLLECTION : /* * Oh, boy, here comes a collection value, so read it... */ value->collection = ippNew(); if (n > 0) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP begCollection value not 0 bytes."), 1); DEBUG_puts("1ippReadIO: begCollection tag with value length " "> 0."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_STATE_ERROR) { DEBUG_puts("1ippReadIO: Unable to read collection value."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } break; case IPP_TAG_END_COLLECTION : _cupsBufferRelease((char *)buffer); if (n > 0) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP endCollection value not 0 bytes."), 1); DEBUG_puts("1ippReadIO: endCollection tag with value length " "> 0."); return (IPP_STATE_ERROR); } DEBUG_puts("1ippReadIO: endCollection tag..."); return (ipp->state = IPP_STATE_DATA); case IPP_TAG_MEMBERNAME : /* * The value the name of the member in the collection, which * we need to carry over... */ if (!attr) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP memberName with no attribute."), 1); DEBUG_puts("1ippReadIO: Member name without attribute."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } else if (n == 0) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP memberName value is empty."), 1); DEBUG_puts("1ippReadIO: Empty member name value."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } else if ((*cb)(src, buffer, (size_t)n) < n) { DEBUG_puts("1ippReadIO: Unable to read member name value."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } buffer[n] = '\0'; attr->name = _cupsStrAlloc((char *)buffer); /* * Since collection members are encoded differently than * regular attributes, make sure we don't start with an * empty value... */ attr->num_values --; DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr->name)); break; default : /* Other unsupported values */ if (tag == IPP_TAG_STRING && n > IPP_MAX_LENGTH) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP octetString length too large."), 1); DEBUG_printf(("1ippReadIO: bad octetString value length %d.", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } value->unknown.length = n; if (n > 0) { if ((value->unknown.data = malloc((size_t)n)) == NULL) { _cupsSetHTTPError(HTTP_STATUS_ERROR); DEBUG_puts("1ippReadIO: Unable to allocate value"); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } if ((*cb)(src, value->unknown.data, (size_t)n) < n) { DEBUG_puts("1ippReadIO: Unable to read unsupported value."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } } else value->unknown.data = NULL; break; } /* * If blocking is disabled, stop here... */ if (!blocking) break; } break; case IPP_STATE_DATA : break; default : break; /* anti-compiler-warning-code */ } DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp->state)); _cupsBufferRelease((char *)buffer); return (ipp->state); } /* * 'ippSetBoolean()' - Set a boolean value in an attribute. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code attr@ parameter may be modified as a result of setting the value. * * The @code element@ parameter specifies which value to set from 0 to * @code ippGetCount(attr)@. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippSetBoolean(ipp_t *ipp, /* I - IPP message */ ipp_attribute_t **attr, /* IO - IPP attribute */ int element, /* I - Value number (0-based) */ int boolvalue)/* I - Boolean value */ { _ipp_value_t *value; /* Current value */ /* * Range check input... */ if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BOOLEAN || element < 0 || element > (*attr)->num_values) return (0); /* * Set the value and return... */ if ((value = ipp_set_value(ipp, attr, element)) != NULL) value->boolean = (char)boolvalue; return (value != NULL); } /* * 'ippSetCollection()' - Set a collection value in an attribute. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code attr@ parameter may be modified as a result of setting the value. * * The @code element@ parameter specifies which value to set from 0 to * @code ippGetCount(attr)@. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippSetCollection( ipp_t *ipp, /* I - IPP message */ ipp_attribute_t **attr, /* IO - IPP attribute */ int element, /* I - Value number (0-based) */ ipp_t *colvalue) /* I - Collection value */ { _ipp_value_t *value; /* Current value */ /* * Range check input... */ if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BEGIN_COLLECTION || element < 0 || element > (*attr)->num_values || !colvalue) return (0); /* * Set the value and return... */ if ((value = ipp_set_value(ipp, attr, element)) != NULL) { if (value->collection) ippDelete(value->collection); value->collection = colvalue; colvalue->use ++; } return (value != NULL); } /* * 'ippSetDate()' - Set a dateTime value in an attribute. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code attr@ parameter may be modified as a result of setting the value. * * The @code element@ parameter specifies which value to set from 0 to * @code ippGetCount(attr)@. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippSetDate(ipp_t *ipp, /* I - IPP message */ ipp_attribute_t **attr, /* IO - IPP attribute */ int element, /* I - Value number (0-based) */ const ipp_uchar_t *datevalue)/* I - dateTime value */ { _ipp_value_t *value; /* Current value */ /* * Range check input... */ if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_DATE || element < 0 || element > (*attr)->num_values || !datevalue) return (0); /* * Set the value and return... */ if ((value = ipp_set_value(ipp, attr, element)) != NULL) memcpy(value->date, datevalue, sizeof(value->date)); return (value != NULL); } /* * 'ippSetGroupTag()' - Set the group tag of an attribute. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code attr@ parameter may be modified as a result of setting the value. * * The @code group@ parameter specifies the IPP attribute group tag: none * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippSetGroupTag( ipp_t *ipp, /* I - IPP message */ ipp_attribute_t **attr, /* IO - Attribute */ ipp_tag_t group_tag) /* I - Group tag */ { /* * Range check input - group tag must be 0x01 to 0x0F, per RFC 8011... */ if (!ipp || !attr || !*attr || group_tag < IPP_TAG_ZERO || group_tag == IPP_TAG_END || group_tag >= IPP_TAG_UNSUPPORTED_VALUE) return (0); /* * Set the group tag and return... */ (*attr)->group_tag = group_tag; return (1); } /* * 'ippSetInteger()' - Set an integer or enum value in an attribute. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code attr@ parameter may be modified as a result of setting the value. * * The @code element@ parameter specifies which value to set from 0 to * @code ippGetCount(attr)@. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippSetInteger(ipp_t *ipp, /* I - IPP message */ ipp_attribute_t **attr, /* IO - IPP attribute */ int element, /* I - Value number (0-based) */ int intvalue) /* I - Integer/enum value */ { _ipp_value_t *value; /* Current value */ /* * Range check input... */ if (!ipp || !attr || !*attr || ((*attr)->value_tag != IPP_TAG_INTEGER && (*attr)->value_tag != IPP_TAG_ENUM) || element < 0 || element > (*attr)->num_values) return (0); /* * Set the value and return... */ if ((value = ipp_set_value(ipp, attr, element)) != NULL) value->integer = intvalue; return (value != NULL); } /* * 'ippSetName()' - Set the name of an attribute. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code attr@ parameter may be modified as a result of setting the value. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippSetName(ipp_t *ipp, /* I - IPP message */ ipp_attribute_t **attr, /* IO - IPP attribute */ const char *name) /* I - Attribute name */ { char *temp; /* Temporary name value */ /* * Range check input... */ if (!ipp || !attr || !*attr) return (0); /* * Set the value and return... */ if ((temp = _cupsStrAlloc(name)) != NULL) { if ((*attr)->name) _cupsStrFree((*attr)->name); (*attr)->name = temp; } return (temp != NULL); } /* * 'ippSetOctetString()' - Set an octetString value in an IPP attribute. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code attr@ parameter may be modified as a result of setting the value. * * The @code element@ parameter specifies which value to set from 0 to * @code ippGetCount(attr)@. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - 1 on success, 0 on failure */ ippSetOctetString( ipp_t *ipp, /* I - IPP message */ ipp_attribute_t **attr, /* IO - IPP attribute */ int element, /* I - Value number (0-based) */ const void *data, /* I - Pointer to octetString data */ int datalen) /* I - Length of octetString data */ { _ipp_value_t *value; /* Current value */ /* * Range check input... */ if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_STRING || element < 0 || element > (*attr)->num_values || datalen < 0 || datalen > IPP_MAX_LENGTH) return (0); /* * Set the value and return... */ if ((value = ipp_set_value(ipp, attr, element)) != NULL) { if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST) { /* * Just copy the pointer... */ value->unknown.data = (void *)data; value->unknown.length = datalen; } else { /* * Copy the data... */ if (value->unknown.data) { /* * Free previous data... */ free(value->unknown.data); value->unknown.data = NULL; value->unknown.length = 0; } if (datalen > 0) { void *temp; /* Temporary data pointer */ if ((temp = malloc((size_t)datalen)) != NULL) { memcpy(temp, data, (size_t)datalen); value->unknown.data = temp; value->unknown.length = datalen; } else return (0); } } } return (value != NULL); } /* * 'ippSetOperation()' - Set the operation ID in an IPP request message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippSetOperation(ipp_t *ipp, /* I - IPP request message */ ipp_op_t op) /* I - Operation ID */ { /* * Range check input... */ if (!ipp) return (0); /* * Set the operation and return... */ ipp->request.op.operation_id = op; return (1); } /* * 'ippSetRange()' - Set a rangeOfInteger value in an attribute. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code attr@ parameter may be modified as a result of setting the value. * * The @code element@ parameter specifies which value to set from 0 to * @code ippGetCount(attr)@. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippSetRange(ipp_t *ipp, /* I - IPP message */ ipp_attribute_t **attr, /* IO - IPP attribute */ int element, /* I - Value number (0-based) */ int lowervalue, /* I - Lower bound for range */ int uppervalue) /* I - Upper bound for range */ { _ipp_value_t *value; /* Current value */ /* * Range check input... */ if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_RANGE || element < 0 || element > (*attr)->num_values || lowervalue > uppervalue) return (0); /* * Set the value and return... */ if ((value = ipp_set_value(ipp, attr, element)) != NULL) { value->range.lower = lowervalue; value->range.upper = uppervalue; } return (value != NULL); } /* * 'ippSetRequestId()' - Set the request ID in an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code request_id@ parameter must be greater than 0. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippSetRequestId(ipp_t *ipp, /* I - IPP message */ int request_id) /* I - Request ID */ { /* * Range check input; not checking request_id values since ipptool wants to send * invalid values for conformance testing and a bad request_id does not affect the * encoding of a message... */ if (!ipp) return (0); /* * Set the request ID and return... */ ipp->request.any.request_id = request_id; return (1); } /* * 'ippSetResolution()' - Set a resolution value in an attribute. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code attr@ parameter may be modified as a result of setting the value. * * The @code element@ parameter specifies which value to set from 0 to * @code ippGetCount(attr)@. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippSetResolution( ipp_t *ipp, /* I - IPP message */ ipp_attribute_t **attr, /* IO - IPP attribute */ int element, /* I - Value number (0-based) */ ipp_res_t unitsvalue, /* I - Resolution units */ int xresvalue, /* I - Horizontal/cross feed resolution */ int yresvalue) /* I - Vertical/feed resolution */ { _ipp_value_t *value; /* Current value */ /* * Range check input... */ if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_RESOLUTION || element < 0 || element > (*attr)->num_values || xresvalue <= 0 || yresvalue <= 0 || unitsvalue < IPP_RES_PER_INCH || unitsvalue > IPP_RES_PER_CM) return (0); /* * Set the value and return... */ if ((value = ipp_set_value(ipp, attr, element)) != NULL) { value->resolution.units = unitsvalue; value->resolution.xres = xresvalue; value->resolution.yres = yresvalue; } return (value != NULL); } /* * 'ippSetState()' - Set the current state of the IPP message. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippSetState(ipp_t *ipp, /* I - IPP message */ ipp_state_t state) /* I - IPP state value */ { /* * Range check input... */ if (!ipp) return (0); /* * Set the state and return... */ ipp->state = state; ipp->current = NULL; return (1); } /* * 'ippSetStatusCode()' - Set the status code in an IPP response or event message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippSetStatusCode(ipp_t *ipp, /* I - IPP response or event message */ ipp_status_t status) /* I - Status code */ { /* * Range check input... */ if (!ipp) return (0); /* * Set the status code and return... */ ipp->request.status.status_code = status; return (1); } /* * 'ippSetString()' - Set a string value in an attribute. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code attr@ parameter may be modified as a result of setting the value. * * The @code element@ parameter specifies which value to set from 0 to * @code ippGetCount(attr)@. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippSetString(ipp_t *ipp, /* I - IPP message */ ipp_attribute_t **attr, /* IO - IPP attribute */ int element, /* I - Value number (0-based) */ const char *strvalue) /* I - String value */ { char *temp; /* Temporary string */ _ipp_value_t *value; /* Current value */ /* * Range check input... */ if (!ipp || !attr || !*attr || ((*attr)->value_tag != IPP_TAG_TEXTLANG && (*attr)->value_tag != IPP_TAG_NAMELANG && ((*attr)->value_tag < IPP_TAG_TEXT || (*attr)->value_tag > IPP_TAG_MIMETYPE)) || element < 0 || element > (*attr)->num_values || !strvalue) return (0); /* * Set the value and return... */ if ((value = ipp_set_value(ipp, attr, element)) != NULL) { if (element > 0) value->string.language = (*attr)->values[0].string.language; if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST) value->string.text = (char *)strvalue; else if ((temp = _cupsStrAlloc(strvalue)) != NULL) { if (value->string.text) _cupsStrFree(value->string.text); value->string.text = temp; } else return (0); } return (value != NULL); } /* * 'ippSetStringf()' - Set a formatted string value of an attribute. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code attr@ parameter may be modified as a result of setting the value. * * The @code element@ parameter specifies which value to set from 0 to * @code ippGetCount(attr)@. * * The @code format@ parameter uses formatting characters compatible with the * printf family of standard functions. Additional arguments follow it as * needed. The formatted string is truncated as needed to the maximum length of * the corresponding value type. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - 1 on success, 0 on failure */ ippSetStringf(ipp_t *ipp, /* I - IPP message */ ipp_attribute_t **attr, /* IO - IPP attribute */ int element, /* I - Value number (0-based) */ const char *format, /* I - Printf-style format string */ ...) /* I - Additional arguments as needed */ { int ret; /* Return value */ va_list ap; /* Pointer to additional arguments */ va_start(ap, format); ret = ippSetStringfv(ipp, attr, element, format, ap); va_end(ap); return (ret); } /* * 'ippSetStringf()' - Set a formatted string value of an attribute. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code attr@ parameter may be modified as a result of setting the value. * * The @code element@ parameter specifies which value to set from 0 to * @code ippGetCount(attr)@. * * The @code format@ parameter uses formatting characters compatible with the * printf family of standard functions. Additional arguments follow it as * needed. The formatted string is truncated as needed to the maximum length of * the corresponding value type. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - 1 on success, 0 on failure */ ippSetStringfv(ipp_t *ipp, /* I - IPP message */ ipp_attribute_t **attr, /* IO - IPP attribute */ int element, /* I - Value number (0-based) */ const char *format, /* I - Printf-style format string */ va_list ap) /* I - Pointer to additional arguments */ { ipp_tag_t value_tag; /* Value tag */ char buffer[IPP_MAX_TEXT + 4]; /* Formatted text string */ ssize_t bytes, /* Length of formatted value */ max_bytes; /* Maximum number of bytes for value */ /* * Range check input... */ if (attr && *attr) value_tag = (*attr)->value_tag & IPP_TAG_CUPS_MASK; else value_tag = IPP_TAG_ZERO; if (!ipp || !attr || !*attr || (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG && value_tag != IPP_TAG_NAMELANG) || value_tag > IPP_TAG_MIMETYPE || !format) return (0); /* * Format the string... */ if (!strcmp(format, "%s")) { /* * Optimize the simple case... */ const char *s = va_arg(ap, char *); if (!s) s = "(null)"; bytes = (ssize_t)strlen(s); strlcpy(buffer, s, sizeof(buffer)); } else { /* * Do a full formatting of the message... */ if ((bytes = vsnprintf(buffer, sizeof(buffer), format, ap)) < 0) return (0); } /* * Limit the length of the string... */ switch (value_tag) { default : case IPP_TAG_TEXT : case IPP_TAG_TEXTLANG : max_bytes = IPP_MAX_TEXT; break; case IPP_TAG_NAME : case IPP_TAG_NAMELANG : max_bytes = IPP_MAX_NAME; break; case IPP_TAG_CHARSET : max_bytes = IPP_MAX_CHARSET; break; case IPP_TAG_KEYWORD : max_bytes = IPP_MAX_KEYWORD; break; case IPP_TAG_LANGUAGE : max_bytes = IPP_MAX_LANGUAGE; break; case IPP_TAG_MIMETYPE : max_bytes = IPP_MAX_MIMETYPE; break; case IPP_TAG_URI : max_bytes = IPP_MAX_URI; break; case IPP_TAG_URISCHEME : max_bytes = IPP_MAX_URISCHEME; break; } if (bytes >= max_bytes) { char *bufmax, /* Buffer at max_bytes */ *bufptr; /* Pointer into buffer */ bufptr = buffer + strlen(buffer) - 1; bufmax = buffer + max_bytes - 1; while (bufptr > bufmax) { if (*bufptr & 0x80) { while ((*bufptr & 0xc0) == 0x80 && bufptr > buffer) bufptr --; } bufptr --; } *bufptr = '\0'; } /* * Set the formatted string and return... */ return (ippSetString(ipp, attr, element, buffer)); } /* * 'ippSetValueTag()' - Set the value tag of an attribute. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The @code attr@ parameter may be modified as a result of setting the value. * * Integer (@code IPP_TAG_INTEGER@) values can be promoted to rangeOfInteger * (@code IPP_TAG_RANGE@) values, the various string tags can be promoted to name * (@code IPP_TAG_NAME@) or nameWithLanguage (@code IPP_TAG_NAMELANG@) values, text * (@code IPP_TAG_TEXT@) values can be promoted to textWithLanguage * (@code IPP_TAG_TEXTLANG@) values, and all values can be demoted to the various * out-of-band value tags such as no-value (@code IPP_TAG_NOVALUE@). All other changes * will be rejected. * * Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language * code in the "attributes-natural-language" attribute or, if not present, the language * code for the current locale. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippSetValueTag( ipp_t *ipp, /* I - IPP message */ ipp_attribute_t **attr, /* IO - IPP attribute */ ipp_tag_t value_tag) /* I - Value tag */ { int i; /* Looping var */ _ipp_value_t *value; /* Current value */ int integer; /* Current integer value */ cups_lang_t *language; /* Current language */ char code[32]; /* Language code */ ipp_tag_t temp_tag; /* Temporary value tag */ /* * Range check input... */ if (!ipp || !attr || !*attr) return (0); /* * If there is no change, return immediately... */ if (value_tag == (*attr)->value_tag) return (1); /* * Otherwise implement changes as needed... */ temp_tag = (ipp_tag_t)((int)((*attr)->value_tag) & IPP_TAG_CUPS_MASK); switch (value_tag) { case IPP_TAG_UNSUPPORTED_VALUE : case IPP_TAG_DEFAULT : case IPP_TAG_UNKNOWN : case IPP_TAG_NOVALUE : case IPP_TAG_NOTSETTABLE : case IPP_TAG_DELETEATTR : case IPP_TAG_ADMINDEFINE : /* * Free any existing values... */ if ((*attr)->num_values > 0) ipp_free_values(*attr, 0, (*attr)->num_values); /* * Set out-of-band value... */ (*attr)->value_tag = value_tag; break; case IPP_TAG_RANGE : if (temp_tag != IPP_TAG_INTEGER) return (0); for (i = (*attr)->num_values, value = (*attr)->values; i > 0; i --, value ++) { integer = value->integer; value->range.lower = value->range.upper = integer; } (*attr)->value_tag = IPP_TAG_RANGE; break; case IPP_TAG_NAME : if (temp_tag != IPP_TAG_KEYWORD && temp_tag != IPP_TAG_URI && temp_tag != IPP_TAG_URISCHEME && temp_tag != IPP_TAG_LANGUAGE && temp_tag != IPP_TAG_MIMETYPE) return (0); (*attr)->value_tag = (ipp_tag_t)(IPP_TAG_NAME | ((*attr)->value_tag & IPP_TAG_CUPS_CONST)); break; case IPP_TAG_NAMELANG : case IPP_TAG_TEXTLANG : if (value_tag == IPP_TAG_NAMELANG && (temp_tag != IPP_TAG_NAME && temp_tag != IPP_TAG_KEYWORD && temp_tag != IPP_TAG_URI && temp_tag != IPP_TAG_URISCHEME && temp_tag != IPP_TAG_LANGUAGE && temp_tag != IPP_TAG_MIMETYPE)) return (0); if (value_tag == IPP_TAG_TEXTLANG && temp_tag != IPP_TAG_TEXT) return (0); if (ipp->attrs && ipp->attrs->next && ipp->attrs->next->name && !strcmp(ipp->attrs->next->name, "attributes-natural-language")) { /* * Use the language code from the IPP message... */ (*attr)->values[0].string.language = _cupsStrAlloc(ipp->attrs->next->values[0].string.text); } else { /* * Otherwise, use the language code corresponding to the locale... */ language = cupsLangDefault(); (*attr)->values[0].string.language = _cupsStrAlloc(ipp_lang_code(language->language, code, sizeof(code))); } for (i = (*attr)->num_values - 1, value = (*attr)->values + 1; i > 0; i --, value ++) value->string.language = (*attr)->values[0].string.language; if ((int)(*attr)->value_tag & IPP_TAG_CUPS_CONST) { /* * Make copies of all values... */ for (i = (*attr)->num_values, value = (*attr)->values; i > 0; i --, value ++) value->string.text = _cupsStrAlloc(value->string.text); } (*attr)->value_tag = IPP_TAG_NAMELANG; break; case IPP_TAG_KEYWORD : if (temp_tag == IPP_TAG_NAME || temp_tag == IPP_TAG_NAMELANG) break; /* Silently "allow" name -> keyword */ default : return (0); } return (1); } /* * 'ippSetVersion()' - Set the version number in an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. * * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2. * * @since CUPS 1.6/macOS 10.8@ */ int /* O - 1 on success, 0 on failure */ ippSetVersion(ipp_t *ipp, /* I - IPP message */ int major, /* I - Major version number (major.minor) */ int minor) /* I - Minor version number (major.minor) */ { /* * Range check input... */ if (!ipp || major < 0 || minor < 0) return (0); /* * Set the version number... */ ipp->request.any.version[0] = (ipp_uchar_t)major; ipp->request.any.version[1] = (ipp_uchar_t)minor; return (1); } /* * 'ippTimeToDate()' - Convert from time in seconds to RFC 2579 format. */ const ipp_uchar_t * /* O - RFC-2579 date/time data */ ippTimeToDate(time_t t) /* I - Time in seconds */ { struct tm *unixdate; /* UNIX unixdate/time info */ ipp_uchar_t *date = _cupsGlobals()->ipp_date; /* RFC-2579 date/time data */ /* * RFC-2579 date/time format is: * * Byte(s) Description * ------- ----------- * 0-1 Year (0 to 65535) * 2 Month (1 to 12) * 3 Day (1 to 31) * 4 Hours (0 to 23) * 5 Minutes (0 to 59) * 6 Seconds (0 to 60, 60 = "leap second") * 7 Deciseconds (0 to 9) * 8 +/- UTC * 9 UTC hours (0 to 11) * 10 UTC minutes (0 to 59) */ unixdate = gmtime(&t); unixdate->tm_year += 1900; date[0] = (ipp_uchar_t)(unixdate->tm_year >> 8); date[1] = (ipp_uchar_t)(unixdate->tm_year); date[2] = (ipp_uchar_t)(unixdate->tm_mon + 1); date[3] = (ipp_uchar_t)unixdate->tm_mday; date[4] = (ipp_uchar_t)unixdate->tm_hour; date[5] = (ipp_uchar_t)unixdate->tm_min; date[6] = (ipp_uchar_t)unixdate->tm_sec; date[7] = 0; date[8] = '+'; date[9] = 0; date[10] = 0; return (date); } /* * 'ippValidateAttribute()' - Validate the contents of an attribute. * * This function validates the contents of an attribute based on the name and * value tag. 1 is returned if the attribute is valid, 0 otherwise. On * failure, @link cupsLastErrorString@ is set to a human-readable message. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - 1 if valid, 0 otherwise */ ippValidateAttribute( ipp_attribute_t *attr) /* I - Attribute */ { int i; /* Looping var */ char scheme[64], /* Scheme from URI */ userpass[256], /* Username/password from URI */ hostname[256], /* Hostname from URI */ resource[1024]; /* Resource from URI */ int port, /* Port number from URI */ uri_status; /* URI separation status */ const char *ptr; /* Pointer into string */ ipp_attribute_t *colattr; /* Collection attribute */ regex_t re; /* Regular expression */ ipp_uchar_t *date; /* Current date value */ /* * Skip separators. */ if (!attr->name) return (1); /* * Validate the attribute name. */ for (ptr = attr->name; *ptr; ptr ++) if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' && *ptr != '_') break; if (*ptr || ptr == attr->name) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad attribute name - invalid character (RFC 8011 section 5.1.4)."), attr->name); return (0); } if ((ptr - attr->name) > 255) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad attribute name - bad length %d (RFC 8011 section 5.1.4)."), attr->name, (int)(ptr - attr->name)); return (0); } switch (attr->value_tag) { case IPP_TAG_INTEGER : break; case IPP_TAG_BOOLEAN : for (i = 0; i < attr->num_values; i ++) { if (attr->values[i].boolean != 0 && attr->values[i].boolean != 1) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad boolean value %d (RFC 8011 section 5.1.21)."), attr->name, attr->values[i].boolean); return (0); } } break; case IPP_TAG_ENUM : for (i = 0; i < attr->num_values; i ++) { if (attr->values[i].integer < 1) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad enum value %d - out of range (RFC 8011 section 5.1.5)."), attr->name, attr->values[i].integer); return (0); } } break; case IPP_TAG_STRING : for (i = 0; i < attr->num_values; i ++) { if (attr->values[i].unknown.length > IPP_MAX_OCTETSTRING) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad octetString value - bad length %d (RFC 8011 section 5.1.20)."), attr->name, attr->values[i].unknown.length); return (0); } } break; case IPP_TAG_DATE : for (i = 0; i < attr->num_values; i ++) { date = attr->values[i].date; if (date[2] < 1 || date[2] > 12) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime month %u (RFC 8011 section 5.1.15)."), attr->name, date[2]); return (0); } if (date[3] < 1 || date[3] > 31) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime day %u (RFC 8011 section 5.1.15)."), attr->name, date[3]); return (0); } if (date[4] > 23) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime hours %u (RFC 8011 section 5.1.15)."), attr->name, date[4]); return (0); } if (date[5] > 59) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime minutes %u (RFC 8011 section 5.1.15)."), attr->name, date[5]); return (0); } if (date[6] > 60) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime seconds %u (RFC 8011 section 5.1.15)."), attr->name, date[6]); return (0); } if (date[7] > 9) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime deciseconds %u (RFC 8011 section 5.1.15)."), attr->name, date[7]); return (0); } if (date[8] != '-' && date[8] != '+') { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime UTC sign '%c' (RFC 8011 section 5.1.15)."), attr->name, date[8]); return (0); } if (date[9] > 11) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime UTC hours %u (RFC 8011 section 5.1.15)."), attr->name, date[9]); return (0); } if (date[10] > 59) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime UTC minutes %u (RFC 8011 section 5.1.15)."), attr->name, date[10]); return (0); } } break; case IPP_TAG_RESOLUTION : for (i = 0; i < attr->num_values; i ++) { if (attr->values[i].resolution.xres <= 0) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad resolution value %dx%d%s - cross feed resolution must be positive (RFC 8011 section 5.1.16)."), attr->name, attr->values[i].resolution.xres, attr->values[i].resolution.yres, attr->values[i].resolution.units == IPP_RES_PER_INCH ? "dpi" : attr->values[i].resolution.units == IPP_RES_PER_CM ? "dpcm" : "unknown"); return (0); } if (attr->values[i].resolution.yres <= 0) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad resolution value %dx%d%s - feed resolution must be positive (RFC 8011 section 5.1.16)."), attr->name, attr->values[i].resolution.xres, attr->values[i].resolution.yres, attr->values[i].resolution.units == IPP_RES_PER_INCH ? "dpi" : attr->values[i].resolution.units == IPP_RES_PER_CM ? "dpcm" : "unknown"); return (0); } if (attr->values[i].resolution.units != IPP_RES_PER_INCH && attr->values[i].resolution.units != IPP_RES_PER_CM) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad resolution value %dx%d%s - bad units value (RFC 8011 section 5.1.16)."), attr->name, attr->values[i].resolution.xres, attr->values[i].resolution.yres, attr->values[i].resolution.units == IPP_RES_PER_INCH ? "dpi" : attr->values[i].resolution.units == IPP_RES_PER_CM ? "dpcm" : "unknown"); return (0); } } break; case IPP_TAG_RANGE : for (i = 0; i < attr->num_values; i ++) { if (attr->values[i].range.lower > attr->values[i].range.upper) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad rangeOfInteger value %d-%d - lower greater than upper (RFC 8011 section 5.1.14)."), attr->name, attr->values[i].range.lower, attr->values[i].range.upper); return (0); } } break; case IPP_TAG_BEGIN_COLLECTION : for (i = 0; i < attr->num_values; i ++) { for (colattr = attr->values[i].collection->attrs; colattr; colattr = colattr->next) { if (!ippValidateAttribute(colattr)) return (0); } } break; case IPP_TAG_TEXT : case IPP_TAG_TEXTLANG : for (i = 0; i < attr->num_values; i ++) { for (ptr = attr->values[i].string.text; *ptr; ptr ++) { if ((*ptr & 0xe0) == 0xc0) { ptr ++; if ((*ptr & 0xc0) != 0x80) break; } else if ((*ptr & 0xf0) == 0xe0) { ptr ++; if ((*ptr & 0xc0) != 0x80) break; ptr ++; if ((*ptr & 0xc0) != 0x80) break; } else if ((*ptr & 0xf8) == 0xf0) { ptr ++; if ((*ptr & 0xc0) != 0x80) break; ptr ++; if ((*ptr & 0xc0) != 0x80) break; ptr ++; if ((*ptr & 0xc0) != 0x80) break; } else if (*ptr & 0x80) break; } if (*ptr) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad text value \"%s\" - bad UTF-8 sequence (RFC 8011 section 5.1.2)."), attr->name, attr->values[i].string.text); return (0); } if ((ptr - attr->values[i].string.text) > (IPP_MAX_TEXT - 1)) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad text value \"%s\" - bad length %d (RFC 8011 section 5.1.2)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text)); return (0); } } break; case IPP_TAG_NAME : case IPP_TAG_NAMELANG : for (i = 0; i < attr->num_values; i ++) { for (ptr = attr->values[i].string.text; *ptr; ptr ++) { if ((*ptr & 0xe0) == 0xc0) { ptr ++; if ((*ptr & 0xc0) != 0x80) break; } else if ((*ptr & 0xf0) == 0xe0) { ptr ++; if ((*ptr & 0xc0) != 0x80) break; ptr ++; if ((*ptr & 0xc0) != 0x80) break; } else if ((*ptr & 0xf8) == 0xf0) { ptr ++; if ((*ptr & 0xc0) != 0x80) break; ptr ++; if ((*ptr & 0xc0) != 0x80) break; ptr ++; if ((*ptr & 0xc0) != 0x80) break; } else if (*ptr & 0x80) break; } if (*ptr) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad name value \"%s\" - bad UTF-8 sequence (RFC 8011 section 5.1.3)."), attr->name, attr->values[i].string.text); return (0); } if ((ptr - attr->values[i].string.text) > (IPP_MAX_NAME - 1)) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad name value \"%s\" - bad length %d (RFC 8011 section 5.1.3)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text)); return (0); } } break; case IPP_TAG_KEYWORD : for (i = 0; i < attr->num_values; i ++) { for (ptr = attr->values[i].string.text; *ptr; ptr ++) { if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' && *ptr != '_') break; } if (*ptr || ptr == attr->values[i].string.text) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad keyword value \"%s\" - invalid character (RFC 8011 section 5.1.4)."), attr->name, attr->values[i].string.text); return (0); } if ((ptr - attr->values[i].string.text) > (IPP_MAX_KEYWORD - 1)) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad keyword value \"%s\" - bad length %d (RFC 8011 section 5.1.4)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text)); return (0); } } break; case IPP_TAG_URI : for (i = 0; i < attr->num_values; i ++) { uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)); if (uri_status < HTTP_URI_STATUS_OK) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad URI value \"%s\" - %s (RFC 8011 section 5.1.6)."), attr->name, attr->values[i].string.text, httpURIStatusString(uri_status)); return (0); } if (strlen(attr->values[i].string.text) > (IPP_MAX_URI - 1)) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad URI value \"%s\" - bad length %d (RFC 8011 section 5.1.6)."), attr->name, attr->values[i].string.text, (int)strlen(attr->values[i].string.text)); } } break; case IPP_TAG_URISCHEME : for (i = 0; i < attr->num_values; i ++) { ptr = attr->values[i].string.text; if (islower(*ptr & 255)) { for (ptr ++; *ptr; ptr ++) { if (!islower(*ptr & 255) && !isdigit(*ptr & 255) && *ptr != '+' && *ptr != '-' && *ptr != '.') break; } } if (*ptr || ptr == attr->values[i].string.text) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad uriScheme value \"%s\" - bad characters (RFC 8011 section 5.1.7)."), attr->name, attr->values[i].string.text); return (0); } if ((ptr - attr->values[i].string.text) > (IPP_MAX_URISCHEME - 1)) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad uriScheme value \"%s\" - bad length %d (RFC 8011 section 5.1.7)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text)); return (0); } } break; case IPP_TAG_CHARSET : for (i = 0; i < attr->num_values; i ++) { for (ptr = attr->values[i].string.text; *ptr; ptr ++) { if (!isprint(*ptr & 255) || isupper(*ptr & 255) || isspace(*ptr & 255)) break; } if (*ptr || ptr == attr->values[i].string.text) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad charset value \"%s\" - bad characters (RFC 8011 section 5.1.8)."), attr->name, attr->values[i].string.text); return (0); } if ((ptr - attr->values[i].string.text) > (IPP_MAX_CHARSET - 1)) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad charset value \"%s\" - bad length %d (RFC 8011 section 5.1.8)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text)); return (0); } } break; case IPP_TAG_LANGUAGE : /* * The following regular expression is derived from the ABNF for * language tags in RFC 4646. All I can say is that this is the * easiest way to check the values... */ if ((i = regcomp(&re, "^(" "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})" /* language */ "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */ "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */ "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */ "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */ "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */ "|" "x(-[a-z0-9]{1,8})+" /* privateuse */ "|" "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */ ")$", REG_NOSUB | REG_EXTENDED)) != 0) { char temp[256]; /* Temporary error string */ regerror(i, &re, temp, sizeof(temp)); ipp_set_error(IPP_STATUS_ERROR_INTERNAL, _("Unable to compile naturalLanguage regular expression: %s."), temp); return (0); } for (i = 0; i < attr->num_values; i ++) { if (regexec(&re, attr->values[i].string.text, 0, NULL, 0)) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad naturalLanguage value \"%s\" - bad characters (RFC 8011 section 5.1.9)."), attr->name, attr->values[i].string.text); regfree(&re); return (0); } if (strlen(attr->values[i].string.text) > (IPP_MAX_LANGUAGE - 1)) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad naturalLanguage value \"%s\" - bad length %d (RFC 8011 section 5.1.9)."), attr->name, attr->values[i].string.text, (int)strlen(attr->values[i].string.text)); regfree(&re); return (0); } } regfree(&re); break; case IPP_TAG_MIMETYPE : /* * The following regular expression is derived from the ABNF for * MIME media types in RFC 2045 and 4288. All I can say is that this is * the easiest way to check the values... */ if ((i = regcomp(&re, "^" "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */ "/" "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */ "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */ "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*" /* value */ "$", REG_NOSUB | REG_EXTENDED)) != 0) { char temp[256]; /* Temporary error string */ regerror(i, &re, temp, sizeof(temp)); ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("Unable to compile mimeMediaType regular expression: %s."), temp); return (0); } for (i = 0; i < attr->num_values; i ++) { if (regexec(&re, attr->values[i].string.text, 0, NULL, 0)) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad mimeMediaType value \"%s\" - bad characters (RFC 8011 section 5.1.10)."), attr->name, attr->values[i].string.text); regfree(&re); return (0); } if (strlen(attr->values[i].string.text) > (IPP_MAX_MIMETYPE - 1)) { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad mimeMediaType value \"%s\" - bad length %d (RFC 8011 section 5.1.10)."), attr->name, attr->values[i].string.text, (int)strlen(attr->values[i].string.text)); regfree(&re); return (0); } } regfree(&re); break; default : break; } return (1); } /* * 'ippValidateAttributes()' - Validate all attributes in an IPP message. * * This function validates the contents of the IPP message, including each * attribute. Like @link ippValidateAttribute@, @link cupsLastErrorString@ is * set to a human-readable message on failure. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - 1 if valid, 0 otherwise */ ippValidateAttributes(ipp_t *ipp) /* I - IPP message */ { ipp_attribute_t *attr; /* Current attribute */ if (!ipp) return (1); for (attr = ipp->attrs; attr; attr = attr->next) if (!ippValidateAttribute(attr)) return (0); return (1); } /* * 'ippWrite()' - Write data for an IPP message to a HTTP connection. */ ipp_state_t /* O - Current state */ ippWrite(http_t *http, /* I - HTTP connection */ ipp_t *ipp) /* I - IPP data */ { DEBUG_printf(("ippWrite(http=%p, ipp=%p)", (void *)http, (void *)ipp)); if (!http) return (IPP_STATE_ERROR); return (ippWriteIO(http, (ipp_iocb_t)httpWrite2, http->blocking, NULL, ipp)); } /* * 'ippWriteFile()' - Write data for an IPP message to a file. * * @since CUPS 1.1.19/macOS 10.3@ */ ipp_state_t /* O - Current state */ ippWriteFile(int fd, /* I - HTTP data */ ipp_t *ipp) /* I - IPP data */ { DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd, (void *)ipp)); ipp->state = IPP_STATE_IDLE; return (ippWriteIO(&fd, (ipp_iocb_t)ipp_write_file, 1, NULL, ipp)); } /* * 'ippWriteIO()' - Write data for an IPP message. * * @since CUPS 1.2/macOS 10.5@ */ ipp_state_t /* O - Current state */ ippWriteIO(void *dst, /* I - Destination */ ipp_iocb_t cb, /* I - Write callback function */ int blocking, /* I - Use blocking IO? */ ipp_t *parent, /* I - Parent IPP message */ ipp_t *ipp) /* I - IPP data */ { int i; /* Looping var */ int n; /* Length of data */ unsigned char *buffer, /* Data buffer */ *bufptr; /* Pointer into buffer */ ipp_attribute_t *attr; /* Current attribute */ _ipp_value_t *value; /* Current value */ DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)dst, (void *)cb, blocking, (void *)parent, (void *)ipp)); if (!dst || !ipp) return (IPP_STATE_ERROR); if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL) { DEBUG_puts("1ippWriteIO: Unable to get write buffer"); return (IPP_STATE_ERROR); } switch (ipp->state) { case IPP_STATE_IDLE : ipp->state ++; /* Avoid common problem... */ case IPP_STATE_HEADER : if (parent == NULL) { /* * Send the request header: * * Version = 2 bytes * Operation/Status Code = 2 bytes * Request ID = 4 bytes * Total = 8 bytes */ bufptr = buffer; *bufptr++ = ipp->request.any.version[0]; *bufptr++ = ipp->request.any.version[1]; *bufptr++ = (ipp_uchar_t)(ipp->request.any.op_status >> 8); *bufptr++ = (ipp_uchar_t)ipp->request.any.op_status; *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 24); *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 16); *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 8); *bufptr++ = (ipp_uchar_t)ipp->request.any.request_id; DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer[0], buffer[1])); DEBUG_printf(("2ippWriteIO: op_status=%04x", ipp->request.any.op_status)); DEBUG_printf(("2ippWriteIO: request_id=%d", ipp->request.any.request_id)); if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP header..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } } /* * Reset the state engine to point to the first attribute * in the request/response, with no current group. */ ipp->state = IPP_STATE_ATTRIBUTE; ipp->current = ipp->attrs; ipp->curtag = IPP_TAG_ZERO; DEBUG_printf(("1ippWriteIO: ipp->current=%p", (void *)ipp->current)); /* * If blocking is disabled, stop here... */ if (!blocking) break; case IPP_STATE_ATTRIBUTE : while (ipp->current != NULL) { /* * Write this attribute... */ bufptr = buffer; attr = ipp->current; ipp->current = ipp->current->next; if (!parent) { if (ipp->curtag != attr->group_tag) { /* * Send a group tag byte... */ ipp->curtag = attr->group_tag; if (attr->group_tag == IPP_TAG_ZERO) continue; DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)", attr->group_tag, ippTagString(attr->group_tag))); *bufptr++ = (ipp_uchar_t)attr->group_tag; } else if (attr->group_tag == IPP_TAG_ZERO) continue; } DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr->name, attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag))); /* * Write the attribute tag and name. * * The attribute name length does not include the trailing nul * character in the source string. * * Collection values (parent != NULL) are written differently... */ if (parent == NULL) { /* * Get the length of the attribute name, and make sure it won't * overflow the buffer... */ if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 8)) { DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } /* * Write the value tag, name length, and name string... */ DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)", attr->value_tag, ippTagString(attr->value_tag))); DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n, attr->name)); if (attr->value_tag > 0xff) { *bufptr++ = IPP_TAG_EXTENSION; *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24); *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16); *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8); *bufptr++ = (ipp_uchar_t)attr->value_tag; } else *bufptr++ = (ipp_uchar_t)attr->value_tag; *bufptr++ = (ipp_uchar_t)(n >> 8); *bufptr++ = (ipp_uchar_t)n; memcpy(bufptr, attr->name, (size_t)n); bufptr += n; } else { /* * Get the length of the attribute name, and make sure it won't * overflow the buffer... */ if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 12)) { DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } /* * Write the member name tag, name length, name string, value tag, * and empty name for the collection member attribute... */ DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)", IPP_TAG_MEMBERNAME)); DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n, attr->name)); DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)", attr->value_tag, ippTagString(attr->value_tag))); DEBUG_puts("2ippWriteIO: writing name=0,\"\""); *bufptr++ = IPP_TAG_MEMBERNAME; *bufptr++ = 0; *bufptr++ = 0; *bufptr++ = (ipp_uchar_t)(n >> 8); *bufptr++ = (ipp_uchar_t)n; memcpy(bufptr, attr->name, (size_t)n); bufptr += n; if (attr->value_tag > 0xff) { *bufptr++ = IPP_TAG_EXTENSION; *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24); *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16); *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8); *bufptr++ = (ipp_uchar_t)attr->value_tag; } else *bufptr++ = (ipp_uchar_t)attr->value_tag; *bufptr++ = 0; *bufptr++ = 0; } /* * Now write the attribute value(s)... */ switch (attr->value_tag & ~IPP_TAG_CUPS_CONST) { case IPP_TAG_UNSUPPORTED_VALUE : case IPP_TAG_DEFAULT : case IPP_TAG_UNKNOWN : case IPP_TAG_NOVALUE : case IPP_TAG_NOTSETTABLE : case IPP_TAG_DELETEATTR : case IPP_TAG_ADMINDEFINE : *bufptr++ = 0; *bufptr++ = 0; break; case IPP_TAG_INTEGER : case IPP_TAG_ENUM : for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++) { if ((IPP_BUF_SIZE - (bufptr - buffer)) < 9) { if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP " "attribute..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } bufptr = buffer; } if (i) { /* * Arrays and sets are done by sending additional * values with a zero-length name... */ *bufptr++ = (ipp_uchar_t)attr->value_tag; *bufptr++ = 0; *bufptr++ = 0; } /* * Integers and enumerations are both 4-byte signed * (twos-complement) values. * * Put the 2-byte length and 4-byte value into the buffer... */ *bufptr++ = 0; *bufptr++ = 4; *bufptr++ = (ipp_uchar_t)(value->integer >> 24); *bufptr++ = (ipp_uchar_t)(value->integer >> 16); *bufptr++ = (ipp_uchar_t)(value->integer >> 8); *bufptr++ = (ipp_uchar_t)value->integer; } break; case IPP_TAG_BOOLEAN : for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++) { if ((IPP_BUF_SIZE - (bufptr - buffer)) < 6) { if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP " "attribute..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } bufptr = buffer; } if (i) { /* * Arrays and sets are done by sending additional * values with a zero-length name... */ *bufptr++ = (ipp_uchar_t)attr->value_tag; *bufptr++ = 0; *bufptr++ = 0; } /* * Boolean values are 1-byte; 0 = false, 1 = true. * * Put the 2-byte length and 1-byte value into the buffer... */ *bufptr++ = 0; *bufptr++ = 1; *bufptr++ = (ipp_uchar_t)value->boolean; } break; case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++) { if (i) { /* * Arrays and sets are done by sending additional * values with a zero-length name... */ DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)", attr->value_tag, ippTagString(attr->value_tag))); DEBUG_printf(("2ippWriteIO: writing name=0,\"\"")); if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3) { if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP " "attribute..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } bufptr = buffer; } *bufptr++ = (ipp_uchar_t)attr->value_tag; *bufptr++ = 0; *bufptr++ = 0; } if (value->string.text != NULL) n = (int)strlen(value->string.text); else n = 0; if (n > (IPP_BUF_SIZE - 2)) { DEBUG_printf(("1ippWriteIO: String too long (%d)", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n, value->string.text)); if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2)) { if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP " "attribute..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } bufptr = buffer; } /* * All simple strings consist of the 2-byte length and * character data without the trailing nul normally found * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH * bytes since the 2-byte length is a signed (twos-complement) * value. * * Put the 2-byte length and string characters in the buffer. */ *bufptr++ = (ipp_uchar_t)(n >> 8); *bufptr++ = (ipp_uchar_t)n; if (n > 0) { memcpy(bufptr, value->string.text, (size_t)n); bufptr += n; } } break; case IPP_TAG_DATE : for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++) { if ((IPP_BUF_SIZE - (bufptr - buffer)) < 16) { if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP " "attribute..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } bufptr = buffer; } if (i) { /* * Arrays and sets are done by sending additional * values with a zero-length name... */ *bufptr++ = (ipp_uchar_t)attr->value_tag; *bufptr++ = 0; *bufptr++ = 0; } /* * Date values consist of a 2-byte length and an * 11-byte date/time structure defined by RFC 1903. * * Put the 2-byte length and 11-byte date/time * structure in the buffer. */ *bufptr++ = 0; *bufptr++ = 11; memcpy(bufptr, value->date, 11); bufptr += 11; } break; case IPP_TAG_RESOLUTION : for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++) { if ((IPP_BUF_SIZE - (bufptr - buffer)) < 14) { if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP " "attribute..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } bufptr = buffer; } if (i) { /* * Arrays and sets are done by sending additional * values with a zero-length name... */ *bufptr++ = (ipp_uchar_t)attr->value_tag; *bufptr++ = 0; *bufptr++ = 0; } /* * Resolution values consist of a 2-byte length, * 4-byte horizontal resolution value, 4-byte vertical * resolution value, and a 1-byte units value. * * Put the 2-byte length and resolution value data * into the buffer. */ *bufptr++ = 0; *bufptr++ = 9; *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 24); *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 16); *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 8); *bufptr++ = (ipp_uchar_t)value->resolution.xres; *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 24); *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 16); *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 8); *bufptr++ = (ipp_uchar_t)value->resolution.yres; *bufptr++ = (ipp_uchar_t)value->resolution.units; } break; case IPP_TAG_RANGE : for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++) { if ((IPP_BUF_SIZE - (bufptr - buffer)) < 13) { if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP " "attribute..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } bufptr = buffer; } if (i) { /* * Arrays and sets are done by sending additional * values with a zero-length name... */ *bufptr++ = (ipp_uchar_t)attr->value_tag; *bufptr++ = 0; *bufptr++ = 0; } /* * Range values consist of a 2-byte length, * 4-byte lower value, and 4-byte upper value. * * Put the 2-byte length and range value data * into the buffer. */ *bufptr++ = 0; *bufptr++ = 8; *bufptr++ = (ipp_uchar_t)(value->range.lower >> 24); *bufptr++ = (ipp_uchar_t)(value->range.lower >> 16); *bufptr++ = (ipp_uchar_t)(value->range.lower >> 8); *bufptr++ = (ipp_uchar_t)value->range.lower; *bufptr++ = (ipp_uchar_t)(value->range.upper >> 24); *bufptr++ = (ipp_uchar_t)(value->range.upper >> 16); *bufptr++ = (ipp_uchar_t)(value->range.upper >> 8); *bufptr++ = (ipp_uchar_t)value->range.upper; } break; case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++) { if (i) { /* * Arrays and sets are done by sending additional * values with a zero-length name... */ if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3) { if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP " "attribute..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } bufptr = buffer; } *bufptr++ = (ipp_uchar_t)attr->value_tag; *bufptr++ = 0; *bufptr++ = 0; } /* * textWithLanguage and nameWithLanguage values consist * of a 2-byte length for both strings and their * individual lengths, a 2-byte length for the * character string, the character string without the * trailing nul, a 2-byte length for the character * set string, and the character set string without * the trailing nul. */ n = 4; if (value->string.language != NULL) n += (int)strlen(value->string.language); if (value->string.text != NULL) n += (int)strlen(value->string.text); if (n > (IPP_BUF_SIZE - 2)) { DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value " "too long (%d)", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2)) { if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP " "attribute..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } bufptr = buffer; } /* Length of entire value */ *bufptr++ = (ipp_uchar_t)(n >> 8); *bufptr++ = (ipp_uchar_t)n; /* Length of language */ if (value->string.language != NULL) n = (int)strlen(value->string.language); else n = 0; *bufptr++ = (ipp_uchar_t)(n >> 8); *bufptr++ = (ipp_uchar_t)n; /* Language */ if (n > 0) { memcpy(bufptr, value->string.language, (size_t)n); bufptr += n; } /* Length of text */ if (value->string.text != NULL) n = (int)strlen(value->string.text); else n = 0; *bufptr++ = (ipp_uchar_t)(n >> 8); *bufptr++ = (ipp_uchar_t)n; /* Text */ if (n > 0) { memcpy(bufptr, value->string.text, (size_t)n); bufptr += n; } } break; case IPP_TAG_BEGIN_COLLECTION : for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++) { /* * Collections are written with the begin-collection * tag first with a value of 0 length, followed by the * attributes in the collection, then the end-collection * value... */ if ((IPP_BUF_SIZE - (bufptr - buffer)) < 5) { if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP " "attribute..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } bufptr = buffer; } if (i) { /* * Arrays and sets are done by sending additional * values with a zero-length name... */ *bufptr++ = (ipp_uchar_t)attr->value_tag; *bufptr++ = 0; *bufptr++ = 0; } /* * Write a data length of 0 and flush the buffer... */ *bufptr++ = 0; *bufptr++ = 0; if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP " "attribute..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } bufptr = buffer; /* * Then write the collection attribute... */ value->collection->state = IPP_STATE_IDLE; if (ippWriteIO(dst, cb, 1, ipp, value->collection) == IPP_STATE_ERROR) { DEBUG_puts("1ippWriteIO: Unable to write collection value"); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } } break; default : for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++) { if (i) { /* * Arrays and sets are done by sending additional * values with a zero-length name... */ if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3) { if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP " "attribute..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } bufptr = buffer; } *bufptr++ = (ipp_uchar_t)attr->value_tag; *bufptr++ = 0; *bufptr++ = 0; } /* * An unknown value might some new value that a * vendor has come up with. It consists of a * 2-byte length and the bytes in the unknown * value buffer. */ n = value->unknown.length; if (n > (IPP_BUF_SIZE - 2)) { DEBUG_printf(("1ippWriteIO: Data length too long (%d)", n)); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2)) { if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP " "attribute..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } bufptr = buffer; } /* Length of unknown value */ *bufptr++ = (ipp_uchar_t)(n >> 8); *bufptr++ = (ipp_uchar_t)n; /* Value */ if (n > 0) { memcpy(bufptr, value->unknown.data, (size_t)n); bufptr += n; } } break; } /* * Write the data out... */ if (bufptr > buffer) { if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP attribute..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } DEBUG_printf(("2ippWriteIO: wrote %d bytes", (int)(bufptr - buffer))); } /* * If blocking is disabled and we aren't at the end of the attribute * list, stop here... */ if (!blocking && ipp->current) break; } if (ipp->current == NULL) { /* * Done with all of the attributes; add the end-of-attributes * tag or end-collection attribute... */ if (parent == NULL) { buffer[0] = IPP_TAG_END; n = 1; } else { buffer[0] = IPP_TAG_END_COLLECTION; buffer[1] = 0; /* empty name */ buffer[2] = 0; buffer[3] = 0; /* empty value */ buffer[4] = 0; n = 5; } if ((*cb)(dst, buffer, (size_t)n) < 0) { DEBUG_puts("1ippWriteIO: Could not write IPP end-tag..."); _cupsBufferRelease((char *)buffer); return (IPP_STATE_ERROR); } ipp->state = IPP_STATE_DATA; } break; case IPP_STATE_DATA : break; default : break; /* anti-compiler-warning-code */ } _cupsBufferRelease((char *)buffer); return (ipp->state); } /* * 'ipp_add_attr()' - Add a new attribute to the message. */ static ipp_attribute_t * /* O - New attribute */ ipp_add_attr(ipp_t *ipp, /* I - IPP message */ const char *name, /* I - Attribute name or NULL */ ipp_tag_t group_tag, /* I - Group tag or IPP_TAG_ZERO */ ipp_tag_t value_tag, /* I - Value tag or IPP_TAG_ZERO */ int num_values) /* I - Number of values */ { int alloc_values; /* Number of values to allocate */ ipp_attribute_t *attr; /* New attribute */ DEBUG_printf(("4ipp_add_attr(ipp=%p, name=\"%s\", group_tag=0x%x, value_tag=0x%x, num_values=%d)", (void *)ipp, name, group_tag, value_tag, num_values)); /* * Range check input... */ if (!ipp || num_values < 0) return (NULL); /* * Allocate memory, rounding the allocation up as needed... */ if (num_values <= 1) alloc_values = 1; else alloc_values = (num_values + IPP_MAX_VALUES - 1) & ~(IPP_MAX_VALUES - 1); attr = calloc(sizeof(ipp_attribute_t) + (size_t)(alloc_values - 1) * sizeof(_ipp_value_t), 1); if (attr) { /* * Initialize attribute... */ DEBUG_printf(("4debug_alloc: %p %s %s%s (%d values)", (void *)attr, name, num_values > 1 ? "1setOf " : "", ippTagString(value_tag), num_values)); if (name) attr->name = _cupsStrAlloc(name); attr->group_tag = group_tag; attr->value_tag = value_tag; attr->num_values = num_values; /* * Add it to the end of the linked list... */ if (ipp->last) ipp->last->next = attr; else ipp->attrs = attr; ipp->prev = ipp->last; ipp->last = ipp->current = attr; } DEBUG_printf(("5ipp_add_attr: Returning %p", (void *)attr)); return (attr); } /* * 'ipp_free_values()' - Free attribute values. */ static void ipp_free_values(ipp_attribute_t *attr, /* I - Attribute to free values from */ int element,/* I - First value to free */ int count) /* I - Number of values to free */ { int i; /* Looping var */ _ipp_value_t *value; /* Current value */ DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", (void *)attr, element, count)); if (!(attr->value_tag & IPP_TAG_CUPS_CONST)) { /* * Free values as needed... */ switch (attr->value_tag) { case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : if (element == 0 && count == attr->num_values && attr->values[0].string.language) { _cupsStrFree(attr->values[0].string.language); attr->values[0].string.language = NULL; } /* Fall through to other string values */ case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_RESERVED_STRING : case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : for (i = count, value = attr->values + element; i > 0; i --, value ++) { _cupsStrFree(value->string.text); value->string.text = NULL; } break; case IPP_TAG_DEFAULT : case IPP_TAG_UNKNOWN : case IPP_TAG_NOVALUE : case IPP_TAG_NOTSETTABLE : case IPP_TAG_DELETEATTR : case IPP_TAG_ADMINDEFINE : case IPP_TAG_INTEGER : case IPP_TAG_ENUM : case IPP_TAG_BOOLEAN : case IPP_TAG_DATE : case IPP_TAG_RESOLUTION : case IPP_TAG_RANGE : break; case IPP_TAG_BEGIN_COLLECTION : for (i = count, value = attr->values + element; i > 0; i --, value ++) { ippDelete(value->collection); value->collection = NULL; } break; case IPP_TAG_STRING : default : for (i = count, value = attr->values + element; i > 0; i --, value ++) { if (value->unknown.data) { free(value->unknown.data); value->unknown.data = NULL; } } break; } } /* * If we are not freeing values from the end, move the remaining values up... */ if ((element + count) < attr->num_values) memmove(attr->values + element, attr->values + element + count, (size_t)(attr->num_values - count - element) * sizeof(_ipp_value_t)); attr->num_values -= count; } /* * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code. * * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER" * to "ll-cc", "ll-region", and "charset-number", respectively. */ static char * /* O - Language code string */ ipp_get_code(const char *value, /* I - Locale/charset string */ char *buffer, /* I - String buffer */ size_t bufsize) /* I - Size of string buffer */ { char *bufptr, /* Pointer into buffer */ *bufend; /* End of buffer */ /* * Convert values to lowercase and change _ to - as needed... */ for (bufptr = buffer, bufend = buffer + bufsize - 1; *value && bufptr < bufend; value ++) if (*value == '_') *bufptr++ = '-'; else *bufptr++ = (char)_cups_tolower(*value); *bufptr = '\0'; /* * Return the converted string... */ return (buffer); } /* * 'ipp_lang_code()' - Convert a C locale name into an IPP language code. * * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and * "ll-region", respectively. It also converts the "C" (POSIX) locale to "en". */ static char * /* O - Language code string */ ipp_lang_code(const char *locale, /* I - Locale string */ char *buffer, /* I - String buffer */ size_t bufsize) /* I - Size of string buffer */ { /* * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is. */ if (!_cups_strcasecmp(locale, "c")) { strlcpy(buffer, "en", bufsize); return (buffer); } else return (ipp_get_code(locale, buffer, bufsize)); } /* * 'ipp_length()' - Compute the length of an IPP message or collection value. */ static size_t /* O - Size of IPP message */ ipp_length(ipp_t *ipp, /* I - IPP message or collection */ int collection) /* I - 1 if a collection, 0 otherwise */ { int i; /* Looping var */ size_t bytes; /* Number of bytes */ ipp_attribute_t *attr; /* Current attribute */ ipp_tag_t group; /* Current group */ _ipp_value_t *value; /* Current value */ DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", (void *)ipp, collection)); if (!ipp) { DEBUG_puts("4ipp_length: Returning 0 bytes"); return (0); } /* * Start with 8 bytes for the IPP message header... */ bytes = collection ? 0 : 8; /* * Then add the lengths of each attribute... */ group = IPP_TAG_ZERO; for (attr = ipp->attrs; attr != NULL; attr = attr->next) { if (attr->group_tag != group && !collection) { group = attr->group_tag; if (group == IPP_TAG_ZERO) continue; bytes ++; /* Group tag */ } if (!attr->name) continue; DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, " "bytes=" CUPS_LLFMT, attr->name, attr->num_values, CUPS_LLCAST bytes)); if ((attr->value_tag & ~IPP_TAG_CUPS_CONST) < IPP_TAG_EXTENSION) bytes += (size_t)attr->num_values;/* Value tag for each value */ else bytes += (size_t)(5 * attr->num_values); /* Value tag for each value */ bytes += (size_t)(2 * attr->num_values); /* Name lengths */ bytes += strlen(attr->name); /* Name */ bytes += (size_t)(2 * attr->num_values); /* Value lengths */ if (collection) bytes += 5; /* Add membername overhead */ switch (attr->value_tag & ~IPP_TAG_CUPS_CONST) { case IPP_TAG_UNSUPPORTED_VALUE : case IPP_TAG_DEFAULT : case IPP_TAG_UNKNOWN : case IPP_TAG_NOVALUE : case IPP_TAG_NOTSETTABLE : case IPP_TAG_DELETEATTR : case IPP_TAG_ADMINDEFINE : break; case IPP_TAG_INTEGER : case IPP_TAG_ENUM : bytes += (size_t)(4 * attr->num_values); break; case IPP_TAG_BOOLEAN : bytes += (size_t)attr->num_values; break; case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++) if (value->string.text) bytes += strlen(value->string.text); break; case IPP_TAG_DATE : bytes += (size_t)(11 * attr->num_values); break; case IPP_TAG_RESOLUTION : bytes += (size_t)(9 * attr->num_values); break; case IPP_TAG_RANGE : bytes += (size_t)(8 * attr->num_values); break; case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : bytes += (size_t)(4 * attr->num_values); /* Charset + text length */ for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++) { if (value->string.language) bytes += strlen(value->string.language); if (value->string.text) bytes += strlen(value->string.text); } break; case IPP_TAG_BEGIN_COLLECTION : for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++) bytes += ipp_length(value->collection, 1); break; default : for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++) bytes += (size_t)value->unknown.length; break; } } /* * Finally, add 1 byte for the "end of attributes" tag or 5 bytes * for the "end of collection" tag and return... */ if (collection) bytes += 5; else bytes ++; DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST bytes)); return (bytes); } /* * 'ipp_read_http()' - Semi-blocking read on a HTTP connection... */ static ssize_t /* O - Number of bytes read */ ipp_read_http(http_t *http, /* I - Client connection */ ipp_uchar_t *buffer, /* O - Buffer for data */ size_t length) /* I - Total length */ { ssize_t tbytes, /* Total bytes read */ bytes; /* Bytes read this pass */ DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)", (void *)http, (void *)buffer, (int)length)); /* * Loop until all bytes are read... */ for (tbytes = 0, bytes = 0; tbytes < (int)length; tbytes += bytes, buffer += bytes) { DEBUG_printf(("9ipp_read_http: tbytes=" CUPS_LLFMT ", http->state=%d", CUPS_LLCAST tbytes, http->state)); if (http->state == HTTP_STATE_WAITING) break; if (http->used == 0 && !http->blocking) { /* * Wait up to 10 seconds for more data on non-blocking sockets... */ if (!httpWait(http, 10000)) { /* * Signal no data... */ bytes = -1; break; } } else if (http->used == 0 && http->timeout_value > 0) { /* * Wait up to timeout seconds for more data on blocking sockets... */ if (!httpWait(http, (int)(1000 * http->timeout_value))) { /* * Signal no data... */ bytes = -1; break; } } if ((bytes = httpRead2(http, (char *)buffer, length - (size_t)tbytes)) < 0) { #ifdef WIN32 break; #else if (errno != EAGAIN && errno != EINTR) break; bytes = 0; #endif /* WIN32 */ } else if (bytes == 0) break; } /* * Return the number of bytes read... */ if (tbytes == 0 && bytes < 0) tbytes = -1; DEBUG_printf(("8ipp_read_http: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST tbytes)); return (tbytes); } /* * 'ipp_read_file()' - Read IPP data from a file. */ static ssize_t /* O - Number of bytes read */ ipp_read_file(int *fd, /* I - File descriptor */ ipp_uchar_t *buffer, /* O - Read buffer */ size_t length) /* I - Number of bytes to read */ { #ifdef WIN32 return ((ssize_t)read(*fd, buffer, (unsigned)length)); #else return (read(*fd, buffer, length)); #endif /* WIN32 */ } /* * 'ipp_set_error()' - Set a formatted, localized error string. */ static void ipp_set_error(ipp_status_t status, /* I - Status code */ const char *format, /* I - Printf-style error string */ ...) /* I - Additional arguments as needed */ { va_list ap; /* Pointer to additional args */ char buffer[2048]; /* Message buffer */ cups_lang_t *lang = cupsLangDefault(); /* Current language */ va_start(ap, format); vsnprintf(buffer, sizeof(buffer), _cupsLangString(lang, format), ap); va_end(ap); _cupsSetError(status, buffer, 0); } /* * 'ipp_set_value()' - Get the value element from an attribute, expanding it as * needed. */ static _ipp_value_t * /* O - IPP value element or NULL on error */ ipp_set_value(ipp_t *ipp, /* IO - IPP message */ ipp_attribute_t **attr, /* IO - IPP attribute */ int element) /* I - Value number (0-based) */ { ipp_attribute_t *temp, /* New attribute pointer */ *current, /* Current attribute in list */ *prev; /* Previous attribute in list */ int alloc_values; /* Allocated values */ /* * If we are setting an existing value element, return it... */ temp = *attr; if (temp->num_values <= 1) alloc_values = 1; else alloc_values = (temp->num_values + IPP_MAX_VALUES - 1) & ~(IPP_MAX_VALUES - 1); if (element < alloc_values) { if (element >= temp->num_values) temp->num_values = element + 1; return (temp->values + element); } /* * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE * values when num_values > 1. */ if (alloc_values < IPP_MAX_VALUES) alloc_values = IPP_MAX_VALUES; else alloc_values += IPP_MAX_VALUES; DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.", alloc_values)); /* * Reallocate memory... */ if ((temp = realloc(temp, sizeof(ipp_attribute_t) + (size_t)(alloc_values - 1) * sizeof(_ipp_value_t))) == NULL) { _cupsSetHTTPError(HTTP_STATUS_ERROR); DEBUG_puts("4ipp_set_value: Unable to resize attribute."); return (NULL); } /* * Zero the new memory... */ memset(temp->values + temp->num_values, 0, (size_t)(alloc_values - temp->num_values) * sizeof(_ipp_value_t)); if (temp != *attr) { /* * Reset pointers in the list... */ DEBUG_printf(("4debug_free: %p %s", (void *)*attr, temp->name)); DEBUG_printf(("4debug_alloc: %p %s %s%s (%d)", (void *)temp, temp->name, temp->num_values > 1 ? "1setOf " : "", ippTagString(temp->value_tag), temp->num_values)); if (ipp->current == *attr && ipp->prev) { /* * Use current "previous" pointer... */ prev = ipp->prev; } else { /* * Find this attribute in the linked list... */ for (prev = NULL, current = ipp->attrs; current && current != *attr; prev = current, current = current->next); if (!current) { /* * This is a serious error! */ *attr = temp; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP attribute is not a member of the message."), 1); DEBUG_puts("4ipp_set_value: Unable to find attribute in message."); return (NULL); } } if (prev) prev->next = temp; else ipp->attrs = temp; ipp->current = temp; ipp->prev = prev; if (ipp->last == *attr) ipp->last = temp; *attr = temp; } /* * Return the value element... */ if (element >= temp->num_values) temp->num_values = element + 1; return (temp->values + element); } /* * 'ipp_write_file()' - Write IPP data to a file. */ static ssize_t /* O - Number of bytes written */ ipp_write_file(int *fd, /* I - File descriptor */ ipp_uchar_t *buffer, /* I - Data to write */ size_t length) /* I - Number of bytes to write */ { #ifdef WIN32 return ((ssize_t)write(*fd, buffer, (unsigned)length)); #else return (write(*fd, buffer, length)); #endif /* WIN32 */ } ippsample/cups/tempfile.c0000644000175000017500000001032213240604116014460 0ustar tilltill/* * Temp file utilities for CUPS. * * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #include #include #include #if defined(WIN32) || defined(__EMX__) # include #else # include #endif /* WIN32 || __EMX__ */ /* * 'cupsTempFd()' - Creates a temporary file. * * The temporary filename is returned in the filename buffer. * The temporary file is opened for reading and writing. */ int /* O - New file descriptor or -1 on error */ cupsTempFd(char *filename, /* I - Pointer to buffer */ int len) /* I - Size of buffer */ { int fd; /* File descriptor for temp file */ int tries; /* Number of tries */ const char *tmpdir; /* TMPDIR environment var */ #ifdef WIN32 char tmppath[1024]; /* Windows temporary directory */ DWORD curtime; /* Current time */ #else struct timeval curtime; /* Current time */ #endif /* WIN32 */ /* * See if TMPDIR is defined... */ #ifdef WIN32 if ((tmpdir = getenv("TEMP")) == NULL) { GetTempPath(sizeof(tmppath), tmppath); tmpdir = tmppath; } #else /* * Previously we put root temporary files in the default CUPS temporary * directory under /var/spool/cups. However, since the scheduler cleans * out temporary files there and runs independently of the user apps, we * don't want to use it unless specifically told to by cupsd. */ if ((tmpdir = getenv("TMPDIR")) == NULL) # if defined(__APPLE__) && !TARGET_OS_IOS tmpdir = "/private/tmp"; /* /tmp is a symlink to /private/tmp */ # else tmpdir = "/tmp"; # endif /* __APPLE__ && !TARGET_OS_IOS */ #endif /* WIN32 */ /* * Make the temporary name using the specified directory... */ tries = 0; do { #ifdef WIN32 /* * Get the current time of day... */ curtime = GetTickCount() + tries; /* * Format a string using the hex time values... */ snprintf(filename, (size_t)len - 1, "%s/%05lx%08lx", tmpdir, GetCurrentProcessId(), curtime); #else /* * Get the current time of day... */ gettimeofday(&curtime, NULL); /* * Format a string using the hex time values... */ snprintf(filename, (size_t)len - 1, "%s/%05x%08x", tmpdir, (unsigned)getpid(), (unsigned)(curtime.tv_sec + curtime.tv_usec + tries)); #endif /* WIN32 */ /* * Open the file in "exclusive" mode, making sure that we don't * stomp on an existing file or someone's symlink crack... */ #ifdef WIN32 fd = open(filename, _O_CREAT | _O_RDWR | _O_TRUNC | _O_BINARY, _S_IREAD | _S_IWRITE); #elif defined(O_NOFOLLOW) fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); #else fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600); #endif /* WIN32 */ if (fd < 0 && errno != EEXIST) break; tries ++; } while (fd < 0 && tries < 1000); /* * Return the file descriptor... */ return (fd); } /* * 'cupsTempFile()' - Generates a temporary filename. * * The temporary filename is returned in the filename buffer. * This function is deprecated and will no longer generate a temporary * filename - use @link cupsTempFd@ or @link cupsTempFile2@ instead. * * @deprecated@ */ char * /* O - Filename or @code NULL@ on error */ cupsTempFile(char *filename, /* I - Pointer to buffer */ int len) /* I - Size of buffer */ { (void)len; if (filename) *filename = '\0'; return (NULL); } /* * 'cupsTempFile2()' - Creates a temporary CUPS file. * * The temporary filename is returned in the filename buffer. * The temporary file is opened for writing. * * @since CUPS 1.2/macOS 10.5@ */ cups_file_t * /* O - CUPS file or @code NULL@ on error */ cupsTempFile2(char *filename, /* I - Pointer to buffer */ int len) /* I - Size of buffer */ { cups_file_t *file; /* CUPS file */ int fd; /* File descriptor */ if ((fd = cupsTempFd(filename, len)) < 0) return (NULL); else if ((file = cupsFileOpenFd(fd, "w")) == NULL) { close(fd); unlink(filename); return (NULL); } else return (file); } ippsample/cups/raster.c0000644000175000017500000017260113240604116014164 0ustar tilltill/* * Raster file routines for CUPS. * * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * This file is part of the CUPS Imaging library. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ /* * Include necessary headers... */ #include #ifdef HAVE_STDINT_H # include #endif /* HAVE_STDINT_H */ /* * Private structures... */ struct _cups_raster_s /**** Raster stream data ****/ { unsigned sync; /* Sync word from start of stream */ void *ctx; /* File descriptor */ cups_raster_iocb_t iocb; /* IO callback */ cups_mode_t mode; /* Read/write mode */ cups_page_header2_t header; /* Raster header for current page */ unsigned rowheight, /* Row height in lines */ count, /* Current row run-length count */ remaining, /* Remaining rows in page image */ bpp; /* Bytes per pixel/color */ unsigned char *pixels, /* Pixels for current row */ *pend, /* End of pixel buffer */ *pcurrent; /* Current byte in pixel buffer */ int compressed, /* Non-zero if data is compressed */ swapped; /* Non-zero if data is byte-swapped */ unsigned char *buffer, /* Read/write buffer */ *bufptr, /* Current (read) position in buffer */ *bufend; /* End of current (read) buffer */ size_t bufsize; /* Buffer size */ #ifdef DEBUG size_t iostart, /* Start of read/write buffer */ iocount; /* Number of bytes read/written */ #endif /* DEBUG */ unsigned apple_page_count;/* Apple raster page count */ }; typedef void (*_cups_copyfunc_t)(void *dst, const void *src, size_t bytes); /* * Local globals... */ #ifdef DEBUG static const char * const cups_color_spaces[] = { /* Color spaces */ "CUPS_CSPACE_W", "CUPS_CSPACE_RGB", "CUPS_CSPACE_RGBA", "CUPS_CSPACE_K", "CUPS_CSPACE_CMY", "CUPS_CSPACE_YMC", "CUPS_CSPACE_CMYK", "CUPS_CSPACE_YMCK", "CUPS_CSPACE_KCMY", "CUPS_CSPACE_KCMYcm", "CUPS_CSPACE_GMCK", "CUPS_CSPACE_GMCS", "CUPS_CSPACE_WHITE", "CUPS_CSPACE_GOLD", "CUPS_CSPACE_SILVER", "CUPS_CSPACE_CIEXYZ", "CUPS_CSPACE_CIELab", "CUPS_CSPACE_RGBW", "CUPS_CSPACE_SW", "CUPS_CSPACE_SRGB", "CUPS_CSPACE_ADOBERGB", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "CUPS_CSPACE_ICC1", "CUPS_CSPACE_ICC2", "CUPS_CSPACE_ICC3", "CUPS_CSPACE_ICC4", "CUPS_CSPACE_ICC5", "CUPS_CSPACE_ICC6", "CUPS_CSPACE_ICC7", "CUPS_CSPACE_ICC8", "CUPS_CSPACE_ICC9", "CUPS_CSPACE_ICCA", "CUPS_CSPACE_ICCB", "CUPS_CSPACE_ICCC", "CUPS_CSPACE_ICCD", "CUPS_CSPACE_ICCE", "CUPS_CSPACE_ICCF", "47", "CUPS_CSPACE_DEVICE1", "CUPS_CSPACE_DEVICE2", "CUPS_CSPACE_DEVICE3", "CUPS_CSPACE_DEVICE4", "CUPS_CSPACE_DEVICE5", "CUPS_CSPACE_DEVICE6", "CUPS_CSPACE_DEVICE7", "CUPS_CSPACE_DEVICE8", "CUPS_CSPACE_DEVICE9", "CUPS_CSPACE_DEVICEA", "CUPS_CSPACE_DEVICEB", "CUPS_CSPACE_DEVICEC", "CUPS_CSPACE_DEVICED", "CUPS_CSPACE_DEVICEE", "CUPS_CSPACE_DEVICEF" }; static const char * const cups_modes[] = { /* Open modes */ "CUPS_RASTER_READ", "CUPS_RASTER_WRITE", "CUPS_RASTER_WRITE_COMPRESSED", "CUPS_RASTER_WRITE_PWG", "CUPS_RASTER_WRITE_APPLE" }; #endif /* DEBUG */ /* * Local functions... */ static ssize_t cups_raster_io(cups_raster_t *r, unsigned char *buf, size_t bytes); static unsigned cups_raster_read_header(cups_raster_t *r); static ssize_t cups_raster_read(cups_raster_t *r, unsigned char *buf, size_t bytes); static int cups_raster_update(cups_raster_t *r); static ssize_t cups_raster_write(cups_raster_t *r, const unsigned char *pixels); static ssize_t cups_read_fd(void *ctx, unsigned char *buf, size_t bytes); static void cups_swap(unsigned char *buf, size_t bytes); static void cups_swap_copy(unsigned char *dst, const unsigned char *src, size_t bytes); static ssize_t cups_write_fd(void *ctx, unsigned char *buf, size_t bytes); /* * 'cupsRasterClose()' - Close a raster stream. * * The file descriptor associated with the raster stream must be closed * separately as needed. */ void cupsRasterClose(cups_raster_t *r) /* I - Stream to close */ { if (r != NULL) { if (r->buffer) free(r->buffer); if (r->pixels) free(r->pixels); free(r); } } /* * 'cupsRasterInitPWGHeader()' - Initialize a page header for PWG Raster output. * * The "media" argument specifies the media to use. * * The "type" argument specifies a "pwg-raster-document-type-supported" value * that controls the color space and bit depth of the raster data. * * The "xres" and "yres" arguments specify the raster resolution in dots per * inch. * * The "sheet_back" argument specifies a "pwg-raster-document-sheet-back" value * to apply for the back side of a page. Pass @code NULL@ for the front side. * * @since CUPS 2.2/macOS 10.12@ */ int /* O - 1 on success, 0 on failure */ cupsRasterInitPWGHeader( cups_page_header2_t *h, /* I - Page header */ pwg_media_t *media, /* I - PWG media information */ const char *type, /* I - PWG raster type string */ int xdpi, /* I - Cross-feed direction (horizontal) resolution */ int ydpi, /* I - Feed direction (vertical) resolution */ const char *sides, /* I - IPP "sides" option value */ const char *sheet_back) /* I - Transform for back side or @code NULL@ for none */ { if (!h || !media || !type || xdpi <= 0 || ydpi <= 0) { _cupsRasterAddError("%s", strerror(EINVAL)); return (0); } /* * Initialize the page header... */ memset(h, 0, sizeof(cups_page_header2_t)); strlcpy(h->cupsPageSizeName, media->pwg, sizeof(h->cupsPageSizeName)); h->PageSize[0] = (unsigned)(72 * media->width / 2540); h->PageSize[1] = (unsigned)(72 * media->length / 2540); /* This never gets written but is needed for some applications */ h->cupsPageSize[0] = 72.0f * media->width / 2540.0f; h->cupsPageSize[1] = 72.0f * media->length / 2540.0f; h->ImagingBoundingBox[2] = h->PageSize[0]; h->ImagingBoundingBox[3] = h->PageSize[1]; h->HWResolution[0] = (unsigned)xdpi; h->HWResolution[1] = (unsigned)ydpi; h->cupsWidth = (unsigned)(media->width * xdpi / 2540); h->cupsHeight = (unsigned)(media->length * ydpi / 2540); if (h->cupsWidth > 0x00ffffff || h->cupsHeight > 0x00ffffff) { _cupsRasterAddError("Raster dimensions too large."); return (0); } h->cupsInteger[CUPS_RASTER_PWG_ImageBoxRight] = h->cupsWidth; h->cupsInteger[CUPS_RASTER_PWG_ImageBoxBottom] = h->cupsHeight; /* * Colorspace and bytes per line... */ if (!strcmp(type, "adobe-rgb_8")) { h->cupsBitsPerColor = 8; h->cupsBitsPerPixel = 24; h->cupsColorSpace = CUPS_CSPACE_ADOBERGB; } else if (!strcmp(type, "adobe-rgb_16")) { h->cupsBitsPerColor = 16; h->cupsBitsPerPixel = 48; h->cupsColorSpace = CUPS_CSPACE_ADOBERGB; } else if (!strcmp(type, "black_1")) { h->cupsBitsPerColor = 1; h->cupsBitsPerPixel = 1; h->cupsColorSpace = CUPS_CSPACE_K; } else if (!strcmp(type, "black_8")) { h->cupsBitsPerColor = 8; h->cupsBitsPerPixel = 8; h->cupsColorSpace = CUPS_CSPACE_K; } else if (!strcmp(type, "black_16")) { h->cupsBitsPerColor = 16; h->cupsBitsPerPixel = 16; h->cupsColorSpace = CUPS_CSPACE_K; } else if (!strcmp(type, "cmyk_8")) { h->cupsBitsPerColor = 8; h->cupsBitsPerPixel = 32; h->cupsColorSpace = CUPS_CSPACE_CMYK; } else if (!strcmp(type, "cmyk_16")) { h->cupsBitsPerColor = 16; h->cupsBitsPerPixel = 64; h->cupsColorSpace = CUPS_CSPACE_CMYK; } else if (!strncmp(type, "device", 6) && type[6] >= '1' && type[6] <= '9') { int ncolors, bits; /* Number of colors and bits */ if (sscanf(type, "device%d_%d", &ncolors, &bits) != 2 || ncolors > 15 || (bits != 8 && bits != 16)) { _cupsRasterAddError("Unsupported raster type \'%s\'.", type); return (0); } h->cupsBitsPerColor = (unsigned)bits; h->cupsBitsPerPixel = (unsigned)(ncolors * bits); h->cupsColorSpace = (cups_cspace_t)(CUPS_CSPACE_DEVICE1 + ncolors - 1); } else if (!strcmp(type, "rgb_8")) { h->cupsBitsPerColor = 8; h->cupsBitsPerPixel = 24; h->cupsColorSpace = CUPS_CSPACE_RGB; } else if (!strcmp(type, "rgb_16")) { h->cupsBitsPerColor = 16; h->cupsBitsPerPixel = 48; h->cupsColorSpace = CUPS_CSPACE_RGB; } else if (!strcmp(type, "sgray_1")) { h->cupsBitsPerColor = 1; h->cupsBitsPerPixel = 1; h->cupsColorSpace = CUPS_CSPACE_SW; } else if (!strcmp(type, "sgray_8")) { h->cupsBitsPerColor = 8; h->cupsBitsPerPixel = 8; h->cupsColorSpace = CUPS_CSPACE_SW; } else if (!strcmp(type, "sgray_16")) { h->cupsBitsPerColor = 16; h->cupsBitsPerPixel = 16; h->cupsColorSpace = CUPS_CSPACE_SW; } else if (!strcmp(type, "srgb_8")) { h->cupsBitsPerColor = 8; h->cupsBitsPerPixel = 24; h->cupsColorSpace = CUPS_CSPACE_SRGB; } else if (!strcmp(type, "srgb_16")) { h->cupsBitsPerColor = 16; h->cupsBitsPerPixel = 48; h->cupsColorSpace = CUPS_CSPACE_SRGB; } else { _cupsRasterAddError("Unsupported raster type \'%s\'.", type); return (0); } h->cupsColorOrder = CUPS_ORDER_CHUNKED; h->cupsNumColors = h->cupsBitsPerPixel / h->cupsBitsPerColor; h->cupsBytesPerLine = (h->cupsWidth * h->cupsBitsPerPixel + 7) / 8; /* * Duplex support... */ h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 1; h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 1; if (sides) { if (!strcmp(sides, "two-sided-long-edge")) { h->Duplex = 1; } else if (!strcmp(sides, "two-sided-short-edge")) { h->Duplex = 1; h->Tumble = 1; } else if (strcmp(sides, "one-sided")) { _cupsRasterAddError("Unsupported sides value \'%s\'.", sides); return (0); } if (sheet_back) { if (!strcmp(sheet_back, "flipped")) { if (h->Tumble) h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 0xffffffffU; else h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 0xffffffffU; } else if (!strcmp(sheet_back, "manual-tumble")) { if (h->Tumble) { h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 0xffffffffU; h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 0xffffffffU; } } else if (!strcmp(sheet_back, "rotated")) { if (!h->Tumble) { h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 0xffffffffU; h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 0xffffffffU; } } else if (strcmp(sheet_back, "normal")) { _cupsRasterAddError("Unsupported sheet_back value \'%s\'.", sheet_back); return (0); } } } return (1); } /* * 'cupsRasterOpen()' - Open a raster stream using a file descriptor. * * This function associates a raster stream with the given file descriptor. * For most printer driver filters, "fd" will be 0 (stdin). For most raster * image processor (RIP) filters that generate raster data, "fd" will be 1 * (stdout). * * When writing raster data, the @code CUPS_RASTER_WRITE@, * @code CUPS_RASTER_WRITE_COMPRESS@, or @code CUPS_RASTER_WRITE_PWG@ mode can * be used - compressed and PWG output is generally 25-50% smaller but adds a * 100-300% execution time overhead. */ cups_raster_t * /* O - New stream */ cupsRasterOpen(int fd, /* I - File descriptor */ cups_mode_t mode) /* I - Mode - @code CUPS_RASTER_READ@, @code CUPS_RASTER_WRITE@, @code CUPS_RASTER_WRITE_COMPRESSED@, or @code CUPS_RASTER_WRITE_PWG@ */ { DEBUG_printf(("cupsRasterOpen(fd=%d, mode=%s)", fd, cups_modes[mode])); if (mode == CUPS_RASTER_READ) return (cupsRasterOpenIO(cups_read_fd, (void *)((intptr_t)fd), mode)); else return (cupsRasterOpenIO(cups_write_fd, (void *)((intptr_t)fd), mode)); } /* * 'cupsRasterOpenIO()' - Open a raster stream using a callback function. * * This function associates a raster stream with the given callback function and * context pointer. * * When writing raster data, the @code CUPS_RASTER_WRITE@, * @code CUPS_RASTER_WRITE_COMPRESS@, or @code CUPS_RASTER_WRITE_PWG@ mode can * be used - compressed and PWG output is generally 25-50% smaller but adds a * 100-300% execution time overhead. */ cups_raster_t * /* O - New stream */ cupsRasterOpenIO( cups_raster_iocb_t iocb, /* I - Read/write callback */ void *ctx, /* I - Context pointer for callback */ cups_mode_t mode) /* I - Mode - @code CUPS_RASTER_READ@, @code CUPS_RASTER_WRITE@, @code CUPS_RASTER_WRITE_COMPRESSED@, or @code CUPS_RASTER_WRITE_PWG@ */ { cups_raster_t *r; /* New stream */ DEBUG_printf(("cupsRasterOpenIO(iocb=%p, ctx=%p, mode=%s)", (void *)iocb, ctx, cups_modes[mode])); _cupsRasterClearError(); if ((r = calloc(sizeof(cups_raster_t), 1)) == NULL) { _cupsRasterAddError("Unable to allocate memory for raster stream: %s\n", strerror(errno)); DEBUG_puts("1cupsRasterOpenIO: Returning NULL."); return (NULL); } r->ctx = ctx; r->iocb = iocb; r->mode = mode; if (mode == CUPS_RASTER_READ) { /* * Open for read - get sync word... */ if (cups_raster_io(r, (unsigned char *)&(r->sync), sizeof(r->sync)) != sizeof(r->sync)) { _cupsRasterAddError("Unable to read header from raster stream: %s\n", strerror(errno)); free(r); DEBUG_puts("1cupsRasterOpenIO: Unable to read header, returning NULL."); return (NULL); } if (r->sync != CUPS_RASTER_SYNC && r->sync != CUPS_RASTER_REVSYNC && r->sync != CUPS_RASTER_SYNCv1 && r->sync != CUPS_RASTER_REVSYNCv1 && r->sync != CUPS_RASTER_SYNCv2 && r->sync != CUPS_RASTER_REVSYNCv2 && r->sync != CUPS_RASTER_SYNCapple && r->sync != CUPS_RASTER_REVSYNCapple) { _cupsRasterAddError("Unknown raster format %08x!\n", r->sync); free(r); DEBUG_puts("1cupsRasterOpenIO: Unknown format, returning NULL."); return (NULL); } if (r->sync == CUPS_RASTER_SYNCv2 || r->sync == CUPS_RASTER_REVSYNCv2 || r->sync == CUPS_RASTER_SYNCapple || r->sync == CUPS_RASTER_REVSYNCapple) r->compressed = 1; DEBUG_printf(("1cupsRasterOpenIO: sync=%08x", r->sync)); if (r->sync == CUPS_RASTER_REVSYNC || r->sync == CUPS_RASTER_REVSYNCv1 || r->sync == CUPS_RASTER_REVSYNCv2 || r->sync == CUPS_RASTER_REVSYNCapple) r->swapped = 1; if (r->sync == CUPS_RASTER_SYNCapple || r->sync == CUPS_RASTER_REVSYNCapple) { unsigned char header[8]; /* File header */ if (cups_raster_io(r, (unsigned char *)header, sizeof(header)) != sizeof(header)) { _cupsRasterAddError("Unable to read header from raster stream: %s\n", strerror(errno)); free(r); DEBUG_puts("1cupsRasterOpenIO: Unable to read header, returning NULL."); return (NULL); } } #ifdef DEBUG r->iostart = r->iocount; #endif /* DEBUG */ } else { /* * Open for write - put sync word... */ switch (mode) { default : case CUPS_RASTER_WRITE : r->sync = CUPS_RASTER_SYNC; break; case CUPS_RASTER_WRITE_COMPRESSED : r->compressed = 1; r->sync = CUPS_RASTER_SYNCv2; break; case CUPS_RASTER_WRITE_PWG : r->compressed = 1; r->sync = htonl(CUPS_RASTER_SYNC_PWG); r->swapped = r->sync != CUPS_RASTER_SYNC_PWG; break; case CUPS_RASTER_WRITE_APPLE : r->compressed = 1; r->sync = htonl(CUPS_RASTER_SYNCapple); r->swapped = r->sync != CUPS_RASTER_SYNCapple; r->apple_page_count = 0xffffffffU; break; } if (cups_raster_io(r, (unsigned char *)&(r->sync), sizeof(r->sync)) < (ssize_t)sizeof(r->sync)) { _cupsRasterAddError("Unable to write raster stream header: %s\n", strerror(errno)); free(r); DEBUG_puts("1cupsRasterOpenIO: Unable to write header, returning NULL."); return (NULL); } } DEBUG_printf(("1cupsRasterOpenIO: compressed=%d, swapped=%d, returning %p", r->compressed, r->swapped, (void *)r)); return (r); } /* * 'cupsRasterReadHeader()' - Read a raster page header and store it in a * version 1 page header structure. * * This function is deprecated. Use @link cupsRasterReadHeader2@ instead. * * Version 1 page headers were used in CUPS 1.0 and 1.1 and contain a subset * of the version 2 page header data. This function handles reading version 2 * page headers and copying only the version 1 data into the provided buffer. * * @deprecated@ */ unsigned /* O - 1 on success, 0 on failure/end-of-file */ cupsRasterReadHeader( cups_raster_t *r, /* I - Raster stream */ cups_page_header_t *h) /* I - Pointer to header data */ { DEBUG_printf(("cupsRasterReadHeader(r=%p, h=%p)", (void *)r, (void *)h)); /* * Get the raster header... */ if (!cups_raster_read_header(r)) { memset(h, 0, sizeof(cups_page_header_t)); DEBUG_puts("1cupsRasterReadHeader: Unable to read page header, returning 0."); return (0); } /* * Copy the header to the user-supplied buffer... */ memcpy(h, &(r->header), sizeof(cups_page_header_t)); DEBUG_printf(("1cupsRasterReadHeader: cupsColorSpace=%s", cups_color_spaces[h->cupsColorSpace])); DEBUG_printf(("1cupsRasterReadHeader: cupsBitsPerColor=%u", h->cupsBitsPerColor)); DEBUG_printf(("1cupsRasterReadHeader: cupsBitsPerPixel=%u", h->cupsBitsPerPixel)); DEBUG_printf(("1cupsRasterReadHeader: cupsBytesPerLine=%u", h->cupsBytesPerLine)); DEBUG_printf(("1cupsRasterReadHeader: cupsWidth=%u", h->cupsWidth)); DEBUG_printf(("1cupsRasterReadHeader: cupsHeight=%u", h->cupsHeight)); DEBUG_puts("1cupsRasterReadHeader: Returning 1."); return (1); } /* * 'cupsRasterReadHeader2()' - Read a raster page header and store it in a * version 2 page header structure. * * @since CUPS 1.2/macOS 10.5@ */ unsigned /* O - 1 on success, 0 on failure/end-of-file */ cupsRasterReadHeader2( cups_raster_t *r, /* I - Raster stream */ cups_page_header2_t *h) /* I - Pointer to header data */ { /* * Get the raster header... */ DEBUG_printf(("cupsRasterReadHeader2(r=%p, h=%p)", (void *)r, (void *)h)); if (!cups_raster_read_header(r)) { memset(h, 0, sizeof(cups_page_header2_t)); DEBUG_puts("1cupsRasterReadHeader2: Unable to read header, returning 0."); return (0); } /* * Copy the header to the user-supplied buffer... */ memcpy(h, &(r->header), sizeof(cups_page_header2_t)); DEBUG_printf(("1cupsRasterReadHeader2: cupsColorSpace=%s", cups_color_spaces[h->cupsColorSpace])); DEBUG_printf(("1cupsRasterReadHeader2: cupsBitsPerColor=%u", h->cupsBitsPerColor)); DEBUG_printf(("1cupsRasterReadHeader2: cupsBitsPerPixel=%u", h->cupsBitsPerPixel)); DEBUG_printf(("1cupsRasterReadHeader2: cupsBytesPerLine=%u", h->cupsBytesPerLine)); DEBUG_printf(("1cupsRasterReadHeader2: cupsWidth=%u", h->cupsWidth)); DEBUG_printf(("1cupsRasterReadHeader2: cupsHeight=%u", h->cupsHeight)); DEBUG_puts("1cupsRasterReadHeader2: Returning 1."); return (1); } /* * 'cupsRasterReadPixels()' - Read raster pixels. * * For best performance, filters should read one or more whole lines. * The "cupsBytesPerLine" value from the page header can be used to allocate * the line buffer and as the number of bytes to read. */ unsigned /* O - Number of bytes read */ cupsRasterReadPixels(cups_raster_t *r, /* I - Raster stream */ unsigned char *p, /* I - Pointer to pixel buffer */ unsigned len) /* I - Number of bytes to read */ { ssize_t bytes; /* Bytes read */ unsigned cupsBytesPerLine; /* cupsBytesPerLine value */ unsigned remaining; /* Bytes remaining */ unsigned char *ptr, /* Pointer to read buffer */ byte, /* Byte from file */ *temp; /* Pointer into buffer */ unsigned count; /* Repetition count */ DEBUG_printf(("cupsRasterReadPixels(r=%p, p=%p, len=%u)", (void *)r, (void *)p, len)); if (r == NULL || r->mode != CUPS_RASTER_READ || r->remaining == 0 || r->header.cupsBytesPerLine == 0) { DEBUG_puts("1cupsRasterReadPixels: Returning 0."); return (0); } DEBUG_printf(("1cupsRasterReadPixels: compressed=%d, remaining=%u", r->compressed, r->remaining)); if (!r->compressed) { /* * Read without compression... */ r->remaining -= len / r->header.cupsBytesPerLine; if (cups_raster_io(r, p, len) < (ssize_t)len) { DEBUG_puts("1cupsRasterReadPixels: Read error, returning 0."); return (0); } /* * Swap bytes as needed... */ if (r->swapped && (r->header.cupsBitsPerColor == 16 || r->header.cupsBitsPerPixel == 12 || r->header.cupsBitsPerPixel == 16)) cups_swap(p, len); /* * Return... */ DEBUG_printf(("1cupsRasterReadPixels: Returning %u", len)); return (len); } /* * Read compressed data... */ remaining = len; cupsBytesPerLine = r->header.cupsBytesPerLine; while (remaining > 0 && r->remaining > 0) { if (r->count == 0) { /* * Need to read a new row... */ if (remaining == cupsBytesPerLine) ptr = p; else ptr = r->pixels; /* * Read using a modified PackBits compression... */ if (!cups_raster_read(r, &byte, 1)) { DEBUG_puts("1cupsRasterReadPixels: Read error, returning 0."); return (0); } r->count = (unsigned)byte + 1; if (r->count > 1) ptr = r->pixels; temp = ptr; bytes = (ssize_t)cupsBytesPerLine; while (bytes > 0) { /* * Get a new repeat count... */ if (!cups_raster_read(r, &byte, 1)) { DEBUG_puts("1cupsRasterReadPixels: Read error, returning 0."); return (0); } if (byte == 128) { /* * Clear to end of line... */ switch (r->header.cupsColorSpace) { case CUPS_CSPACE_W : case CUPS_CSPACE_RGB : case CUPS_CSPACE_SW : case CUPS_CSPACE_SRGB : case CUPS_CSPACE_RGBW : case CUPS_CSPACE_ADOBERGB : memset(temp, 0xff, (size_t)bytes); break; default : memset(temp, 0x00, (size_t)bytes); break; } temp += bytes; bytes = 0; } else if (byte & 128) { /* * Copy N literal pixels... */ count = (unsigned)(257 - byte) * r->bpp; if (count > (unsigned)bytes) count = (unsigned)bytes; if (!cups_raster_read(r, temp, count)) { DEBUG_puts("1cupsRasterReadPixels: Read error, returning 0."); return (0); } temp += count; bytes -= (ssize_t)count; } else { /* * Repeat the next N bytes... */ count = ((unsigned)byte + 1) * r->bpp; if (count > (unsigned)bytes) count = (unsigned)bytes; if (count < r->bpp) break; bytes -= (ssize_t)count; if (!cups_raster_read(r, temp, r->bpp)) { DEBUG_puts("1cupsRasterReadPixels: Read error, returning 0."); return (0); } temp += r->bpp; count -= r->bpp; while (count > 0) { memcpy(temp, temp - r->bpp, r->bpp); temp += r->bpp; count -= r->bpp; } } } /* * Swap bytes as needed... */ if ((r->header.cupsBitsPerColor == 16 || r->header.cupsBitsPerPixel == 12 || r->header.cupsBitsPerPixel == 16) && r->swapped) { DEBUG_puts("1cupsRasterReadPixels: Swapping bytes."); cups_swap(ptr, (size_t)cupsBytesPerLine); } /* * Update pointers... */ if (remaining >= cupsBytesPerLine) { bytes = (ssize_t)cupsBytesPerLine; r->pcurrent = r->pixels; r->count --; r->remaining --; } else { bytes = (ssize_t)remaining; r->pcurrent = r->pixels + bytes; } /* * Copy data as needed... */ if (ptr != p) memcpy(p, ptr, (size_t)bytes); } else { /* * Copy fragment from buffer... */ if ((unsigned)(bytes = (int)(r->pend - r->pcurrent)) > remaining) bytes = (ssize_t)remaining; memcpy(p, r->pcurrent, (size_t)bytes); r->pcurrent += bytes; if (r->pcurrent >= r->pend) { r->pcurrent = r->pixels; r->count --; r->remaining --; } } remaining -= (unsigned)bytes; p += bytes; } DEBUG_printf(("1cupsRasterReadPixels: Returning %u", len)); return (len); } /* * 'cupsRasterWriteHeader()' - Write a raster page header from a version 1 page * header structure. * * This function is deprecated. Use @link cupsRasterWriteHeader2@ instead. * * @deprecated@ */ unsigned /* O - 1 on success, 0 on failure */ cupsRasterWriteHeader( cups_raster_t *r, /* I - Raster stream */ cups_page_header_t *h) /* I - Raster page header */ { DEBUG_printf(("cupsRasterWriteHeader(r=%p, h=%p)", (void *)r, (void *)h)); if (r == NULL || r->mode == CUPS_RASTER_READ) { DEBUG_puts("1cupsRasterWriteHeader: Returning 0."); return (0); } DEBUG_printf(("1cupsRasterWriteHeader: cupsColorSpace=%s", cups_color_spaces[h->cupsColorSpace])); DEBUG_printf(("1cupsRasterWriteHeader: cupsBitsPerColor=%u", h->cupsBitsPerColor)); DEBUG_printf(("1cupsRasterWriteHeader: cupsBitsPerPixel=%u", h->cupsBitsPerPixel)); DEBUG_printf(("1cupsRasterWriteHeader: cupsBytesPerLine=%u", h->cupsBytesPerLine)); DEBUG_printf(("1cupsRasterWriteHeader: cupsWidth=%u", h->cupsWidth)); DEBUG_printf(("1cupsRasterWriteHeader: cupsHeight=%u", h->cupsHeight)); /* * Make a copy of the header, and compute the number of raster * lines in the page image... */ memset(&(r->header), 0, sizeof(r->header)); memcpy(&(r->header), h, sizeof(cups_page_header_t)); if (!cups_raster_update(r)) { DEBUG_puts("1cupsRasterWriteHeader: Unable to update parameters, returning 0."); return (0); } if (r->mode == CUPS_RASTER_WRITE_APPLE) { r->rowheight = h->HWResolution[0] / h->HWResolution[1]; if (h->HWResolution[0] != (r->rowheight * h->HWResolution[1])) return (0); } else r->rowheight = 1; /* * Write the raster header... */ if (r->mode == CUPS_RASTER_WRITE_PWG) { /* * PWG raster data is always network byte order with much of the page header * zeroed. */ cups_page_header2_t fh; /* File page header */ memset(&fh, 0, sizeof(fh)); strlcpy(fh.MediaClass, "PwgRaster", sizeof(fh.MediaClass)); /* PwgRaster */ strlcpy(fh.MediaColor, r->header.MediaColor, sizeof(fh.MediaColor)); strlcpy(fh.MediaType, r->header.MediaType, sizeof(fh.MediaType)); strlcpy(fh.OutputType, r->header.OutputType, sizeof(fh.OutputType)); /* PrintContentType */ fh.CutMedia = htonl(r->header.CutMedia); fh.Duplex = htonl(r->header.Duplex); fh.HWResolution[0] = htonl(r->header.HWResolution[0]); fh.HWResolution[1] = htonl(r->header.HWResolution[1]); fh.ImagingBoundingBox[0] = htonl(r->header.ImagingBoundingBox[0]); fh.ImagingBoundingBox[1] = htonl(r->header.ImagingBoundingBox[1]); fh.ImagingBoundingBox[2] = htonl(r->header.ImagingBoundingBox[2]); fh.ImagingBoundingBox[3] = htonl(r->header.ImagingBoundingBox[3]); fh.InsertSheet = htonl(r->header.InsertSheet); fh.Jog = htonl(r->header.Jog); fh.LeadingEdge = htonl(r->header.LeadingEdge); fh.ManualFeed = htonl(r->header.ManualFeed); fh.MediaPosition = htonl(r->header.MediaPosition); fh.MediaWeight = htonl(r->header.MediaWeight); fh.NumCopies = htonl(r->header.NumCopies); fh.Orientation = htonl(r->header.Orientation); fh.PageSize[0] = htonl(r->header.PageSize[0]); fh.PageSize[1] = htonl(r->header.PageSize[1]); fh.Tumble = htonl(r->header.Tumble); fh.cupsWidth = htonl(r->header.cupsWidth); fh.cupsHeight = htonl(r->header.cupsHeight); fh.cupsBitsPerColor = htonl(r->header.cupsBitsPerColor); fh.cupsBitsPerPixel = htonl(r->header.cupsBitsPerPixel); fh.cupsBytesPerLine = htonl(r->header.cupsBytesPerLine); fh.cupsColorOrder = htonl(r->header.cupsColorOrder); fh.cupsColorSpace = htonl(r->header.cupsColorSpace); fh.cupsNumColors = htonl(r->header.cupsNumColors); fh.cupsInteger[0] = htonl(r->header.cupsInteger[0]); /* TotalPageCount */ fh.cupsInteger[1] = htonl(r->header.cupsInteger[1]); /* CrossFeedTransform */ fh.cupsInteger[2] = htonl(r->header.cupsInteger[2]); /* FeedTransform */ fh.cupsInteger[3] = htonl(r->header.cupsInteger[3]); /* ImageBoxLeft */ fh.cupsInteger[4] = htonl(r->header.cupsInteger[4]); /* ImageBoxTop */ fh.cupsInteger[5] = htonl(r->header.cupsInteger[5]); /* ImageBoxRight */ fh.cupsInteger[6] = htonl(r->header.cupsInteger[6]); /* ImageBoxBottom */ fh.cupsInteger[7] = htonl(r->header.cupsInteger[7]); /* BlackPrimary */ fh.cupsInteger[8] = htonl(r->header.cupsInteger[8]); /* PrintQuality */ fh.cupsInteger[14] = htonl(r->header.cupsInteger[14]); /* VendorIdentifier */ fh.cupsInteger[15] = htonl(r->header.cupsInteger[15]); /* VendorLength */ void *dst = fh.cupsReal; /* Bypass bogus compiler warning */ void *src = r->header.cupsReal; memcpy(dst, src, sizeof(fh.cupsReal) + sizeof(fh.cupsString)); /* VendorData */ strlcpy(fh.cupsRenderingIntent, r->header.cupsRenderingIntent, sizeof(fh.cupsRenderingIntent)); strlcpy(fh.cupsPageSizeName, r->header.cupsPageSizeName, sizeof(fh.cupsPageSizeName)); return (cups_raster_io(r, (unsigned char *)&fh, sizeof(fh)) == sizeof(fh)); } else if (r->mode == CUPS_RASTER_WRITE_APPLE) { /* * Raw raster data is always network byte order with most of the page header * zeroed. */ unsigned char appleheader[32]; /* Raw page header */ if (r->apple_page_count == 0xffffffffU) { /* * Write raw page count from raster page header... */ r->apple_page_count = r->header.cupsInteger[0]; appleheader[0] = 'A'; appleheader[1] = 'S'; appleheader[2] = 'T'; appleheader[3] = 0; appleheader[4] = (unsigned char)(r->apple_page_count >> 24); appleheader[5] = (unsigned char)(r->apple_page_count >> 16); appleheader[6] = (unsigned char)(r->apple_page_count >> 8); appleheader[7] = (unsigned char)(r->apple_page_count); if (cups_raster_io(r, appleheader, 8) != 8) return (0); } memset(appleheader, 0, sizeof(appleheader)); appleheader[0] = (unsigned char)r->header.cupsBitsPerPixel; appleheader[1] = r->header.cupsColorSpace == CUPS_CSPACE_SRGB ? 1 : r->header.cupsColorSpace == CUPS_CSPACE_RGBW ? 2 : r->header.cupsColorSpace == CUPS_CSPACE_ADOBERGB ? 3 : r->header.cupsColorSpace == CUPS_CSPACE_W ? 4 : r->header.cupsColorSpace == CUPS_CSPACE_RGB ? 5 : r->header.cupsColorSpace == CUPS_CSPACE_CMYK ? 6 : 0; appleheader[12] = (unsigned char)(r->header.cupsWidth >> 24); appleheader[13] = (unsigned char)(r->header.cupsWidth >> 16); appleheader[14] = (unsigned char)(r->header.cupsWidth >> 8); appleheader[15] = (unsigned char)(r->header.cupsWidth); appleheader[16] = (unsigned char)(r->header.cupsHeight >> 24); appleheader[17] = (unsigned char)(r->header.cupsHeight >> 16); appleheader[18] = (unsigned char)(r->header.cupsHeight >> 8); appleheader[19] = (unsigned char)(r->header.cupsHeight); appleheader[20] = (unsigned char)(r->header.HWResolution[0] >> 24); appleheader[21] = (unsigned char)(r->header.HWResolution[0] >> 16); appleheader[22] = (unsigned char)(r->header.HWResolution[0] >> 8); appleheader[23] = (unsigned char)(r->header.HWResolution[0]); return (cups_raster_io(r, appleheader, sizeof(appleheader)) == sizeof(appleheader)); } else return (cups_raster_io(r, (unsigned char *)&(r->header), sizeof(r->header)) == sizeof(r->header)); } /* * 'cupsRasterWriteHeader2()' - Write a raster page header from a version 2 * page header structure. * * The page header can be initialized using @link cupsRasterInitPWGHeader@. * * @since CUPS 1.2/macOS 10.5@ */ unsigned /* O - 1 on success, 0 on failure */ cupsRasterWriteHeader2( cups_raster_t *r, /* I - Raster stream */ cups_page_header2_t *h) /* I - Raster page header */ { DEBUG_printf(("cupsRasterWriteHeader(r=%p, h=%p)", (void *)r, (void *)h)); if (r == NULL || r->mode == CUPS_RASTER_READ) { DEBUG_puts("1cupsRasterWriteHeader2: Returning 0."); return (0); } DEBUG_printf(("1cupsRasterWriteHeader2: cupsColorSpace=%s", cups_color_spaces[h->cupsColorSpace])); DEBUG_printf(("1cupsRasterWriteHeader2: cupsBitsPerColor=%u", h->cupsBitsPerColor)); DEBUG_printf(("1cupsRasterWriteHeader2: cupsBitsPerPixel=%u", h->cupsBitsPerPixel)); DEBUG_printf(("1cupsRasterWriteHeader2: cupsBytesPerLine=%u", h->cupsBytesPerLine)); DEBUG_printf(("1cupsRasterWriteHeader2: cupsWidth=%u", h->cupsWidth)); DEBUG_printf(("1cupsRasterWriteHeader2: cupsHeight=%u", h->cupsHeight)); /* * Make a copy of the header, and compute the number of raster * lines in the page image... */ memcpy(&(r->header), h, sizeof(cups_page_header2_t)); if (!cups_raster_update(r)) { DEBUG_puts("1cupsRasterWriteHeader: Unable to update parameters, returning 0."); return (0); } if (r->mode == CUPS_RASTER_WRITE_APPLE) { r->rowheight = h->HWResolution[0] / h->HWResolution[1]; if (h->HWResolution[0] != (r->rowheight * h->HWResolution[1])) return (0); } else r->rowheight = 1; /* * Write the raster header... */ if (r->mode == CUPS_RASTER_WRITE_PWG) { /* * PWG raster data is always network byte order with most of the page header * zeroed. */ cups_page_header2_t fh; /* File page header */ memset(&fh, 0, sizeof(fh)); strlcpy(fh.MediaClass, "PwgRaster", sizeof(fh.MediaClass)); strlcpy(fh.MediaColor, r->header.MediaColor, sizeof(fh.MediaColor)); strlcpy(fh.MediaType, r->header.MediaType, sizeof(fh.MediaType)); strlcpy(fh.OutputType, r->header.OutputType, sizeof(fh.OutputType)); strlcpy(fh.cupsRenderingIntent, r->header.cupsRenderingIntent, sizeof(fh.cupsRenderingIntent)); strlcpy(fh.cupsPageSizeName, r->header.cupsPageSizeName, sizeof(fh.cupsPageSizeName)); fh.CutMedia = htonl(r->header.CutMedia); fh.Duplex = htonl(r->header.Duplex); fh.HWResolution[0] = htonl(r->header.HWResolution[0]); fh.HWResolution[1] = htonl(r->header.HWResolution[1]); fh.ImagingBoundingBox[0] = htonl(r->header.ImagingBoundingBox[0]); fh.ImagingBoundingBox[1] = htonl(r->header.ImagingBoundingBox[1]); fh.ImagingBoundingBox[2] = htonl(r->header.ImagingBoundingBox[2]); fh.ImagingBoundingBox[3] = htonl(r->header.ImagingBoundingBox[3]); fh.InsertSheet = htonl(r->header.InsertSheet); fh.Jog = htonl(r->header.Jog); fh.LeadingEdge = htonl(r->header.LeadingEdge); fh.ManualFeed = htonl(r->header.ManualFeed); fh.MediaPosition = htonl(r->header.MediaPosition); fh.MediaWeight = htonl(r->header.MediaWeight); fh.NumCopies = htonl(r->header.NumCopies); fh.Orientation = htonl(r->header.Orientation); fh.PageSize[0] = htonl(r->header.PageSize[0]); fh.PageSize[1] = htonl(r->header.PageSize[1]); fh.Tumble = htonl(r->header.Tumble); fh.cupsWidth = htonl(r->header.cupsWidth); fh.cupsHeight = htonl(r->header.cupsHeight); fh.cupsBitsPerColor = htonl(r->header.cupsBitsPerColor); fh.cupsBitsPerPixel = htonl(r->header.cupsBitsPerPixel); fh.cupsBytesPerLine = htonl(r->header.cupsBytesPerLine); fh.cupsColorOrder = htonl(r->header.cupsColorOrder); fh.cupsColorSpace = htonl(r->header.cupsColorSpace); fh.cupsNumColors = htonl(r->header.cupsNumColors); fh.cupsInteger[0] = htonl(r->header.cupsInteger[0]); fh.cupsInteger[1] = htonl(r->header.cupsInteger[1]); fh.cupsInteger[2] = htonl(r->header.cupsInteger[2]); fh.cupsInteger[3] = htonl((unsigned)(r->header.cupsImagingBBox[0] * r->header.HWResolution[0] / 72.0)); fh.cupsInteger[4] = htonl((unsigned)(r->header.cupsImagingBBox[1] * r->header.HWResolution[1] / 72.0)); fh.cupsInteger[5] = htonl((unsigned)(r->header.cupsImagingBBox[2] * r->header.HWResolution[0] / 72.0)); fh.cupsInteger[6] = htonl((unsigned)(r->header.cupsImagingBBox[3] * r->header.HWResolution[1] / 72.0)); fh.cupsInteger[7] = htonl(0xffffff); return (cups_raster_io(r, (unsigned char *)&fh, sizeof(fh)) == sizeof(fh)); } else if (r->mode == CUPS_RASTER_WRITE_APPLE) { /* * Raw raster data is always network byte order with most of the page header * zeroed. */ unsigned char appleheader[32]; /* Raw page header */ unsigned height = r->header.cupsHeight * r->rowheight; /* Computed page height */ if (r->apple_page_count == 0xffffffffU) { /* * Write raw page count from raster page header... */ r->apple_page_count = r->header.cupsInteger[0]; appleheader[0] = 'A'; appleheader[1] = 'S'; appleheader[2] = 'T'; appleheader[3] = 0; appleheader[4] = (unsigned char)(r->apple_page_count >> 24); appleheader[5] = (unsigned char)(r->apple_page_count >> 16); appleheader[6] = (unsigned char)(r->apple_page_count >> 8); appleheader[7] = (unsigned char)(r->apple_page_count); if (cups_raster_io(r, appleheader, 8) != 8) return (0); } memset(appleheader, 0, sizeof(appleheader)); appleheader[0] = (unsigned char)r->header.cupsBitsPerPixel; appleheader[1] = r->header.cupsColorSpace == CUPS_CSPACE_SRGB ? 1 : r->header.cupsColorSpace == CUPS_CSPACE_RGBW ? 2 : r->header.cupsColorSpace == CUPS_CSPACE_ADOBERGB ? 3 : r->header.cupsColorSpace == CUPS_CSPACE_W ? 4 : r->header.cupsColorSpace == CUPS_CSPACE_RGB ? 5 : r->header.cupsColorSpace == CUPS_CSPACE_CMYK ? 6 : 0; appleheader[12] = (unsigned char)(r->header.cupsWidth >> 24); appleheader[13] = (unsigned char)(r->header.cupsWidth >> 16); appleheader[14] = (unsigned char)(r->header.cupsWidth >> 8); appleheader[15] = (unsigned char)(r->header.cupsWidth); appleheader[16] = (unsigned char)(height >> 24); appleheader[17] = (unsigned char)(height >> 16); appleheader[18] = (unsigned char)(height >> 8); appleheader[19] = (unsigned char)(height); appleheader[20] = (unsigned char)(r->header.HWResolution[0] >> 24); appleheader[21] = (unsigned char)(r->header.HWResolution[0] >> 16); appleheader[22] = (unsigned char)(r->header.HWResolution[0] >> 8); appleheader[23] = (unsigned char)(r->header.HWResolution[0]); return (cups_raster_io(r, appleheader, sizeof(appleheader)) == sizeof(appleheader)); } else return (cups_raster_io(r, (unsigned char *)&(r->header), sizeof(r->header)) == sizeof(r->header)); } /* * 'cupsRasterWritePixels()' - Write raster pixels. * * For best performance, filters should write one or more whole lines. * The "cupsBytesPerLine" value from the page header can be used to allocate * the line buffer and as the number of bytes to write. */ unsigned /* O - Number of bytes written */ cupsRasterWritePixels(cups_raster_t *r, /* I - Raster stream */ unsigned char *p, /* I - Bytes to write */ unsigned len)/* I - Number of bytes to write */ { ssize_t bytes; /* Bytes read */ unsigned remaining; /* Bytes remaining */ DEBUG_printf(("cupsRasterWritePixels(r=%p, p=%p, len=%u), remaining=%u", (void *)r, (void *)p, len, r->remaining)); if (r == NULL || r->mode == CUPS_RASTER_READ || r->remaining == 0) return (0); if (!r->compressed) { /* * Without compression, just write the raster data raw unless the data needs * to be swapped... */ r->remaining -= len / r->header.cupsBytesPerLine; if (r->swapped && (r->header.cupsBitsPerColor == 16 || r->header.cupsBitsPerPixel == 12 || r->header.cupsBitsPerPixel == 16)) { unsigned char *bufptr; /* Pointer into write buffer */ /* * Allocate a write buffer as needed... */ if ((size_t)len > r->bufsize) { if (r->buffer) bufptr = realloc(r->buffer, len); else bufptr = malloc(len); if (!bufptr) return (0); r->buffer = bufptr; r->bufsize = len; } /* * Byte swap the pixels and write them... */ cups_swap_copy(r->buffer, p, len); bytes = cups_raster_io(r, r->buffer, len); } else bytes = cups_raster_io(r, p, len); if (bytes < len) return (0); else return (len); } /* * Otherwise, compress each line... */ for (remaining = len; remaining > 0; remaining -= (unsigned)bytes, p += bytes) { /* * Figure out the number of remaining bytes on the current line... */ if ((bytes = (ssize_t)remaining) > (ssize_t)(r->pend - r->pcurrent)) bytes = (ssize_t)(r->pend - r->pcurrent); if (r->count > 0) { /* * Check to see if this line is the same as the previous line... */ if (memcmp(p, r->pcurrent, (size_t)bytes)) { if (cups_raster_write(r, r->pixels) <= 0) return (0); r->count = 0; } else { /* * Mark more bytes as the same... */ r->pcurrent += bytes; if (r->pcurrent >= r->pend) { /* * Increase the repeat count... */ r->count += r->rowheight; r->pcurrent = r->pixels; /* * Flush out this line if it is the last one... */ r->remaining --; if (r->remaining == 0) { if (cups_raster_write(r, r->pixels) <= 0) return (0); else return (len); } else if (r->count > (256 - r->rowheight)) { if (cups_raster_write(r, r->pixels) <= 0) return (0); r->count = 0; } } continue; } } if (r->count == 0) { /* * Copy the raster data to the buffer... */ memcpy(r->pcurrent, p, (size_t)bytes); r->pcurrent += bytes; if (r->pcurrent >= r->pend) { /* * Increase the repeat count... */ r->count += r->rowheight; r->pcurrent = r->pixels; /* * Flush out this line if it is the last one... */ r->remaining --; if (r->remaining == 0) { if (cups_raster_write(r, r->pixels) <= 0) return (0); } } } } return (len); } /* * 'cups_raster_read_header()' - Read a raster page header. */ static unsigned /* O - 1 on success, 0 on fail */ cups_raster_read_header( cups_raster_t *r) /* I - Raster stream */ { size_t len; /* Length for read/swap */ DEBUG_printf(("3cups_raster_read_header(r=%p), r->mode=%s", (void *)r, r ? cups_modes[r->mode] : "")); if (r == NULL || r->mode != CUPS_RASTER_READ) return (0); DEBUG_printf(("4cups_raster_read_header: r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount)); memset(&(r->header), 0, sizeof(r->header)); /* * Read the header... */ switch (r->sync) { default : /* * Get the length of the raster header... */ if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1) len = sizeof(cups_page_header_t); else len = sizeof(cups_page_header2_t); DEBUG_printf(("4cups_raster_read_header: len=%d", (int)len)); /* * Read it... */ if (cups_raster_read(r, (unsigned char *)&(r->header), len) < (ssize_t)len) { DEBUG_printf(("4cups_raster_read_header: EOF, r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount)); return (0); } /* * Swap bytes as needed... */ if (r->swapped) { unsigned *s, /* Current word */ temp; /* Temporary copy */ DEBUG_puts("4cups_raster_read_header: Swapping header bytes."); for (len = 81, s = &(r->header.AdvanceDistance); len > 0; len --, s ++) { temp = *s; *s = ((temp & 0xff) << 24) | ((temp & 0xff00) << 8) | ((temp & 0xff0000) >> 8) | ((temp & 0xff000000) >> 24); DEBUG_printf(("4cups_raster_read_header: %08x => %08x", temp, *s)); } } break; case CUPS_RASTER_SYNCapple : case CUPS_RASTER_REVSYNCapple : { unsigned char appleheader[32]; /* Raw header */ static const unsigned rawcspace[] = { CUPS_CSPACE_SW, CUPS_CSPACE_SRGB, CUPS_CSPACE_RGBW, CUPS_CSPACE_ADOBERGB, CUPS_CSPACE_W, CUPS_CSPACE_RGB, CUPS_CSPACE_CMYK }; static const unsigned rawnumcolors[] = { 1, 3, 4, 3, 1, 3, 4 }; if (cups_raster_read(r, appleheader, sizeof(appleheader)) < (ssize_t)sizeof(appleheader)) { DEBUG_printf(("4cups_raster_read_header: EOF, r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount)); return (0); } strlcpy(r->header.MediaClass, "PwgRaster", sizeof(r->header.MediaClass)); /* PwgRaster */ r->header.cupsBitsPerPixel = appleheader[0]; r->header.cupsColorSpace = appleheader[1] >= (sizeof(rawcspace) / sizeof(rawcspace[0])) ? CUPS_CSPACE_DEVICE1 : rawcspace[appleheader[1]]; r->header.cupsNumColors = appleheader[1] >= (sizeof(rawnumcolors) / sizeof(rawnumcolors[0])) ? 1 : rawnumcolors[appleheader[1]]; r->header.cupsBitsPerColor = r->header.cupsBitsPerPixel / r->header.cupsNumColors; r->header.cupsWidth = ((((((unsigned)appleheader[12] << 8) | (unsigned)appleheader[13]) << 8) | (unsigned)appleheader[14]) << 8) | (unsigned)appleheader[15]; r->header.cupsHeight = ((((((unsigned)appleheader[16] << 8) | (unsigned)appleheader[17]) << 8) | (unsigned)appleheader[18]) << 8) | (unsigned)appleheader[19]; r->header.cupsBytesPerLine = r->header.cupsWidth * r->header.cupsBitsPerPixel / 8; r->header.cupsColorOrder = CUPS_ORDER_CHUNKED; r->header.HWResolution[0] = r->header.HWResolution[1] = ((((((unsigned)appleheader[20] << 8) | (unsigned)appleheader[21]) << 8) | (unsigned)appleheader[22]) << 8) | (unsigned)appleheader[23]; if (r->header.HWResolution[0] > 0) { r->header.PageSize[0] = (unsigned)(r->header.cupsWidth * 72 / r->header.HWResolution[0]); r->header.PageSize[1] = (unsigned)(r->header.cupsHeight * 72 / r->header.HWResolution[1]); r->header.cupsPageSize[0] = (float)(r->header.cupsWidth * 72.0 / r->header.HWResolution[0]); r->header.cupsPageSize[1] = (float)(r->header.cupsHeight * 72.0 / r->header.HWResolution[1]); } r->header.cupsInteger[0] = r->apple_page_count; r->header.cupsInteger[7] = 0xffffff; } break; } /* * Update the header and row count... */ if (!cups_raster_update(r)) return (0); DEBUG_printf(("4cups_raster_read_header: cupsBitsPerPixel=%u, cupsBitsPerColor=%u, cupsBytesPerLine=%u, cupsWidth=%u, cupsHeight=%u, r->bpp=%d", r->header.cupsBitsPerPixel, r->header.cupsBitsPerColor, r->header.cupsBytesPerLine, r->header.cupsWidth, r->header.cupsHeight, r->bpp)); return (r->header.cupsBitsPerPixel > 0 && r->header.cupsBitsPerPixel <= 240 && r->header.cupsBitsPerColor > 0 && r->header.cupsBitsPerColor <= 16 && r->header.cupsBytesPerLine > 0 && r->header.cupsBytesPerLine <= 0x7fffffff && r->header.cupsHeight != 0 && (r->header.cupsBytesPerLine % r->bpp) == 0); } /* * 'cups_raster_io()' - Read/write bytes from a context, handling interruptions. */ static ssize_t /* O - Bytes read/write or -1 */ cups_raster_io(cups_raster_t *r, /* I - Raster stream */ unsigned char *buf, /* I - Buffer for read/write */ size_t bytes) /* I - Number of bytes to read/write */ { ssize_t count, /* Number of bytes read/written */ total; /* Total bytes read/written */ DEBUG_printf(("5cups_raster_io(r=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)r, (void *)buf, CUPS_LLCAST bytes)); for (total = 0; total < (ssize_t)bytes; total += count, buf += count) { count = (*r->iocb)(r->ctx, buf, bytes - (size_t)total); DEBUG_printf(("6cups_raster_io: count=%d, total=%d", (int)count, (int)total)); if (count == 0) break; // { // DEBUG_puts("6cups_raster_io: Returning 0."); // return (0); // } else if (count < 0) { DEBUG_puts("6cups_raster_io: Returning -1 on error."); return (-1); } #ifdef DEBUG r->iocount += (size_t)count; #endif /* DEBUG */ } DEBUG_printf(("6cups_raster_io: iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount)); DEBUG_printf(("6cups_raster_io: Returning " CUPS_LLFMT ".", CUPS_LLCAST total)); return (total); } /* * 'cups_raster_read()' - Read through the raster buffer. */ static ssize_t /* O - Number of bytes read */ cups_raster_read(cups_raster_t *r, /* I - Raster stream */ unsigned char *buf, /* I - Buffer */ size_t bytes) /* I - Number of bytes to read */ { ssize_t count, /* Number of bytes read */ remaining, /* Remaining bytes in buffer */ total; /* Total bytes read */ DEBUG_printf(("4cups_raster_read(r=%p, buf=%p, bytes=" CUPS_LLFMT "), offset=" CUPS_LLFMT, (void *)r, (void *)buf, CUPS_LLCAST bytes, CUPS_LLCAST (r->iostart + r->bufptr - r->buffer))); if (!r->compressed) return (cups_raster_io(r, buf, bytes)); /* * Allocate a read buffer as needed... */ count = (ssize_t)(2 * r->header.cupsBytesPerLine); if (count < 65536) count = 65536; if ((size_t)count > r->bufsize) { ssize_t offset = r->bufptr - r->buffer; /* Offset to current start of buffer */ ssize_t end = r->bufend - r->buffer;/* Offset to current end of buffer */ unsigned char *rptr; /* Pointer in read buffer */ if (r->buffer) rptr = realloc(r->buffer, (size_t)count); else rptr = malloc((size_t)count); if (!rptr) return (0); r->buffer = rptr; r->bufptr = rptr + offset; r->bufend = rptr + end; r->bufsize = (size_t)count; } /* * Loop until we have read everything... */ for (total = 0, remaining = (int)(r->bufend - r->bufptr); total < (ssize_t)bytes; total += count, buf += count) { count = (ssize_t)bytes - total; DEBUG_printf(("5cups_raster_read: count=" CUPS_LLFMT ", remaining=" CUPS_LLFMT ", buf=%p, bufptr=%p, bufend=%p", CUPS_LLCAST count, CUPS_LLCAST remaining, (void *)buf, (void *)r->bufptr, (void *)r->bufend)); if (remaining == 0) { if (count < 16) { /* * Read into the raster buffer and then copy... */ #ifdef DEBUG r->iostart += (size_t)(r->bufend - r->buffer); #endif /* DEBUG */ remaining = (*r->iocb)(r->ctx, r->buffer, r->bufsize); if (remaining <= 0) return (0); r->bufptr = r->buffer; r->bufend = r->buffer + remaining; #ifdef DEBUG r->iocount += (size_t)remaining; #endif /* DEBUG */ } else { /* * Read directly into "buf"... */ count = (*r->iocb)(r->ctx, buf, (size_t)count); if (count <= 0) return (0); #ifdef DEBUG r->iostart += (size_t)count; r->iocount += (size_t)count; #endif /* DEBUG */ continue; } } /* * Copy bytes from raster buffer to "buf"... */ if (count > remaining) count = remaining; if (count == 1) { /* * Copy 1 byte... */ *buf = *(r->bufptr)++; remaining --; } else if (count < 128) { /* * Copy up to 127 bytes without using memcpy(); this is * faster because it avoids an extra function call and is * often further optimized by the compiler... */ unsigned char *bufptr; /* Temporary buffer pointer */ remaining -= count; for (bufptr = r->bufptr; count > 0; count --, total ++) *buf++ = *bufptr++; r->bufptr = bufptr; } else { /* * Use memcpy() for a large read... */ memcpy(buf, r->bufptr, (size_t)count); r->bufptr += count; remaining -= count; } } DEBUG_printf(("5cups_raster_read: Returning %ld", (long)total)); return (total); } /* * 'cups_raster_update()' - Update the raster header and row count for the * current page. */ static int /* O - 1 on success, 0 on failure */ cups_raster_update(cups_raster_t *r) /* I - Raster stream */ { if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1 || r->header.cupsNumColors == 0) { /* * Set the "cupsNumColors" field according to the colorspace... */ switch (r->header.cupsColorSpace) { case CUPS_CSPACE_W : case CUPS_CSPACE_K : case CUPS_CSPACE_WHITE : case CUPS_CSPACE_GOLD : case CUPS_CSPACE_SILVER : case CUPS_CSPACE_SW : r->header.cupsNumColors = 1; break; case CUPS_CSPACE_RGB : case CUPS_CSPACE_CMY : case CUPS_CSPACE_YMC : case CUPS_CSPACE_CIEXYZ : case CUPS_CSPACE_CIELab : case CUPS_CSPACE_SRGB : case CUPS_CSPACE_ADOBERGB : case CUPS_CSPACE_ICC1 : case CUPS_CSPACE_ICC2 : case CUPS_CSPACE_ICC3 : case CUPS_CSPACE_ICC4 : case CUPS_CSPACE_ICC5 : case CUPS_CSPACE_ICC6 : case CUPS_CSPACE_ICC7 : case CUPS_CSPACE_ICC8 : case CUPS_CSPACE_ICC9 : case CUPS_CSPACE_ICCA : case CUPS_CSPACE_ICCB : case CUPS_CSPACE_ICCC : case CUPS_CSPACE_ICCD : case CUPS_CSPACE_ICCE : case CUPS_CSPACE_ICCF : r->header.cupsNumColors = 3; break; case CUPS_CSPACE_RGBA : case CUPS_CSPACE_RGBW : case CUPS_CSPACE_CMYK : case CUPS_CSPACE_YMCK : case CUPS_CSPACE_KCMY : case CUPS_CSPACE_GMCK : case CUPS_CSPACE_GMCS : r->header.cupsNumColors = 4; break; case CUPS_CSPACE_KCMYcm : if (r->header.cupsBitsPerPixel < 8) r->header.cupsNumColors = 6; else r->header.cupsNumColors = 4; break; case CUPS_CSPACE_DEVICE1 : case CUPS_CSPACE_DEVICE2 : case CUPS_CSPACE_DEVICE3 : case CUPS_CSPACE_DEVICE4 : case CUPS_CSPACE_DEVICE5 : case CUPS_CSPACE_DEVICE6 : case CUPS_CSPACE_DEVICE7 : case CUPS_CSPACE_DEVICE8 : case CUPS_CSPACE_DEVICE9 : case CUPS_CSPACE_DEVICEA : case CUPS_CSPACE_DEVICEB : case CUPS_CSPACE_DEVICEC : case CUPS_CSPACE_DEVICED : case CUPS_CSPACE_DEVICEE : case CUPS_CSPACE_DEVICEF : r->header.cupsNumColors = r->header.cupsColorSpace - CUPS_CSPACE_DEVICE1 + 1; break; default : /* Unknown color space */ return (0); } } /* * Set the number of bytes per pixel/color... */ if (r->header.cupsColorOrder == CUPS_ORDER_CHUNKED) r->bpp = (r->header.cupsBitsPerPixel + 7) / 8; else r->bpp = (r->header.cupsBitsPerColor + 7) / 8; if (r->bpp == 0) r->bpp = 1; /* * Set the number of remaining rows... */ if (r->header.cupsColorOrder == CUPS_ORDER_PLANAR) r->remaining = r->header.cupsHeight * r->header.cupsNumColors; else r->remaining = r->header.cupsHeight; /* * Allocate the compression buffer... */ if (r->compressed) { if (r->pixels != NULL) free(r->pixels); if ((r->pixels = calloc(r->header.cupsBytesPerLine, 1)) == NULL) { r->pcurrent = NULL; r->pend = NULL; r->count = 0; return (0); } r->pcurrent = r->pixels; r->pend = r->pixels + r->header.cupsBytesPerLine; r->count = 0; } return (1); } /* * 'cups_raster_write()' - Write a row of compressed raster data... */ static ssize_t /* O - Number of bytes written */ cups_raster_write( cups_raster_t *r, /* I - Raster stream */ const unsigned char *pixels) /* I - Pixel data to write */ { const unsigned char *start, /* Start of sequence */ *ptr, /* Current pointer in sequence */ *pend, /* End of raster buffer */ *plast; /* Pointer to last pixel */ unsigned char *wptr; /* Pointer into write buffer */ unsigned bpp, /* Bytes per pixel */ count; /* Count */ _cups_copyfunc_t cf; /* Copy function */ DEBUG_printf(("3cups_raster_write(r=%p, pixels=%p)", (void *)r, (void *)pixels)); /* * Determine whether we need to swap bytes... */ if (r->swapped && (r->header.cupsBitsPerColor == 16 || r->header.cupsBitsPerPixel == 12 || r->header.cupsBitsPerPixel == 16)) { DEBUG_puts("4cups_raster_write: Swapping bytes when writing."); cf = (_cups_copyfunc_t)cups_swap_copy; } else cf = (_cups_copyfunc_t)memcpy; /* * Allocate a write buffer as needed... */ count = r->header.cupsBytesPerLine * 2; if (count < 65536) count = 65536; if ((size_t)count > r->bufsize) { if (r->buffer) wptr = realloc(r->buffer, count); else wptr = malloc(count); if (!wptr) { DEBUG_printf(("4cups_raster_write: Unable to allocate " CUPS_LLFMT " bytes for raster buffer: %s", CUPS_LLCAST count, strerror(errno))); return (-1); } r->buffer = wptr; r->bufsize = count; } /* * Write the row repeat count... */ bpp = r->bpp; pend = pixels + r->header.cupsBytesPerLine; plast = pend - bpp; wptr = r->buffer; *wptr++ = (unsigned char)(r->count - 1); /* * Write using a modified PackBits compression... */ for (ptr = pixels; ptr < pend;) { start = ptr; ptr += bpp; if (ptr == pend) { /* * Encode a single pixel at the end... */ *wptr++ = 0; (*cf)(wptr, start, bpp); wptr += bpp; } else if (!memcmp(start, ptr, bpp)) { /* * Encode a sequence of repeating pixels... */ for (count = 2; count < 128 && ptr < plast; count ++, ptr += bpp) if (memcmp(ptr, ptr + bpp, bpp)) break; *wptr++ = (unsigned char)(count - 1); (*cf)(wptr, ptr, bpp); wptr += bpp; ptr += bpp; } else { /* * Encode a sequence of non-repeating pixels... */ for (count = 1; count < 128 && ptr < plast; count ++, ptr += bpp) if (!memcmp(ptr, ptr + bpp, bpp)) break; if (ptr >= plast && count < 128) { count ++; ptr += bpp; } *wptr++ = (unsigned char)(257 - count); count *= bpp; (*cf)(wptr, start, count); wptr += count; } } DEBUG_printf(("4cups_raster_write: Writing " CUPS_LLFMT " bytes.", CUPS_LLCAST (wptr - r->buffer))); return (cups_raster_io(r, r->buffer, (size_t)(wptr - r->buffer))); } /* * 'cups_read_fd()' - Read bytes from a file. */ static ssize_t /* O - Bytes read or -1 */ cups_read_fd(void *ctx, /* I - File descriptor as pointer */ unsigned char *buf, /* I - Buffer for read */ size_t bytes) /* I - Maximum number of bytes to read */ { int fd = (int)((intptr_t)ctx); /* File descriptor */ ssize_t count; /* Number of bytes read */ #ifdef WIN32 /* Sigh */ while ((count = read(fd, buf, (unsigned)bytes)) < 0) #else while ((count = read(fd, buf, bytes)) < 0) #endif /* WIN32 */ if (errno != EINTR && errno != EAGAIN) { DEBUG_printf(("8cups_read_fd: %s", strerror(errno))); return (-1); } DEBUG_printf(("8cups_read_fd: Returning %d bytes.", (int)count)); return (count); } /* * 'cups_swap()' - Swap bytes in raster data... */ static void cups_swap(unsigned char *buf, /* I - Buffer to swap */ size_t bytes) /* I - Number of bytes to swap */ { unsigned char even, odd; /* Temporary variables */ bytes /= 2; while (bytes > 0) { even = buf[0]; odd = buf[1]; buf[0] = odd; buf[1] = even; buf += 2; bytes --; } } /* * 'cups_swap_copy()' - Copy and swap bytes in raster data... */ static void cups_swap_copy( unsigned char *dst, /* I - Destination */ const unsigned char *src, /* I - Source */ size_t bytes) /* I - Number of bytes to swap */ { bytes /= 2; while (bytes > 0) { dst[0] = src[1]; dst[1] = src[0]; dst += 2; src += 2; bytes --; } } /* * 'cups_write_fd()' - Write bytes to a file. */ static ssize_t /* O - Bytes written or -1 */ cups_write_fd(void *ctx, /* I - File descriptor pointer */ unsigned char *buf, /* I - Bytes to write */ size_t bytes) /* I - Number of bytes to write */ { int fd = (int)((intptr_t)ctx); /* File descriptor */ ssize_t count; /* Number of bytes written */ #ifdef WIN32 /* Sigh */ while ((count = write(fd, buf, (unsigned)bytes)) < 0) #else while ((count = write(fd, buf, bytes)) < 0) #endif /* WIN32 */ if (errno != EINTR && errno != EAGAIN) { DEBUG_printf(("8cups_write_fd: %s", strerror(errno))); return (-1); } return (count); } ippsample/cups/testhttp.c0000644000175000017500000006106513240604116014544 0ustar tilltill/* * HTTP test program for CUPS. * * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" /* * Types and structures... */ typedef struct uri_test_s /**** URI test cases ****/ { http_uri_status_t result; /* Expected return value */ const char *uri, /* URI */ *scheme, /* Scheme string */ *username, /* Username:password string */ *hostname, /* Hostname string */ *resource; /* Resource string */ int port, /* Port number */ assemble_port; /* Port number for httpAssembleURI() */ http_uri_coding_t assemble_coding;/* Coding for httpAssembleURI() */ } uri_test_t; /* * Local globals... */ static uri_test_t uri_tests[] = /* URI test data */ { /* Start with valid URIs */ { HTTP_URI_STATUS_OK, "file:/filename", "file", "", "", "/filename", 0, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "file:/filename%20with%20spaces", "file", "", "", "/filename with spaces", 0, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "file:///filename", "file", "", "", "/filename", 0, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "file:///filename%20with%20spaces", "file", "", "", "/filename with spaces", 0, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "file://localhost/filename", "file", "", "localhost", "/filename", 0, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "file://localhost/filename%20with%20spaces", "file", "", "localhost", "/filename with spaces", 0, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "http://server/", "http", "", "server", "/", 80, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "http://username@server/", "http", "username", "server", "/", 80, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "http://username:passwor%64@server/", "http", "username:password", "server", "/", 80, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "http://username:passwor%64@server:8080/", "http", "username:password", "server", "/", 8080, 8080, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "http://username:passwor%64@server:8080/directory/filename", "http", "username:password", "server", "/directory/filename", 8080, 8080, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "http://[2000::10:100]:631/ipp", "http", "", "2000::10:100", "/ipp", 631, 631, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "https://username:passwor%64@server/directory/filename", "https", "username:password", "server", "/directory/filename", 443, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "ipp://username:passwor%64@[::1]/ipp", "ipp", "username:password", "::1", "/ipp", 631, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "lpd://server/queue?reserve=yes", "lpd", "", "server", "/queue?reserve=yes", 515, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "mailto:user@domain.com", "mailto", "", "", "user@domain.com", 0, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "socket://server/", "socket", "", "server", "/", 9100, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "socket://192.168.1.1:9101/", "socket", "", "192.168.1.1", "/", 9101, 9101, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "tel:8005551212", "tel", "", "", "8005551212", 0, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "ipp://username:password@[v1.fe80::200:1234:5678:9abc+eth0]:999/ipp", "ipp", "username:password", "fe80::200:1234:5678:9abc%eth0", "/ipp", 999, 999, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "ipp://username:password@[fe80::200:1234:5678:9abc%25eth0]:999/ipp", "ipp", "username:password", "fe80::200:1234:5678:9abc%eth0", "/ipp", 999, 999, (http_uri_coding_t)(HTTP_URI_CODING_MOST | HTTP_URI_CODING_RFC6874) }, { HTTP_URI_STATUS_OK, "http://server/admin?DEVICE_URI=usb://HP/Photosmart%25202600%2520series?serial=MY53OK70V10400", "http", "", "server", "/admin?DEVICE_URI=usb://HP/Photosmart%25202600%2520series?serial=MY53OK70V10400", 80, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "lpd://Acme%20Laser%20(01%3A23%3A45).local._tcp._printer/", "lpd", "", "Acme Laser (01:23:45).local._tcp._printer", "/", 515, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "ipp://HP%20Officejet%204500%20G510n-z%20%40%20Will's%20MacBook%20Pro%2015%22._ipp._tcp.local./", "ipp", "", "HP Officejet 4500 G510n-z @ Will's MacBook Pro 15\"._ipp._tcp.local.", "/", 631, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_OK, "ipp://%22%23%2F%3A%3C%3E%3F%40%5B%5C%5D%5E%60%7B%7C%7D/", "ipp", "", "\"#/:<>?@[\\]^`{|}", "/", 631, 0, HTTP_URI_CODING_MOST }, /* Missing scheme */ { HTTP_URI_STATUS_MISSING_SCHEME, "/path/to/file/index.html", "file", "", "", "/path/to/file/index.html", 0, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_MISSING_SCHEME, "//server/ipp", "ipp", "", "server", "/ipp", 631, 0, HTTP_URI_CODING_MOST }, /* Unknown scheme */ { HTTP_URI_STATUS_UNKNOWN_SCHEME, "vendor://server/resource", "vendor", "", "server", "/resource", 0, 0, HTTP_URI_CODING_MOST }, /* Missing resource */ { HTTP_URI_STATUS_MISSING_RESOURCE, "socket://[::192.168.2.1]", "socket", "", "::192.168.2.1", "/", 9100, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_MISSING_RESOURCE, "socket://192.168.1.1:9101", "socket", "", "192.168.1.1", "/", 9101, 0, HTTP_URI_CODING_MOST }, /* Bad URI */ { HTTP_URI_STATUS_BAD_URI, "", "", "", "", "", 0, 0, HTTP_URI_CODING_MOST }, /* Bad scheme */ { HTTP_URI_STATUS_BAD_SCHEME, "bad_scheme://server/resource", "", "", "", "", 0, 0, HTTP_URI_CODING_MOST }, /* Bad username */ { HTTP_URI_STATUS_BAD_USERNAME, "http://username:passwor%6@server/resource", "http", "", "", "", 80, 0, HTTP_URI_CODING_MOST }, /* Bad hostname */ { HTTP_URI_STATUS_BAD_HOSTNAME, "http://[/::1]/index.html", "http", "", "", "", 80, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_BAD_HOSTNAME, "http://[", "http", "", "", "", 80, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_BAD_HOSTNAME, "http://serve%7/index.html", "http", "", "", "", 80, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_BAD_HOSTNAME, "http://server with spaces/index.html", "http", "", "", "", 80, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_BAD_HOSTNAME, "ipp://\"#/:<>?@[\\]^`{|}/", "ipp", "", "", "", 631, 0, HTTP_URI_CODING_MOST }, /* Bad port number */ { HTTP_URI_STATUS_BAD_PORT, "http://127.0.0.1:9999a/index.html", "http", "", "127.0.0.1", "", 0, 0, HTTP_URI_CODING_MOST }, /* Bad resource */ { HTTP_URI_STATUS_BAD_RESOURCE, "http://server/index.html%", "http", "", "server", "", 80, 0, HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_BAD_RESOURCE, "http://server/index with spaces.html", "http", "", "server", "", 80, 0, HTTP_URI_CODING_MOST } }; static const char * const base64_tests[][2] = { { "A", "QQ==" }, /* 010000 01 */ { "AB", "QUI=" }, /* 010000 010100 0010 */ { "ABC", "QUJD" }, /* 010000 010100 001001 000011 */ { "ABCD", "QUJDRA==" }, /* 010000 010100 001001 000011 010001 00 */ { "ABCDE", "QUJDREU=" }, /* 010000 010100 001001 000011 010001 000100 0101 */ { "ABCDEF", "QUJDREVG" }, /* 010000 010100 001001 000011 010001 000100 010101 000110 */ }; /* * 'main()' - Main entry. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int i, j, k; /* Looping vars */ http_t *http; /* HTTP connection */ http_encryption_t encryption; /* Encryption type */ http_status_t status; /* Status of GET command */ int failures; /* Number of test failures */ char buffer[8192]; /* Input buffer */ long bytes; /* Number of bytes read */ FILE *out; /* Output file */ char encode[256], /* Base64-encoded string */ decode[256]; /* Base64-decoded string */ int decodelen; /* Length of decoded string */ char scheme[HTTP_MAX_URI], /* Scheme from URI */ hostname[HTTP_MAX_URI], /* Hostname from URI */ username[HTTP_MAX_URI], /* Username:password from URI */ resource[HTTP_MAX_URI]; /* Resource from URI */ int port; /* Port number from URI */ http_uri_status_t uri_status; /* Status of URI separation */ http_addrlist_t *addrlist, /* Address list */ *addr; /* Current address */ off_t length, total; /* Length and total bytes */ time_t start, current; /* Start and end time */ const char *encoding; /* Negotiated Content-Encoding */ static const char * const uri_status_strings[] = { "HTTP_URI_STATUS_OVERFLOW", "HTTP_URI_STATUS_BAD_ARGUMENTS", "HTTP_URI_STATUS_BAD_RESOURCE", "HTTP_URI_STATUS_BAD_PORT", "HTTP_URI_STATUS_BAD_HOSTNAME", "HTTP_URI_STATUS_BAD_USERNAME", "HTTP_URI_STATUS_BAD_SCHEME", "HTTP_URI_STATUS_BAD_URI", "HTTP_URI_STATUS_OK", "HTTP_URI_STATUS_MISSING_SCHEME", "HTTP_URI_STATUS_UNKNOWN_SCHEME", "HTTP_URI_STATUS_MISSING_RESOURCE" }; /* * Do API tests if we don't have a URL on the command-line... */ if (argc == 1) { failures = 0; /* * httpGetDateString()/httpGetDateTime() */ fputs("httpGetDateString()/httpGetDateTime(): ", stdout); start = time(NULL); strlcpy(buffer, httpGetDateString(start), sizeof(buffer)); current = httpGetDateTime(buffer); i = (int)(current - start); if (i < 0) i = -i; if (!i) puts("PASS"); else { failures ++; puts("FAIL"); printf(" Difference is %d seconds, %02d:%02d:%02d...\n", i, i / 3600, (i / 60) % 60, i % 60); printf(" httpGetDateString(%d) returned \"%s\"\n", (int)start, buffer); printf(" httpGetDateTime(\"%s\") returned %d\n", buffer, (int)current); printf(" httpGetDateString(%d) returned \"%s\"\n", (int)current, httpGetDateString(current)); } /* * httpDecode64_2()/httpEncode64_2() */ fputs("httpDecode64_2()/httpEncode64_2(): ", stdout); for (i = 0, j = 0; i < (int)(sizeof(base64_tests) / sizeof(base64_tests[0])); i ++) { httpEncode64_2(encode, sizeof(encode), base64_tests[i][0], (int)strlen(base64_tests[i][0])); decodelen = (int)sizeof(decode); httpDecode64_2(decode, &decodelen, base64_tests[i][1]); if (strcmp(decode, base64_tests[i][0])) { failures ++; if (j) { puts("FAIL"); j = 1; } printf(" httpDecode64_2() returned \"%s\", expected \"%s\"...\n", decode, base64_tests[i][0]); } if (strcmp(encode, base64_tests[i][1])) { failures ++; if (j) { puts("FAIL"); j = 1; } printf(" httpEncode64_2() returned \"%s\", expected \"%s\"...\n", encode, base64_tests[i][1]); } } if (!j) puts("PASS"); /* * httpGetHostname() */ fputs("httpGetHostname(): ", stdout); if (httpGetHostname(NULL, hostname, sizeof(hostname))) printf("PASS (%s)\n", hostname); else { failures ++; puts("FAIL"); } /* * httpAddrGetList() */ printf("httpAddrGetList(%s): ", hostname); addrlist = httpAddrGetList(hostname, AF_UNSPEC, NULL); if (addrlist) { for (i = 0, addr = addrlist; addr; i ++, addr = addr->next) { char numeric[1024]; /* Numeric IP address */ httpAddrString(&(addr->addr), numeric, sizeof(numeric)); if (!strcmp(numeric, "UNKNOWN")) break; } if (addr) printf("FAIL (bad address for %s)\n", hostname); else printf("PASS (%d address(es) for %s)\n", i, hostname); httpAddrFreeList(addrlist); } else if (isdigit(hostname[0] & 255)) { puts("FAIL (ignored because hostname is numeric)"); } else { failures ++; puts("FAIL"); } /* * Test httpSeparateURI()... */ fputs("httpSeparateURI(): ", stdout); for (i = 0, j = 0; i < (int)(sizeof(uri_tests) / sizeof(uri_tests[0])); i ++) { uri_status = httpSeparateURI(HTTP_URI_CODING_MOST, uri_tests[i].uri, scheme, sizeof(scheme), username, sizeof(username), hostname, sizeof(hostname), &port, resource, sizeof(resource)); if (uri_status != uri_tests[i].result || strcmp(scheme, uri_tests[i].scheme) || strcmp(username, uri_tests[i].username) || strcmp(hostname, uri_tests[i].hostname) || port != uri_tests[i].port || strcmp(resource, uri_tests[i].resource)) { failures ++; if (!j) { puts("FAIL"); j = 1; } printf(" \"%s\":\n", uri_tests[i].uri); if (uri_status != uri_tests[i].result) printf(" Returned %s instead of %s\n", uri_status_strings[uri_status + 8], uri_status_strings[uri_tests[i].result + 8]); if (strcmp(scheme, uri_tests[i].scheme)) printf(" Scheme \"%s\" instead of \"%s\"\n", scheme, uri_tests[i].scheme); if (strcmp(username, uri_tests[i].username)) printf(" Username \"%s\" instead of \"%s\"\n", username, uri_tests[i].username); if (strcmp(hostname, uri_tests[i].hostname)) printf(" Hostname \"%s\" instead of \"%s\"\n", hostname, uri_tests[i].hostname); if (port != uri_tests[i].port) printf(" Port %d instead of %d\n", port, uri_tests[i].port); if (strcmp(resource, uri_tests[i].resource)) printf(" Resource \"%s\" instead of \"%s\"\n", resource, uri_tests[i].resource); } } if (!j) printf("PASS (%d URIs tested)\n", (int)(sizeof(uri_tests) / sizeof(uri_tests[0]))); /* * Test httpAssembleURI()... */ fputs("httpAssembleURI(): ", stdout); for (i = 0, j = 0, k = 0; i < (int)(sizeof(uri_tests) / sizeof(uri_tests[0])); i ++) if (uri_tests[i].result == HTTP_URI_STATUS_OK && !strstr(uri_tests[i].uri, "%64") && strstr(uri_tests[i].uri, "//")) { k ++; uri_status = httpAssembleURI(uri_tests[i].assemble_coding, buffer, sizeof(buffer), uri_tests[i].scheme, uri_tests[i].username, uri_tests[i].hostname, uri_tests[i].assemble_port, uri_tests[i].resource); if (uri_status != HTTP_URI_STATUS_OK) { failures ++; if (!j) { puts("FAIL"); j = 1; } printf(" \"%s\": %s\n", uri_tests[i].uri, uri_status_strings[uri_status + 8]); } else if (strcmp(buffer, uri_tests[i].uri)) { failures ++; if (!j) { puts("FAIL"); j = 1; } printf(" \"%s\": assembled = \"%s\"\n", uri_tests[i].uri, buffer); } } if (!j) printf("PASS (%d URIs tested)\n", k); /* * httpAssembleUUID */ fputs("httpAssembleUUID: ", stdout); httpAssembleUUID("hostname.example.com", 631, "printer", 12345, buffer, sizeof(buffer)); if (strncmp(buffer, "urn:uuid:", 9)) { printf("FAIL (%s)\n", buffer); failures ++; } else printf("PASS (%s)\n", buffer); /* * Show a summary and return... */ if (failures) printf("\n%d TESTS FAILED!\n", failures); else puts("\nALL TESTS PASSED!"); return (failures); } else if (strstr(argv[1], "._tcp")) { /* * Test resolving an mDNS name. */ char resolved[1024]; /* Resolved URI */ printf("_httpResolveURI(%s, _HTTP_RESOLVE_DEFAULT): ", argv[1]); fflush(stdout); if (!_httpResolveURI(argv[1], resolved, sizeof(resolved), _HTTP_RESOLVE_DEFAULT, NULL, NULL)) { puts("FAIL"); return (1); } else printf("PASS (%s)\n", resolved); printf("_httpResolveURI(%s, _HTTP_RESOLVE_FQDN): ", argv[1]); fflush(stdout); if (!_httpResolveURI(argv[1], resolved, sizeof(resolved), _HTTP_RESOLVE_FQDN, NULL, NULL)) { puts("FAIL"); return (1); } else if (strstr(resolved, ".local:")) { printf("FAIL (%s)\n", resolved); return (1); } else { printf("PASS (%s)\n", resolved); return (0); } } else if (!strcmp(argv[1], "-u") && argc == 3) { /* * Test URI separation... */ uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, argv[2], scheme, sizeof(scheme), username, sizeof(username), hostname, sizeof(hostname), &port, resource, sizeof(resource)); printf("uri_status = %s\n", uri_status_strings[uri_status + 8]); printf("scheme = \"%s\"\n", scheme); printf("username = \"%s\"\n", username); printf("hostname = \"%s\"\n", hostname); printf("port = %d\n", port); printf("resource = \"%s\"\n", resource); return (0); } /* * Test HTTP GET requests... */ http = NULL; out = stdout; for (i = 1; i < argc; i ++) { if (!strcmp(argv[i], "-o")) { i ++; if (i >= argc) break; out = fopen(argv[i], "wb"); continue; } httpSeparateURI(HTTP_URI_CODING_MOST, argv[i], scheme, sizeof(scheme), username, sizeof(username), hostname, sizeof(hostname), &port, resource, sizeof(resource)); if (!_cups_strcasecmp(scheme, "https") || !_cups_strcasecmp(scheme, "ipps") || port == 443) encryption = HTTP_ENCRYPTION_ALWAYS; else encryption = HTTP_ENCRYPTION_IF_REQUESTED; http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL); if (http == NULL) { perror(hostname); continue; } if (httpIsEncrypted(http)) { cups_array_t *creds; char info[1024]; static const char *trusts[] = { "OK", "Invalid", "Changed", "Expired", "Renewed", "Unknown" }; if (!httpCopyCredentials(http, &creds)) { cups_array_t *lcreds; http_trust_t trust = httpCredentialsGetTrust(creds, hostname); httpCredentialsString(creds, info, sizeof(info)); printf("Count: %d\n", cupsArrayCount(creds)); printf("Trust: %s\n", trusts[trust]); printf("Expiration: %s\n", httpGetDateString(httpCredentialsGetExpiration(creds))); printf("IsValidName: %d\n", httpCredentialsAreValidForName(creds, hostname)); printf("String: \"%s\"\n", info); printf("LoadCredentials: %d\n", httpLoadCredentials(NULL, &lcreds, hostname)); httpCredentialsString(lcreds, info, sizeof(info)); printf(" Count: %d\n", cupsArrayCount(lcreds)); printf(" String: \"%s\"\n", info); if (lcreds && cupsArrayCount(creds) == cupsArrayCount(lcreds)) { http_credential_t *cred, *lcred; for (i = 1, cred = (http_credential_t *)cupsArrayFirst(creds), lcred = (http_credential_t *)cupsArrayFirst(lcreds); cred && lcred; i ++, cred = (http_credential_t *)cupsArrayNext(creds), lcred = (http_credential_t *)cupsArrayNext(lcreds)) { if (cred->datalen != lcred->datalen) printf(" Credential #%d: Different lengths (saved=%d, current=%d)\n", i, (int)cred->datalen, (int)lcred->datalen); else if (memcmp(cred->data, lcred->data, cred->datalen)) printf(" Credential #%d: Different data\n", i); else printf(" Credential #%d: Matches\n", i); } } if (trust != HTTP_TRUST_OK) { printf("SaveCredentials: %d\n", httpSaveCredentials(NULL, creds, hostname)); trust = httpCredentialsGetTrust(creds, hostname); printf("New Trust: %s\n", trusts[trust]); } httpFreeCredentials(creds); } else puts("No credentials!"); } printf("Checking file \"%s\"...\n", resource); do { if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) { httpClearFields(http); if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } } httpClearFields(http); httpSetField(http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString(http)); httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); if (httpHead(http, resource)) { if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } else { status = HTTP_STATUS_UNAUTHORIZED; continue; } } while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); if (status == HTTP_STATUS_UNAUTHORIZED) { /* * Flush any error message... */ httpFlush(http); /* * See if we can do authentication... */ if (cupsDoAuthentication(http, "GET", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; break; } if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } continue; } #ifdef HAVE_SSL else if (status == HTTP_STATUS_UPGRADE_REQUIRED) { /* Flush any error message... */ httpFlush(http); /* Reconnect... */ if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } /* Upgrade with encryption... */ httpEncryption(http, HTTP_ENCRYPTION_REQUIRED); /* Try again, this time with encryption enabled... */ continue; } #endif /* HAVE_SSL */ } while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED); if (status == HTTP_STATUS_OK) puts("HEAD OK:"); else printf("HEAD failed with status %d...\n", status); encoding = httpGetContentEncoding(http); printf("Requesting file \"%s\" (Accept-Encoding: %s)...\n", resource, encoding ? encoding : "identity"); do { if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) { httpClearFields(http); if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } } httpClearFields(http); httpSetField(http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString(http)); httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, encoding); if (httpGet(http, resource)) { if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } else { status = HTTP_STATUS_UNAUTHORIZED; continue; } } while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); if (status == HTTP_STATUS_UNAUTHORIZED) { /* * Flush any error message... */ httpFlush(http); /* * See if we can do authentication... */ if (cupsDoAuthentication(http, "GET", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; break; } if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } continue; } #ifdef HAVE_SSL else if (status == HTTP_STATUS_UPGRADE_REQUIRED) { /* Flush any error message... */ httpFlush(http); /* Reconnect... */ if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } /* Upgrade with encryption... */ httpEncryption(http, HTTP_ENCRYPTION_REQUIRED); /* Try again, this time with encryption enabled... */ continue; } #endif /* HAVE_SSL */ } while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED); if (status == HTTP_STATUS_OK) puts("GET OK:"); else printf("GET failed with status %d...\n", status); start = time(NULL); length = httpGetLength2(http); total = 0; while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) { total += bytes; fwrite(buffer, (size_t)bytes, 1, out); if (out != stdout) { current = time(NULL); if (current == start) current ++; printf("\r" CUPS_LLFMT "/" CUPS_LLFMT " bytes (" CUPS_LLFMT " bytes/sec) ", CUPS_LLCAST total, CUPS_LLCAST length, CUPS_LLCAST (total / (current - start))); fflush(stdout); } } } if (out != stdout) putchar('\n'); puts("Closing connection to server..."); httpClose(http); if (out != stdout) fclose(out); return (0); } ippsample/cups/array-private.h0000644000175000017500000000133413240604116015451 0ustar tilltill/* * Private array definitions for CUPS. * * Copyright 2011-2012 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_ARRAY_PRIVATE_H_ # define _CUPS_ARRAY_PRIVATE_H_ /* * Include necessary headers... */ # include /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Functions... */ extern int _cupsArrayAddStrings(cups_array_t *a, const char *s, char delim) _CUPS_API_1_5; extern cups_array_t *_cupsArrayNewStrings(const char *s, char delim) _CUPS_API_1_5; # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_ARRAY_PRIVATE_H_ */ ippsample/cups/Dependencies0000644000175000017500000002404613240604116015030 0ustar tilltillarray.o: array.c ../cups/cups.h file.h versioning.h ipp.h http.h array.h \ language.h pwg.h string-private.h ../config.h debug-private.h \ array-private.h auth.o: auth.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h debug.o: debug.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h dest.o: dest.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h dest-job.o: dest-job.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h dest-localization.o: dest-localization.c cups-private.h string-private.h \ ../config.h debug-private.h ../cups/versioning.h array-private.h \ ../cups/array.h ipp-private.h ../cups/cups.h file.h ipp.h http.h \ language.h pwg.h http-private.h language-private.h ../cups/transcode.h \ pwg-private.h thread-private.h dest-options.o: dest-options.c cups-private.h string-private.h \ ../config.h debug-private.h ../cups/versioning.h array-private.h \ ../cups/array.h ipp-private.h ../cups/cups.h file.h ipp.h http.h \ language.h pwg.h http-private.h language-private.h ../cups/transcode.h \ pwg-private.h thread-private.h dir.o: dir.c string-private.h ../config.h debug-private.h \ ../cups/versioning.h dir.h encode.o: encode.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h error.o: error.c ../cups/raster-private.h raster.h cups.h file.h \ versioning.h ipp.h http.h array.h language.h pwg.h \ ../cups/debug-private.h ../cups/string-private.h ../config.h file.o: file.c file-private.h cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h getputfile.o: getputfile.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h globals.o: globals.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h hash.o: hash.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h http.o: http.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h http-addr.o: http-addr.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h http-addrlist.o: http-addrlist.c cups-private.h string-private.h \ ../config.h debug-private.h ../cups/versioning.h array-private.h \ ../cups/array.h ipp-private.h ../cups/cups.h file.h ipp.h http.h \ language.h pwg.h http-private.h language-private.h ../cups/transcode.h \ pwg-private.h thread-private.h http-support.o: http-support.c cups-private.h string-private.h \ ../config.h debug-private.h ../cups/versioning.h array-private.h \ ../cups/array.h ipp-private.h ../cups/cups.h file.h ipp.h http.h \ language.h pwg.h http-private.h language-private.h ../cups/transcode.h \ pwg-private.h thread-private.h ipp.o: ipp.c cups-private.h string-private.h ../config.h debug-private.h \ ../cups/versioning.h array-private.h ../cups/array.h ipp-private.h \ ../cups/cups.h file.h ipp.h http.h language.h pwg.h http-private.h \ language-private.h ../cups/transcode.h pwg-private.h thread-private.h ipp-file.o: ipp-file.c ipp-private.h ../cups/cups.h file.h versioning.h \ ipp.h http.h array.h language.h pwg.h string-private.h ../config.h \ debug-private.h ipp-support.o: ipp-support.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h ipp-vars.o: ipp-vars.c ../cups/cups.h file.h versioning.h ipp.h http.h \ array.h language.h pwg.h ipp-private.h string-private.h ../config.h langprintf.o: langprintf.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h language.o: language.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h md5.o: md5.c md5-private.h string-private.h ../config.h md5passwd.o: md5passwd.c ../cups/cups.h file.h versioning.h ipp.h http.h \ array.h language.h pwg.h http-private.h ../config.h ipp-private.h \ string-private.h notify.o: notify.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h options.o: options.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h pwg-media.o: pwg-media.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h raster.o: raster.c ../cups/raster-private.h raster.h cups.h file.h \ versioning.h ipp.h http.h array.h language.h pwg.h \ ../cups/debug-private.h ../cups/string-private.h ../config.h request.o: request.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h snprintf.o: snprintf.c string-private.h ../config.h string.o: string.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h tempfile.o: tempfile.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h thread.o: thread.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h tls.o: tls.c cups-private.h string-private.h ../config.h debug-private.h \ ../cups/versioning.h array-private.h ../cups/array.h ipp-private.h \ ../cups/cups.h file.h ipp.h http.h language.h pwg.h http-private.h \ language-private.h ../cups/transcode.h pwg-private.h thread-private.h \ tls-darwin.c transcode.o: transcode.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h usersys.o: usersys.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h util.o: util.c cups-private.h string-private.h ../config.h \ debug-private.h ../cups/versioning.h array-private.h ../cups/array.h \ ipp-private.h ../cups/cups.h file.h ipp.h http.h language.h pwg.h \ http-private.h language-private.h ../cups/transcode.h pwg-private.h \ thread-private.h ippsample/cups/hash.c0000644000175000017500000001637413240604116013613 0ustar tilltill/* * Hashing function for CUPS. * * Copyright 2015-2017 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #ifdef __APPLE__ # include #elif defined(HAVE_GNUTLS) # include #else # include "md5-private.h" #endif /* __APPLE__ */ /* * 'cupsHashData()' - Perform a hash function on the given data. * * The "algorithm" argument can be any of the registered, non-deprecated IPP * hash algorithms for the "job-password-encryption" attribute, including * "sha" for SHA-1, "sha-256" for SHA2-256, etc. * * The "hash" argument points to a buffer of "hashsize" bytes and should be at * least 64 bytes in length for all of the supported algorithms. * * The returned hash is binary data. * * @since CUPS 2.2/macOS 10.12@ */ ssize_t /* O - Size of hash or -1 on error */ cupsHashData(const char *algorithm, /* I - Algorithm name */ const void *data, /* I - Data to hash */ size_t datalen, /* I - Length of data to hash */ unsigned char *hash, /* I - Hash buffer */ size_t hashsize) /* I - Size of hash buffer */ { if (!algorithm || !data || datalen == 0 || !hash || hashsize == 0) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad arguments to function"), 1); return (-1); } #ifdef __APPLE__ if (!strcmp(algorithm, "md5")) { /* * MD5 (deprecated but widely used...) */ CC_MD5_CTX ctx; /* MD5 context */ if (hashsize < CC_MD5_DIGEST_LENGTH) goto too_small; CC_MD5_Init(&ctx); CC_MD5_Update(&ctx, data, (CC_LONG)datalen); CC_MD5_Final(hash, &ctx); return (CC_MD5_DIGEST_LENGTH); } else if (!strcmp(algorithm, "sha")) { /* * SHA-1... */ CC_SHA1_CTX ctx; /* SHA-1 context */ if (hashsize < CC_SHA1_DIGEST_LENGTH) goto too_small; CC_SHA1_Init(&ctx); CC_SHA1_Update(&ctx, data, (CC_LONG)datalen); CC_SHA1_Final(hash, &ctx); return (CC_SHA1_DIGEST_LENGTH); } else if (!strcmp(algorithm, "sha2-224")) { CC_SHA256_CTX ctx; /* SHA-224 context */ if (hashsize < CC_SHA224_DIGEST_LENGTH) goto too_small; CC_SHA224_Init(&ctx); CC_SHA224_Update(&ctx, data, (CC_LONG)datalen); CC_SHA224_Final(hash, &ctx); return (CC_SHA224_DIGEST_LENGTH); } else if (!strcmp(algorithm, "sha2-256")) { CC_SHA256_CTX ctx; /* SHA-256 context */ if (hashsize < CC_SHA256_DIGEST_LENGTH) goto too_small; CC_SHA256_Init(&ctx); CC_SHA256_Update(&ctx, data, (CC_LONG)datalen); CC_SHA256_Final(hash, &ctx); return (CC_SHA256_DIGEST_LENGTH); } else if (!strcmp(algorithm, "sha2-384")) { CC_SHA512_CTX ctx; /* SHA-384 context */ if (hashsize < CC_SHA384_DIGEST_LENGTH) goto too_small; CC_SHA384_Init(&ctx); CC_SHA384_Update(&ctx, data, (CC_LONG)datalen); CC_SHA384_Final(hash, &ctx); return (CC_SHA384_DIGEST_LENGTH); } else if (!strcmp(algorithm, "sha2-512")) { CC_SHA512_CTX ctx; /* SHA-512 context */ if (hashsize < CC_SHA512_DIGEST_LENGTH) goto too_small; CC_SHA512_Init(&ctx); CC_SHA512_Update(&ctx, data, (CC_LONG)datalen); CC_SHA512_Final(hash, &ctx); return (CC_SHA512_DIGEST_LENGTH); } else if (!strcmp(algorithm, "sha2-512_224")) { CC_SHA512_CTX ctx; /* SHA-512 context */ unsigned char temp[CC_SHA512_DIGEST_LENGTH]; /* SHA-512 hash */ /* * SHA2-512 truncated to 224 bits (28 bytes)... */ if (hashsize < CC_SHA224_DIGEST_LENGTH) goto too_small; CC_SHA512_Init(&ctx); CC_SHA512_Update(&ctx, data, (CC_LONG)datalen); CC_SHA512_Final(temp, &ctx); memcpy(hash, temp, CC_SHA224_DIGEST_LENGTH); return (CC_SHA224_DIGEST_LENGTH); } else if (!strcmp(algorithm, "sha2-512_256")) { CC_SHA512_CTX ctx; /* SHA-512 context */ unsigned char temp[CC_SHA512_DIGEST_LENGTH]; /* SHA-512 hash */ /* * SHA2-512 truncated to 256 bits (32 bytes)... */ if (hashsize < CC_SHA256_DIGEST_LENGTH) goto too_small; CC_SHA512_Init(&ctx); CC_SHA512_Update(&ctx, data, (CC_LONG)datalen); CC_SHA512_Final(temp, &ctx); memcpy(hash, temp, CC_SHA256_DIGEST_LENGTH); return (CC_SHA256_DIGEST_LENGTH); } #elif defined(HAVE_GNUTLS) gnutls_digest_algorithm_t alg = GNUTLS_DIG_UNKNOWN; /* Algorithm */ unsigned char temp[64]; /* Temporary hash buffer */ size_t tempsize = 0; /* Truncate to this size? */ if (!strcmp(algorithm, "md5")) alg = GNUTLS_DIG_MD5; else if (!strcmp(algorithm, "sha")) alg = GNUTLS_DIG_SHA1; else if (!strcmp(algorithm, "sha2-224")) alg = GNUTLS_DIG_SHA224; else if (!strcmp(algorithm, "sha2-256")) alg = GNUTLS_DIG_SHA256; else if (!strcmp(algorithm, "sha2-384")) alg = GNUTLS_DIG_SHA384; else if (!strcmp(algorithm, "sha2-512")) alg = GNUTLS_DIG_SHA512; else if (!strcmp(algorithm, "sha2-512_224")) { alg = GNUTLS_DIG_SHA512; tempsize = 28; } else if (!strcmp(algorithm, "sha2-512_256")) { alg = GNUTLS_DIG_SHA512; tempsize = 32; } if (alg != GNUTLS_DIG_UNKNOWN) { if (tempsize > 0) { /* * Truncate result to tempsize bytes... */ if (hashsize < tempsize) goto too_small; gnutls_hash_fast(alg, data, datalen, temp); memcpy(hash, temp, tempsize); return ((ssize_t)tempsize); } if (hashsize < gnutls_hash_get_len(alg)) goto too_small; gnutls_hash_fast(alg, data, datalen, hash); return (gnutls_hash_get_len(alg)); } #else /* * No hash support beyond MD5 without CommonCrypto or GNU TLS... */ if (!strcmp(algorithm, "md5")) { _cups_md5_state_t state; /* MD5 state info */ _cupsMD5Init(&state); _cupsMD5Append(&state, data, datalen); _cupsMD5Finish(&state, hash); return (16); } else if (hashsize < 64) goto too_small; #endif /* __APPLE__ */ /* * Unknown hash algorithm... */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown hash algorithm."), 1); return (-1); /* * We get here if the buffer is too small. */ too_small: _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Hash buffer too small."), 1); return (-1); } /* * 'cupsHashString()' - Format a hash value as a hexadecimal string. * * The passed buffer must be at least 2 * hashsize + 1 characters in length. */ const char * /* O - Formatted string */ cupsHashString( const unsigned char *hash, /* I - Hash */ size_t hashsize, /* I - Size of hash */ char *buffer, /* I - String buffer */ size_t bufsize) /* I - Size of string buffer */ { char *bufptr = buffer; /* Pointer into buffer */ static const char *hex = "0123456789abcdef"; /* Hex characters (lowercase!) */ /* * Range check input... */ if (!hash || hashsize < 1 || !buffer || bufsize < (2 * hashsize + 1)) { if (buffer) *buffer = '\0'; return (NULL); } /* * Loop until we've converted the whole hash... */ while (hashsize > 0) { *bufptr++ = hex[*hash >> 4]; *bufptr++ = hex[*hash & 15]; hash ++; hashsize --; } *bufptr = '\0'; return (buffer); } ippsample/cups/language.h0000644000175000017500000000606313240604116014452 0ustar tilltill/* * Multi-language support for CUPS. * * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_LANGUAGE_H_ # define _CUPS_LANGUAGE_H_ /* * Include necessary headers... */ # include # include "array.h" # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Types... */ typedef enum cups_encoding_e /**** Language Encodings @exclude all@ ****/ { CUPS_AUTO_ENCODING = -1, /* Auto-detect the encoding @private@ */ CUPS_US_ASCII, /* US ASCII */ CUPS_ISO8859_1, /* ISO-8859-1 */ CUPS_ISO8859_2, /* ISO-8859-2 */ CUPS_ISO8859_3, /* ISO-8859-3 */ CUPS_ISO8859_4, /* ISO-8859-4 */ CUPS_ISO8859_5, /* ISO-8859-5 */ CUPS_ISO8859_6, /* ISO-8859-6 */ CUPS_ISO8859_7, /* ISO-8859-7 */ CUPS_ISO8859_8, /* ISO-8859-8 */ CUPS_ISO8859_9, /* ISO-8859-9 */ CUPS_ISO8859_10, /* ISO-8859-10 */ CUPS_UTF8, /* UTF-8 */ CUPS_ISO8859_13, /* ISO-8859-13 */ CUPS_ISO8859_14, /* ISO-8859-14 */ CUPS_ISO8859_15, /* ISO-8859-15 */ CUPS_WINDOWS_874, /* CP-874 */ CUPS_WINDOWS_1250, /* CP-1250 */ CUPS_WINDOWS_1251, /* CP-1251 */ CUPS_WINDOWS_1252, /* CP-1252 */ CUPS_WINDOWS_1253, /* CP-1253 */ CUPS_WINDOWS_1254, /* CP-1254 */ CUPS_WINDOWS_1255, /* CP-1255 */ CUPS_WINDOWS_1256, /* CP-1256 */ CUPS_WINDOWS_1257, /* CP-1257 */ CUPS_WINDOWS_1258, /* CP-1258 */ CUPS_KOI8_R, /* KOI-8-R */ CUPS_KOI8_U, /* KOI-8-U */ CUPS_ISO8859_11, /* ISO-8859-11 */ CUPS_ISO8859_16, /* ISO-8859-16 */ CUPS_MAC_ROMAN, /* MacRoman */ CUPS_ENCODING_SBCS_END = 63, /* End of single-byte encodings @private@ */ CUPS_WINDOWS_932, /* Japanese JIS X0208-1990 */ CUPS_WINDOWS_936, /* Simplified Chinese GB 2312-80 */ CUPS_WINDOWS_949, /* Korean KS C5601-1992 */ CUPS_WINDOWS_950, /* Traditional Chinese Big Five */ CUPS_WINDOWS_1361, /* Korean Johab */ CUPS_ENCODING_DBCS_END = 127, /* End of double-byte encodings @private@ */ CUPS_EUC_CN, /* EUC Simplified Chinese */ CUPS_EUC_JP, /* EUC Japanese */ CUPS_EUC_KR, /* EUC Korean */ CUPS_EUC_TW, /* EUC Traditional Chinese */ CUPS_JIS_X0213, /* JIS X0213 aka Shift JIS */ CUPS_ENCODING_VBCS_END = 191 /* End of variable-length encodings @private@ */ } cups_encoding_t; typedef struct cups_lang_s /**** Language Cache Structure ****/ { struct cups_lang_s *next; /* Next language in cache */ int used; /* Number of times this entry has been used. */ cups_encoding_t encoding; /* Text encoding */ char language[16]; /* Language/locale name */ cups_array_t *strings; /* Message strings @private@ */ } cups_lang_t; /* * Prototypes... */ extern cups_lang_t *cupsLangDefault(void); extern const char *cupsLangEncoding(cups_lang_t *lang); extern void cupsLangFlush(void); extern void cupsLangFree(cups_lang_t *lang); extern cups_lang_t *cupsLangGet(const char *language); # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_LANGUAGE_H_ */ ippsample/cups/api.intro0000644000175000017500000010406313240604116014343 0ustar tilltill

Overview

The IPP Sample project provides APIs for IPP client and server applications in the "cups" library. Most library functions are accessed by including the <cups/cups.h> header, while the raster functions are found in the <cups/raster.h> header.

Compiling Programs

The library can be used from any C, C++, or Objective C program. The method of compiling against the library varies depending on the operating system and installation of the IPP Sample project.

The following simple program lists the available printers on the network:

#include <stdio.h>
#include <cups/cups.h>

int main(void)
{
  int i;
  cups_dest_t *dests, *dest;
  int num_dests = cupsGetDests(&dests);

  for (i = num_dests, dest = dests; i > 0; i --, dest ++)
  {
    if (dest->instance)
      printf("%s/%s\n", dest->name, dest->instance);
    else
      puts(dest->name);
  }

  return (0);
}

CUPS API

The CUPS API provides the convenience functions needed to support applications, filters, printer drivers, and backends that need to interface with the CUPS scheduler.

Clients and Servers

CUPS is based on the Internet Printing Protocol ("IPP"), which allows clients (applications) to communicate with a server (the scheduler) to get a list of printers, send print jobs, and so forth. You identify which server you want to communicate with using a pointer to the opaque structure http_t. All of the examples in this document use the CUPS_HTTP_DEFAULT constant, referring to the default connection to the scheduler. The HTTP and IPP APIs document provides more information on server connections.

Printers and Classes

Printers and classes (collections of printers) are accessed through the cups_dest_t structure which includes the name (name), instance (instance - a way of selecting certain saved options/settings), and the options and attributes associated with that destination (num_options and options). Destinations are created using the cupsGetDests function and freed using the cupsFreeDests function. The cupsGetDest function finds a specific destination for printing:

#include <cups/cups.h>

cups_dest_t *dests;
int num_dests = cupsGetDests(&dests);
cups_dest_t *dest = cupsGetDest("name", NULL, num_dests, dests);

/* do something with dest */

cupsFreeDests(num_dests, dests);

Passing NULL to cupsGetDest for the destination name will return the default destination. Similarly, passing a NULL instance will return the default instance for that destination.

Table 1: Printer Attributes
Attribute Name Description
"auth-info-required" The type of authentication required for printing to this destination: "none", "username,password", "domain,username,password", or "negotiate" (Kerberos)
"printer-info" The human-readable description of the destination such as "My Laser Printer".
"printer-is-accepting-jobs" "true" if the destination is accepting new jobs, "false" if not.
"printer-is-shared" "true" if the destination is being shared with other computers, "false" if not.
"printer-location" The human-readable location of the destination such as "Lab 4".
"printer-make-and-model" The human-readable make and model of the destination such as "HP LaserJet 4000 Series".
"printer-state" "3" if the destination is idle, "4" if the destination is printing a job, and "5" if the destination is stopped.
"printer-state-change-time" The UNIX time when the destination entered the current state.
"printer-state-reasons" Additional comma-delimited state keywords for the destination such as "media-tray-empty-error" and "toner-low-warning".
"printer-type" The cups_printer_t value associated with the destination.

Options

Options are stored in arrays of cups_option_t structures. Each option has a name (name) and value (value) associated with it. The cups_dest_t num_options and options members contain the default options for a particular destination, along with several informational attributes about the destination as shown in Table 1. The cupsGetOption function gets the value for the named option. For example, the following code lists the available destinations and their human-readable descriptions:

#include <cups/cups.h>

cups_dest_t *dests;
int num_dests = cupsGetDests(&dests);
cups_dest_t *dest;
int i;
const char *value;

for (i = num_dests, dest = dests; i > 0; i --, dest ++)
  if (dest->instance == NULL)
  {
    value = cupsGetOption("printer-info", dest->num_options, dest->options);
    printf("%s (%s)\n", dest->name, value ? value : "no description");
  }

cupsFreeDests(num_dests, dests);

You can create your own option arrays using the cupsAddOption function, which adds a single named option to an array:

#include <cups/cups.h>

int num_options = 0;
cups_option_t *options = NULL;

/* The returned num_options value is updated as needed */
num_options = cupsAddOption("first", "value", num_options, &options);

/* This adds a second option value */
num_options = cupsAddOption("second", "value", num_options, &options);

/* This replaces the first option we added */
num_options = cupsAddOption("first", "new value", num_options, &options);

Use a for loop to copy the options from a destination:

#include <cups/cups.h>

int i;
int num_options = 0;
cups_option_t *options = NULL;
cups_dest_t *dest;

for (i = 0; i < dest->num_options; i ++)
  num_options = cupsAddOption(dest->options[i].name, dest->options[i].value,
                              num_options, &options);

Use the cupsFreeOptions function to free the options array when you are done using it:

cupsFreeOptions(num_options, options);

Print Jobs

Print jobs are identified by a locally-unique job ID number from 1 to 231-1 and have options and one or more files for printing to a single destination. The cupsPrintFile function creates a new job with one file. The following code prints the CUPS test page file:

#include <cups/cups.h>

cups_dest_t *dest;
int num_options;
cups_option_t *options;
int job_id;

/* Print a single file */
job_id = cupsPrintFile(dest->name, "/usr/share/cups/data/testprint.ps",
                        "Test Print", num_options, options);

The cupsPrintFiles function creates a job with multiple files. The files are provided in a char * array:

#include <cups/cups.h>

cups_dest_t *dest;
int num_options;
cups_option_t *options;
int job_id;
char *files[3] = { "file1.pdf", "file2.pdf", "file3.pdf" };

/* Print three files */
job_id = cupsPrintFiles(dest->name, 3, files, "Test Print", num_options, options);

Finally, the cupsCreateJob function creates a new job with no files in it. Files are added using the cupsStartDocument, cupsWriteRequestData, and cupsFinishDocument functions. The following example creates a job with 10 text files for printing:

#include <cups/cups.h>

cups_dest_t *dest;
int num_options;
cups_option_t *options;
int job_id;
int i;
char buffer[1024];

/* Create the job */
job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, dest->name, "10 Text Files",
                       num_options, options);

/* If the job is created, add 10 files */
if (job_id > 0)
{
  for (i = 1; i <= 10; i ++)
  {
    snprintf(buffer, sizeof(buffer), "file%d.txt", i);

    cupsStartDocument(CUPS_HTTP_DEFAULT, dest->name, job_id, buffer,
                      CUPS_FORMAT_TEXT, i == 10);

    snprintf(buffer, sizeof(buffer),
             "File %d\n"
             "\n"
             "One fish,\n"
             "Two fish,\n
             "Red fish,\n
             "Blue fish\n", i);

    /* cupsWriteRequestData can be called as many times as needed */
    cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, strlen(buffer));

    cupsFinishDocument(CUPS_HTTP_DEFAULT, dest->name);
  }
}

Once you have created a job, you can monitor its status using the cupsGetJobs function, which returns an array of cups_job_t structures. Each contains the job ID (id), destination name (dest), title (title), and other information associated with the job. The job array is freed using the cupsFreeJobs function. The following example monitors a specific job ID, showing the current job state once every 5 seconds until the job is completed:

#include <cups/cups.h>

cups_dest_t *dest;
int job_id;
int num_jobs;
cups_job_t *jobs;
int i;
ipp_jstate_t job_state = IPP_JOB_PENDING;

while (job_state < IPP_JOB_STOPPED)
{
  /* Get my jobs (1) with any state (-1) */
  num_jobs = cupsGetJobs(&jobs, dest->name, 1, -1);

  /* Loop to find my job */
  job_state = IPP_JOB_COMPLETED;

  for (i = 0; i < num_jobs; i ++)
    if (jobs[i].id == job_id)
    {
      job_state = jobs[i].state;
      break;
    }

  /* Free the job array */
  cupsFreeJobs(num_jobs, jobs);

  /* Show the current state */
  switch (job_state)
  {
    case IPP_JOB_PENDING :
        printf("Job %d is pending.\n", job_id);
        break;
    case IPP_JOB_HELD :
        printf("Job %d is held.\n", job_id);
        break;
    case IPP_JOB_PROCESSING :
        printf("Job %d is processing.\n", job_id);
        break;
    case IPP_JOB_STOPPED :
        printf("Job %d is stopped.\n", job_id);
        break;
    case IPP_JOB_CANCELED :
        printf("Job %d is canceled.\n", job_id);
        break;
    case IPP_JOB_ABORTED :
        printf("Job %d is aborted.\n", job_id);
        break;
    case IPP_JOB_COMPLETED :
        printf("Job %d is completed.\n", job_id);
        break;
  }

  /* Sleep if the job is not finished */
  if (job_state < IPP_JOB_STOPPED)
    sleep(5);
}

To cancel a job, use the cupsCancelJob function with the job ID:

#include <cups/cups.h>

cups_dest_t *dest;
int job_id;

cupsCancelJob(dest->name, job_id);

Error Handling

If any of the CUPS API printing functions returns an error, the reason for that error can be found by calling the cupsLastError and cupsLastErrorString functions. cupsLastError returns the last IPP error code (ipp_status_t) that was encountered, while cupsLastErrorString returns a (localized) human-readable string that can be shown to the user. For example, if any of the job creation functions returns a job ID of 0, you can use cupsLastErrorString to show the reason why the job could not be created:

#include <cups/cups.h>

int job_id;

if (job_id == 0)
  puts(cupsLastErrorString());

Passwords and Authentication

CUPS supports authentication of any request, including submission of print jobs. The default mechanism for getting the username and password is to use the login user and a password from the console.

To support other types of applications, in particular Graphical User Interfaces ("GUIs"), the CUPS API provides functions to set the default username and to register a callback function that returns a password string.

The cupsSetPasswordCB function is used to set a password callback in your program. Only one function can be used at any time.

The cupsSetUser function sets the current username for authentication. This function can be called by your password callback function to change the current username as needed.

The following example shows a simple password callback that gets a username and password from the user:

#include <cups/cups.h>

const char *
my_password_cb(const char *prompt)
{
  char	user[65];


  puts(prompt);

  /* Get a username from the user */
  printf("Username: ");
  if (fgets(user, sizeof(user), stdin) == NULL)
    return (NULL);

  /* Strip the newline from the string and set the user */
  user[strlen(user) - 1] = '\0';

  cupsSetUser(user);

  /* Use getpass() to ask for the password... */
  return (getpass("Password: "));
}

cupsSetPasswordCB(my_password_cb);

Similarly, a GUI could display the prompt string in a window with input fields for the username and password. The username should default to the string returned by the cupsUser function.

HTTP and IPP APIs

The CUPS HTTP and IPP APIs provide low-level access to the HTTP and IPP protocols and CUPS scheduler. They are typically used by monitoring and administration programs to perform specific functions not supported by the high-level CUPS API functions.

The HTTP APIs use an opaque structure called http_t to manage connections to a particular HTTP or IPP server. The httpConnectEncrypt function is used to create an instance of this structure for a particular server. The constant CUPS_HTTP_DEFAULT can be used with all of the cups functions to refer to the default CUPS server - the functions create a per-thread http_t as needed.

The IPP APIs use two opaque structures for requests (messages sent to the CUPS scheduler) and responses (messages sent back to your application from the scheduler). The ipp_t type holds a complete request or response and is allocated using the ippNew or ippNewRequest functions and freed using the ippDelete function.

The second opaque structure is called ipp_attribute_t and holds a single IPP attribute which consists of a group tag (ippGetGroupTag), a value type tag (ippGetValueTag), the attribute name (ippGetName), and 1 or more values (ippGetCount, ippGetBoolean, ippGetCollection, ippGetDate, ippGetInteger, ippGetRange, ippGetResolution, and ippGetString). Attributes are added to an ipp_t pointer using one of the ippAdd functions. For example, use ippAddString to add the "printer-uri" and "requesting-user-name" string attributes to a request:

ipp_t *request = ippNewRequest(IPP_GET_JOBS);

ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
             NULL, "ipp://localhost/printers/");
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
             NULL, cupsUser());

Once you have created an IPP request, use the cups functions to send the request to and read the response from the server. For example, the cupsDoRequest function can be used for simple query operations that do not involve files:

#include <cups/cups.h>


ipp_t *get_jobs(void)
{
  ipp_t *request = ippNewRequest(IPP_GET_JOBS);

  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
               NULL, "ipp://localhost/printers/");
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
               NULL, cupsUser());

  return (cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/"));
}

The cupsDoRequest function frees the request and returns an IPP response or NULL pointer if the request could not be sent to the server. Once you have a response from the server, you can either use the ippFindAttribute and ippFindNextAttribute functions to find specific attributes, for example:

ipp_t *response;
ipp_attribute_t *attr;

attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM);

You can also walk the list of attributes with a simple for loop like this:

ipp_t *response;
ipp_attribute_t *attr;

for (attr = ippFirstAttribute(response); attr != NULL; attr = ippNextAttribute(response))
  if (ippGetName(attr) == NULL)
    puts("--SEPARATOR--");
  else
    puts(ippGetName(attr));

The for loop approach is normally used when collecting attributes for multiple objects (jobs, printers, etc.) in a response. Attributes with NULL names indicate a separator between the attributes of each object. For example, the following code will list the jobs returned from our previous get_jobs example code:

ipp_t *response = get_jobs();

if (response != NULL)
{
  ipp_attribute_t *attr;
  const char *attrname;
  int job_id = 0;
  const char *job_name = NULL;
  const char *job_originating_user_name = NULL;

  puts("Job ID  Owner             Title");
  puts("------  ----------------  ---------------------------------");

  for (attr = ippFirstAttribute(response); attr != NULL; attr = ippNextAttribute(response))
  {
   /* Attributes without names are separators between jobs */
    attrname = ippGetName(attr);
    if (attrname == NULL)
    {
      if (job_id > 0)
      {
        if (job_name == NULL)
          job_name = "(withheld)";

        if (job_originating_user_name == NULL)
          job_originating_user_name = "(withheld)";

        printf("%5d  %-16s  %s\n", job_id, job_originating_user_name, job_name);
      }

      job_id = 0;
      job_name = NULL;
      job_originating_user_name = NULL;
      continue;
    }
    else if (!strcmp(attrname, "job-id") && ippGetValueTag(attr) == IPP_TAG_INTEGER)
      job_id = ippGetInteger(attr, 0);
    else if (!strcmp(attrname, "job-name") && ippGetValueTag(attr) == IPP_TAG_NAME)
      job_name = ippGetString(attr, 0, NULL);
    else if (!strcmp(attrname, "job-originating-user-name") &&
             ippGetValueTag(attr) == IPP_TAG_NAME)
      job_originating_user_name = ippGetString(attr, 0, NULL);
  }

  if (job_id > 0)
  {
    if (job_name == NULL)
      job_name = "(withheld)";

    if (job_originating_user_name == NULL)
      job_originating_user_name = "(withheld)";

    printf("%5d  %-16s  %s\n", job_id, job_originating_user_name, job_name);
  }
}

Creating URI Strings

To ensure proper encoding, the httpAssembleURIf function must be used to format a "printer-uri" string for all printer-based requests:

const char *name = "Foo";
char uri[1024];
ipp_t *request;

httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, cupsServer(),
                 ippPort(), "/printers/%s", name);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);

Sending Requests with Files

The cupsDoFileRequest and cupsDoIORequest functions are used for requests involving files. The cupsDoFileRequest function attaches the named file to a request and is typically used when sending a print file or changing a printer's PPD file:

const char *filename = "/usr/share/cups/data/testprint.ps";
const char *name = "Foo";
char uri[1024];
char resource[1024];
ipp_t *request = ippNewRequest(IPP_PRINT_JOB);
ipp_t *response;

/* Use httpAssembleURIf for the printer-uri string */
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, cupsServer(),
                 ippPort(), "/printers/%s", name);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
             NULL, cupsUser());
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
             NULL, "testprint.ps");

/* Use snprintf for the resource path */
snprintf(resource, sizeof(resource), "/printers/%s", name);

response = cupsDoFileRequest(CUPS_HTTP_DEFAULT, request, resource, filename);

The cupsDoIORequest function optionally attaches a file to the request and optionally saves a file in the response from the server. It is used when using a pipe for the request attachment or when using a request that returns a file, currently only CUPS_GET_DOCUMENT and CUPS_GET_PPD. For example, the following code will download the PPD file for the sample HP LaserJet printer driver:

char tempfile[1024];
int tempfd;
ipp_t *request = ippNewRequest(CUPS_GET_PPD);
ipp_t *response;

ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name",
             NULL, "laserjet.ppd");

tempfd = cupsTempFd(tempfile, sizeof(tempfile));

response = cupsDoIORequest(CUPS_HTTP_DEFAULT, request, "/", -1, tempfd);

The example passes -1 for the input file descriptor to specify that no file is to be attached to the request. The PPD file attached to the response is written to the temporary file descriptor we created using the cupsTempFd function.

Asynchronous Request Processing

The cupsSendRequest and cupsGetResponse support asynchronous communications with the server. Unlike the other request functions, the IPP request is not automatically freed, so remember to free your request with the ippDelete function.

File data is attached to the request using the cupsWriteRequestData function, while file data returned from the server is read using the cupsReadResponseData function. We can rewrite the previous CUPS_GET_PPD example to use the asynchronous functions quite easily:

char tempfile[1024];
int tempfd;
ipp_t *request = ippNewRequest(CUPS_GET_PPD);
ipp_t *response;

ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name",
             NULL, "laserjet.ppd");

tempfd = cupsTempFd(tempfile, sizeof(tempfile));

if (cupsSendRequest(CUPS_HTTP_DEFAULT, request, "/") == HTTP_CONTINUE)
{
  response = cupsGetResponse(CUPS_HTTP_DEFAULT, "/");

  if (response != NULL)
  {
    ssize_t bytes;
    char buffer[8192];

    while ((bytes = cupsReadResponseData(CUPS_HTTP_DEFAULT, buffer, sizeof(buffer))) > 0)
      write(tempfd, buffer, bytes);
  }
}

/* Free the request! */
ippDelete(request);

The cupsSendRequest function returns the initial HTTP request status, typically either HTTP_CONTINUE or HTTP_UNAUTHORIZED. The latter status is returned when the request requires authentication of some sort. The cupsDoAuthentication function must be called when your see HTTP_UNAUTHORIZED and the request re-sent. We can add authentication support to our example code by using a do ... while loop:

char tempfile[1024];
int tempfd;
ipp_t *request = ippNewRequest(CUPS_GET_PPD);
ipp_t *response;
http_status_t status;

ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name",
             NULL, "laserjet.ppd");

tempfd = cupsTempFd(tempfile, sizeof(tempfile));

/* Loop for authentication */
do
{
  status = cupsSendRequest(CUPS_HTTP_DEFAULT, request, "/");

  if (status == HTTP_UNAUTHORIZED)
  {
    /* Try to authenticate, break out of the loop if that fails */
    if (cupsDoAuthentication(CUPS_HTTP_DEFAULT, "POST", "/"))
      break;
  }
}
while (status != HTTP_CONTINUE && status != HTTP_UNAUTHORIZED);

if (status == HTTP_CONTINUE)
{
  response = cupsGetResponse(CUPS_HTTP_DEFAULT, "/");

  if (response != NULL)
  {
    ssize_t bytes;
    char buffer[8192];

    while ((bytes = cupsReadResponseData(CUPS_HTTP_DEFAULT, buffer, sizeof(buffer))) > 0)
      write(tempfd, buffer, bytes);
  }
}

/* Free the request! */
ippDelete(request);

Raster API

The CUPS raster API provides a standard interface for reading and writing CUPS raster streams which are used for printing to raster printers. Because the raster format is updated from time to time, it is important to use this API to avoid incompatibilities with newer versions of CUPS.

Two kinds of CUPS filters use the CUPS raster API - raster image processor (RIP) filters such as pstoraster and cgpdftoraster (macOS) that produce CUPS raster files and printer driver filters that convert CUPS raster files into a format usable by the printer. Printer driver filters are by far the most common.

CUPS raster files (application/vnd.cups-raster) consists of a stream of raster page descriptions produced by one of the RIP filters such as pstoraster, imagetoraster, or cgpdftoraster. CUPS raster files are referred to using the cups_raster_t type and are opened using the cupsRasterOpen function. For example, to read raster data from the standard input, open file descriptor 0:

#include <cups/raster.h>>

cups_raster_t *ras = cupsRasterOpen(0, CUPS_RASTER_READ);

Each page of data begins with a page dictionary structure called cups_page_header2_t. This structure contains the colorspace, bits per color, media size, media type, hardware resolution, and so forth used for the page.

You read the page header using the cupsRasterReadHeader2 function:

#include <cups/raster.h>>

cups_raster_t *ras = cupsRasterOpen(0, CUPS_RASTER_READ);
cups_page_header2_t header;

while (cupsRasterReadHeader2(ras, &header))
{
  /* setup this page */

  /* read raster data */

  /* finish this page */
}

After the page dictionary comes the page data which is a full-resolution, possibly compressed bitmap representing the page in the printer's output colorspace. You read uncompressed raster data using the cupsRasterReadPixels function. A for loop is normally used to read the page one line at a time:

#include <cups/raster.h>>

cups_raster_t *ras = cupsRasterOpen(0, CUPS_RASTER_READ);
cups_page_header2_t header;
int page = 0;
int y;
char *buffer;

while (cupsRasterReadHeader2(ras, &header))
{
  /* setup this page */
  page ++;
  fprintf(stderr, "PAGE: %d %d\n", page, header.NumCopies);

  /* allocate memory for 1 line */
  buffer = malloc(header.cupsBytesPerLine);

  /* read raster data */
  for (y = 0; y < header.cupsHeight; y ++)
  {
    if (cupsRasterReadPixels(ras, buffer, header.cupsBytesPerLine) == 0)
      break;

    /* write raster data to printer on stdout */
  }

  /* finish this page */
}

When you are done reading the raster data, call the cupsRasterClose function to free the memory used to read the raster file:

cups_raster_t *ras;

cupsRasterClose(ras);
ippsample/cups/array.h0000644000175000017500000000521613240604116014004 0ustar tilltill/* * Sorted array definitions for CUPS. * * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_ARRAY_H_ # define _CUPS_ARRAY_H_ /* * Include necessary headers... */ # include "versioning.h" # include /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Types and structures... */ typedef struct _cups_array_s cups_array_t; /**** CUPS array type ****/ typedef int (*cups_array_func_t)(void *first, void *second, void *data); /**** Array comparison function ****/ typedef int (*cups_ahash_func_t)(void *element, void *data); /**** Array hash function ****/ typedef void *(*cups_acopy_func_t)(void *element, void *data); /**** Array element copy function ****/ typedef void (*cups_afree_func_t)(void *element, void *data); /**** Array element free function ****/ /* * Functions... */ extern int cupsArrayAdd(cups_array_t *a, void *e) _CUPS_API_1_2; extern void cupsArrayClear(cups_array_t *a) _CUPS_API_1_2; extern int cupsArrayCount(cups_array_t *a) _CUPS_API_1_2; extern void *cupsArrayCurrent(cups_array_t *a) _CUPS_API_1_2; extern void cupsArrayDelete(cups_array_t *a) _CUPS_API_1_2; extern cups_array_t *cupsArrayDup(cups_array_t *a) _CUPS_API_1_2; extern void *cupsArrayFind(cups_array_t *a, void *e) _CUPS_API_1_2; extern void *cupsArrayFirst(cups_array_t *a) _CUPS_API_1_2; extern int cupsArrayGetIndex(cups_array_t *a) _CUPS_API_1_3; extern int cupsArrayGetInsert(cups_array_t *a) _CUPS_API_1_3; extern void *cupsArrayIndex(cups_array_t *a, int n) _CUPS_API_1_2; extern int cupsArrayInsert(cups_array_t *a, void *e) _CUPS_API_1_2; extern void *cupsArrayLast(cups_array_t *a) _CUPS_API_1_2; extern cups_array_t *cupsArrayNew(cups_array_func_t f, void *d) _CUPS_API_1_2; extern cups_array_t *cupsArrayNew2(cups_array_func_t f, void *d, cups_ahash_func_t h, int hsize) _CUPS_API_1_3; extern cups_array_t *cupsArrayNew3(cups_array_func_t f, void *d, cups_ahash_func_t h, int hsize, cups_acopy_func_t cf, cups_afree_func_t ff) _CUPS_API_1_5; extern void *cupsArrayNext(cups_array_t *a) _CUPS_API_1_2; extern void *cupsArrayPrev(cups_array_t *a) _CUPS_API_1_2; extern int cupsArrayRemove(cups_array_t *a, void *e) _CUPS_API_1_2; extern void *cupsArrayRestore(cups_array_t *a) _CUPS_API_1_2; extern int cupsArraySave(cups_array_t *a) _CUPS_API_1_2; extern void *cupsArrayUserData(cups_array_t *a) _CUPS_API_1_2; # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_ARRAY_H_ */ ippsample/cups/pwg.h0000644000175000017500000000403413240604116013460 0ustar tilltill/* * PWG media API definitions for CUPS. * * Copyright 2009-2017 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_PWG_H_ # define _CUPS_PWG_H_ /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Macros... */ /* Convert from points to hundredths of millimeters */ # define PWG_FROM_POINTS(n) (int)(((n) * 2540 + 36) / 72) /* Convert from hundredths of millimeters to points */ # define PWG_TO_POINTS(n) ((n) * 72.0 / 2540.0) /* * Types and structures... */ typedef struct pwg_map_s /**** Map element - PPD to/from PWG @exclude all@ */ { char *pwg, /* PWG media keyword */ *ppd; /* PPD option keyword */ } pwg_map_t; typedef struct pwg_media_s /**** Common media size data ****/ { const char *pwg, /* PWG 5101.1 "self describing" name */ *legacy, /* IPP/ISO legacy name */ *ppd; /* Standard Adobe PPD name */ int width, /* Width in 2540ths */ length; /* Length in 2540ths */ } pwg_media_t; typedef struct pwg_size_s /**** Size element - PPD to/from PWG @exclude all@ */ { pwg_map_t map; /* Map element */ int width, /* Width in 2540ths */ length, /* Length in 2540ths */ left, /* Left margin in 2540ths */ bottom, /* Bottom margin in 2540ths */ right, /* Right margin in 2540ths */ top; /* Top margin in 2540ths */ } pwg_size_t; /* * Functions... */ extern int pwgFormatSizeName(char *keyword, size_t keysize, const char *prefix, const char *name, int width, int length, const char *units) _CUPS_API_1_7; extern int pwgInitSize(pwg_size_t *size, ipp_t *job, int *margins_set) _CUPS_API_1_7; extern pwg_media_t *pwgMediaForLegacy(const char *legacy) _CUPS_API_1_7; extern pwg_media_t *pwgMediaForPPD(const char *ppd) _CUPS_API_1_7; extern pwg_media_t *pwgMediaForPWG(const char *pwg) _CUPS_API_1_7; extern pwg_media_t *pwgMediaForSize(int width, int length) _CUPS_API_1_7; # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_PWG_H_ */ ippsample/cups/getputfile.c0000644000175000017500000002363413240604116015035 0ustar tilltill/* * Get/put file functions for CUPS. * * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #include #include #if defined(WIN32) || defined(__EMX__) # include #else # include #endif /* WIN32 || __EMX__ */ /* * 'cupsGetFd()' - Get a file from the server. * * This function returns @code HTTP_STATUS_OK@ when the file is successfully retrieved. * * @since CUPS 1.1.20/macOS 10.4@ */ http_status_t /* O - HTTP status */ cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *resource, /* I - Resource name */ int fd) /* I - File descriptor */ { ssize_t bytes; /* Number of bytes read */ char buffer[8192]; /* Buffer for file */ http_status_t status; /* HTTP status from server */ char if_modified_since[HTTP_MAX_VALUE]; /* If-Modified-Since header */ /* * Range check input... */ DEBUG_printf(("cupsGetFd(http=%p, resource=\"%s\", fd=%d)", (void *)http, resource, fd)); if (!resource || fd < 0) { if (http) http->error = EINVAL; return (HTTP_STATUS_ERROR); } if (!http) if ((http = _cupsConnect()) == NULL) return (HTTP_STATUS_SERVICE_UNAVAILABLE); /* * Then send GET requests to the HTTP server... */ strlcpy(if_modified_since, httpGetField(http, HTTP_FIELD_IF_MODIFIED_SINCE), sizeof(if_modified_since)); do { if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) { httpClearFields(http); if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } } httpClearFields(http); httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE, if_modified_since); if (httpGet(http, resource)) { if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } else { status = HTTP_STATUS_UNAUTHORIZED; continue; } } while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); if (status == HTTP_STATUS_UNAUTHORIZED) { /* * Flush any error message... */ httpFlush(http); /* * See if we can do authentication... */ if (cupsDoAuthentication(http, "GET", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; break; } if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } continue; } #ifdef HAVE_SSL else if (status == HTTP_STATUS_UPGRADE_REQUIRED) { /* Flush any error message... */ httpFlush(http); /* Reconnect... */ if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } /* Upgrade with encryption... */ httpEncryption(http, HTTP_ENCRYPTION_REQUIRED); /* Try again, this time with encryption enabled... */ continue; } #endif /* HAVE_SSL */ } while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED); /* * See if we actually got the file or an error... */ if (status == HTTP_STATUS_OK) { /* * Yes, copy the file... */ while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) write(fd, buffer, (size_t)bytes); } else { _cupsSetHTTPError(status); httpFlush(http); } /* * Return the request status... */ DEBUG_printf(("1cupsGetFd: Returning %d...", status)); return (status); } /* * 'cupsGetFile()' - Get a file from the server. * * This function returns @code HTTP_STATUS_OK@ when the file is successfully retrieved. * * @since CUPS 1.1.20/macOS 10.4@ */ http_status_t /* O - HTTP status */ cupsGetFile(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *resource, /* I - Resource name */ const char *filename) /* I - Filename */ { int fd; /* File descriptor */ http_status_t status; /* Status */ /* * Range check input... */ if (!http || !resource || !filename) { if (http) http->error = EINVAL; return (HTTP_STATUS_ERROR); } /* * Create the file... */ if ((fd = open(filename, O_WRONLY | O_EXCL | O_TRUNC)) < 0) { /* * Couldn't open the file! */ http->error = errno; return (HTTP_STATUS_ERROR); } /* * Get the file... */ status = cupsGetFd(http, resource, fd); /* * If the file couldn't be gotten, then remove the file... */ close(fd); if (status != HTTP_STATUS_OK) unlink(filename); /* * Return the HTTP status code... */ return (status); } /* * 'cupsPutFd()' - Put a file on the server. * * This function returns @code HTTP_STATUS_CREATED@ when the file is stored * successfully. * * @since CUPS 1.1.20/macOS 10.4@ */ http_status_t /* O - HTTP status */ cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *resource, /* I - Resource name */ int fd) /* I - File descriptor */ { ssize_t bytes; /* Number of bytes read */ int retries; /* Number of retries */ char buffer[8192]; /* Buffer for file */ http_status_t status; /* HTTP status from server */ /* * Range check input... */ DEBUG_printf(("cupsPutFd(http=%p, resource=\"%s\", fd=%d)", (void *)http, resource, fd)); if (!resource || fd < 0) { if (http) http->error = EINVAL; return (HTTP_STATUS_ERROR); } if (!http) if ((http = _cupsConnect()) == NULL) return (HTTP_STATUS_SERVICE_UNAVAILABLE); /* * Then send PUT requests to the HTTP server... */ retries = 0; do { if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) { httpClearFields(http); if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } } DEBUG_printf(("2cupsPutFd: starting attempt, authstring=\"%s\"...", http->authstring)); httpClearFields(http); httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked"); httpSetExpect(http, HTTP_STATUS_CONTINUE); if (httpPut(http, resource)) { if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } else { status = HTTP_STATUS_UNAUTHORIZED; continue; } } /* * Wait up to 1 second for a 100-continue response... */ if (httpWait(http, 1000)) status = httpUpdate(http); else status = HTTP_STATUS_CONTINUE; if (status == HTTP_STATUS_CONTINUE) { /* * Copy the file... */ lseek(fd, 0, SEEK_SET); while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) if (httpCheck(http)) { if ((status = httpUpdate(http)) != HTTP_STATUS_CONTINUE) break; } else httpWrite2(http, buffer, (size_t)bytes); } if (status == HTTP_STATUS_CONTINUE) { httpWrite2(http, buffer, 0); while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); } if (status == HTTP_STATUS_ERROR && !retries) { DEBUG_printf(("2cupsPutFd: retry on status %d", status)); retries ++; /* Flush any error message... */ httpFlush(http); /* Reconnect... */ if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } /* Try again... */ continue; } DEBUG_printf(("2cupsPutFd: status=%d", status)); if (status == HTTP_STATUS_UNAUTHORIZED) { /* * Flush any error message... */ httpFlush(http); /* * See if we can do authentication... */ if (cupsDoAuthentication(http, "PUT", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; break; } if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } continue; } #ifdef HAVE_SSL else if (status == HTTP_STATUS_UPGRADE_REQUIRED) { /* Flush any error message... */ httpFlush(http); /* Reconnect... */ if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } /* Upgrade with encryption... */ httpEncryption(http, HTTP_ENCRYPTION_REQUIRED); /* Try again, this time with encryption enabled... */ continue; } #endif /* HAVE_SSL */ } while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED || (status == HTTP_STATUS_ERROR && retries < 2)); /* * See if we actually put the file or an error... */ if (status != HTTP_STATUS_CREATED) { _cupsSetHTTPError(status); httpFlush(http); } DEBUG_printf(("1cupsPutFd: Returning %d...", status)); return (status); } /* * 'cupsPutFile()' - Put a file on the server. * * This function returns @code HTTP_CREATED@ when the file is stored * successfully. * * @since CUPS 1.1.20/macOS 10.4@ */ http_status_t /* O - HTTP status */ cupsPutFile(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *resource, /* I - Resource name */ const char *filename) /* I - Filename */ { int fd; /* File descriptor */ http_status_t status; /* Status */ /* * Range check input... */ if (!http || !resource || !filename) { if (http) http->error = EINVAL; return (HTTP_STATUS_ERROR); } /* * Open the local file... */ if ((fd = open(filename, O_RDONLY)) < 0) { /* * Couldn't open the file! */ http->error = errno; return (HTTP_STATUS_ERROR); } /* * Put the file... */ status = cupsPutFd(http, resource, fd); close(fd); return (status); } ippsample/cups/ipp-file.c0000644000175000017500000003755013240604116014374 0ustar tilltill/* * IPP data file parsing functions. * * Copyright © 2007-2018 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ /* * Include necessary headers... */ #include "ipp-private.h" #include "string-private.h" #include "debug-private.h" /* * Local functions... */ static ipp_t *parse_collection(_ipp_file_t *f, _ipp_vars_t *v, void *user_data); static int parse_value(_ipp_file_t *f, _ipp_vars_t *v, void *user_data, ipp_t *ipp, ipp_attribute_t **attr, int element); static void report_error(_ipp_file_t *f, _ipp_vars_t *v, void *user_data, const char *message, ...) __attribute((__format__ (__printf__, 4, 5))); /* * '_ippFileParse()' - Parse an IPP data file. */ ipp_t * /* O - IPP attributes or @code NULL@ on failure */ _ippFileParse( _ipp_vars_t *v, /* I - Variables */ const char *filename, /* I - Name of file to parse */ void *user_data) /* I - User data pointer */ { _ipp_file_t f; /* IPP data file information */ ipp_t *attrs = NULL; /* Active IPP message */ ipp_attribute_t *attr = NULL; /* Current attribute */ char token[1024]; /* Token string */ ipp_t *ignored = NULL; /* Ignored attributes */ DEBUG_printf(("_ippFileParse(v=%p, filename=\"%s\", user_data=%p)", (void *)v, filename, user_data)); /* * Initialize file info... */ memset(&f, 0, sizeof(f)); f.filename = filename; f.linenum = 1; if ((f.fp = cupsFileOpen(filename, "r")) == NULL) { DEBUG_printf(("1_ippFileParse: Unable to open \"%s\": %s", filename, strerror(errno))); return (0); } /* * Do the callback with a NULL token to setup any initial state... */ (*v->tokencb)(&f, v, user_data, NULL); /* * Read data file, using the callback function as needed... */ while (_ippFileReadToken(&f, token, sizeof(token))) { if (!_cups_strcasecmp(token, "DEFINE") || !_cups_strcasecmp(token, "DEFINE-DEFAULT")) { char name[128], /* Variable name */ value[1024], /* Variable value */ temp[1024]; /* Temporary string */ attr = NULL; if (_ippFileReadToken(&f, name, sizeof(name)) && _ippFileReadToken(&f, temp, sizeof(temp))) { _ippVarsExpand(v, value, temp, sizeof(value)); _ippVarsSet(v, name, value); } else { report_error(&f, v, user_data, "Missing %s name and/or value on line %d of \"%s\".", token, f.linenum, f.filename); break; } } else if (f.attrs && !_cups_strcasecmp(token, "ATTR")) { /* * Attribute definition... */ char syntax[128], /* Attribute syntax (value tag) */ name[128]; /* Attribute name */ ipp_tag_t value_tag; /* Value tag */ attr = NULL; if (!_ippFileReadToken(&f, syntax, sizeof(syntax))) { report_error(&f, v, user_data, "Missing ATTR syntax on line %d of \"%s\".", f.linenum, f.filename); break; } else if ((value_tag = ippTagValue(syntax)) < IPP_TAG_UNSUPPORTED_VALUE) { report_error(&f, v, user_data, "Bad ATTR syntax \"%s\" on line %d of \"%s\".", syntax, f.linenum, f.filename); break; } if (!_ippFileReadToken(&f, name, sizeof(name)) || !name[0]) { report_error(&f, v, user_data, "Missing ATTR name on line %d of \"%s\".", f.linenum, f.filename); break; } if (!v->attrcb || (*v->attrcb)(&f, user_data, name)) { /* * Add this attribute... */ attrs = f.attrs; } else { /* * Ignore this attribute... */ if (!ignored) ignored = ippNew(); attrs = ignored; } if (value_tag < IPP_TAG_INTEGER) { /* * Add out-of-band attribute - no value string needed... */ ippAddOutOfBand(attrs, f.group_tag, value_tag, name); } else { /* * Add attribute with one or more values... */ attr = ippAddString(attrs, f.group_tag, value_tag, name, NULL, NULL); if (!parse_value(&f, v, user_data, attrs, &attr, 0)) break; } } else if (attr && !_cups_strcasecmp(token, ",")) { /* * Additional value... */ if (!parse_value(&f, v, user_data, attrs, &attr, ippGetCount(attr))) break; } else { /* * Something else... */ attr = NULL; attrs = NULL; if (!(*v->tokencb)(&f, v, user_data, token)) break; } } /* * Close the file and free ignored attributes, then return any attributes we * kept... */ cupsFileClose(f.fp); ippDelete(ignored); return (f.attrs); } /* * '_ippFileReadToken()' - Read a token from an IPP data file. */ int /* O - 1 on success, 0 on failure */ _ippFileReadToken(_ipp_file_t *f, /* I - File to read from */ char *token, /* I - Token string buffer */ size_t tokensize)/* I - Size of token string buffer */ { int ch, /* Character from file */ quote = 0; /* Quoting character */ char *tokptr = token, /* Pointer into token buffer */ *tokend = token + tokensize - 1;/* End of token buffer */ /* * Skip whitespace and comments... */ while ((ch = cupsFileGetChar(f->fp)) != EOF) { if (_cups_isspace(ch)) { /* * Whitespace... */ if (ch == '\n') f->linenum ++; } else if (ch == '#') { /* * Comment... */ while ((ch = cupsFileGetChar(f->fp)) != EOF) { if (ch == '\n') break; } if (ch == '\n') f->linenum ++; else break; } else break; } if (ch == EOF) { DEBUG_puts("1_ippFileReadToken: EOF"); return (0); } /* * Read a token... */ while (ch != EOF) { if (ch == '\n') f->linenum ++; if (ch == quote) { /* * End of quoted text... */ *tokptr = '\0'; DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token)); return (1); } else if (!quote && _cups_isspace(ch)) { /* * End of unquoted text... */ *tokptr = '\0'; DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token)); return (1); } else if (!quote && (ch == '\'' || ch == '\"')) { /* * Start of quoted text or regular expression... */ quote = ch; } else if (!quote && ch == '#') { /* * Start of comment... */ cupsFileSeek(f->fp, cupsFileTell(f->fp) - 1); *tokptr = '\0'; DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token)); return (1); } else if (!quote && (ch == '{' || ch == '}' || ch == ',')) { /* * Delimiter... */ if (tokptr > token) { /* * Return the preceding token first... */ cupsFileSeek(f->fp, cupsFileTell(f->fp) - 1); } else { /* * Return this delimiter by itself... */ *tokptr++ = (char)ch; } *tokptr = '\0'; DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token)); return (1); } else { if (ch == '\\') { /* * Quoted character... */ if ((ch = cupsFileGetChar(f->fp)) == EOF) { *token = '\0'; DEBUG_puts("1_ippFileReadToken: EOF"); return (0); } else if (ch == '\n') f->linenum ++; } if (tokptr < tokend) { /* * Add to current token... */ *tokptr++ = (char)ch; } else { /* * Token too long... */ *tokptr = '\0'; DEBUG_printf(("1_ippFileReadToken: Too long: \"%s\".", token)); return (0); } } /* * Get the next character... */ ch = cupsFileGetChar(f->fp); } *tokptr = '\0'; DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token)); return (tokptr > token); } /* * 'parse_collection()' - Parse an IPP collection value. */ static ipp_t * /* O - Collection value or @code NULL@ on error */ parse_collection( _ipp_file_t *f, /* I - IPP data file */ _ipp_vars_t *v, /* I - IPP variables */ void *user_data) /* I - User data pointer */ { ipp_t *col = ippNew(); /* Collection value */ ipp_attribute_t *attr = NULL; /* Current member attribute */ char token[1024]; /* Token string */ /* * Parse the collection value... */ while (_ippFileReadToken(f, token, sizeof(token))) { if (!_cups_strcasecmp(token, "}")) { /* * End of collection value... */ break; } else if (!_cups_strcasecmp(token, "MEMBER")) { /* * Member attribute definition... */ char syntax[128], /* Attribute syntax (value tag) */ name[128]; /* Attribute name */ ipp_tag_t value_tag; /* Value tag */ attr = NULL; if (!_ippFileReadToken(f, syntax, sizeof(syntax))) { report_error(f, v, user_data, "Missing ATTR syntax on line %d of \"%s\".", f->linenum, f->filename); ippDelete(col); col = NULL; break; } else if ((value_tag = ippTagValue(syntax)) < IPP_TAG_UNSUPPORTED_VALUE) { report_error(f, v, user_data, "Bad ATTR syntax \"%s\" on line %d of \"%s\".", syntax, f->linenum, f->filename); ippDelete(col); col = NULL; break; } if (!_ippFileReadToken(f, name, sizeof(name)) || !name[0]) { report_error(f, v, user_data, "Missing ATTR name on line %d of \"%s\".", f->linenum, f->filename); ippDelete(col); col = NULL; break; } if (value_tag < IPP_TAG_INTEGER) { /* * Add out-of-band attribute - no value string needed... */ ippAddOutOfBand(col, IPP_TAG_ZERO, value_tag, name); } else { /* * Add attribute with one or more values... */ attr = ippAddString(col, IPP_TAG_ZERO, value_tag, name, NULL, NULL); if (!parse_value(f, v, user_data, col, &attr, 0)) { ippDelete(col); col = NULL; break; } } } else if (attr && !_cups_strcasecmp(token, ",")) { /* * Additional value... */ if (!parse_value(f, v, user_data, col, &attr, ippGetCount(attr))) { ippDelete(col); col = NULL; break; } } else { /* * Something else... */ report_error(f, v, user_data, "Unknown directive \"%s\" on line %d of \"%s\".", token, f->linenum, f->filename); ippDelete(col); col = NULL; attr = NULL; break; } } return (col); } /* * 'parse_value()' - Parse an IPP value. */ static int /* O - 1 on success or 0 on error */ parse_value(_ipp_file_t *f, /* I - IPP data file */ _ipp_vars_t *v, /* I - IPP variables */ void *user_data,/* I - User data pointer */ ipp_t *ipp, /* I - IPP message */ ipp_attribute_t **attr, /* IO - IPP attribute */ int element) /* I - Element number */ { char value[1024], /* Value string */ temp[1024]; /* Temporary string */ if (!_ippFileReadToken(f, temp, sizeof(temp))) { report_error(f, v, user_data, "Missing value on line %d of \"%s\".", f->linenum, f->filename); return (0); } _ippVarsExpand(v, value, temp, sizeof(value)); switch (ippGetValueTag(*attr)) { case IPP_TAG_BOOLEAN : return (ippSetBoolean(ipp, attr, element, !_cups_strcasecmp(value, "true"))); break; case IPP_TAG_ENUM : case IPP_TAG_INTEGER : return (ippSetInteger(ipp, attr, element, (int)strtol(value, NULL, 0))); break; case IPP_TAG_DATE : { int year, /* Year */ month, /* Month */ day, /* Day of month */ hour, /* Hour */ minute, /* Minute */ second, /* Second */ utc_offset = 0; /* Timezone offset from UTC */ ipp_uchar_t date[11]; /* dateTime value */ if (sscanf(value, "%d-%d-%dT%d:%d:%d%d", &year, &month, &day, &hour, &minute, &second, &utc_offset) < 6) { report_error(f, v, user_data, "Bad dateTime value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename); return (0); } date[0] = (ipp_uchar_t)(year >> 8); date[1] = (ipp_uchar_t)(year & 255); date[2] = (ipp_uchar_t)month; date[3] = (ipp_uchar_t)day; date[4] = (ipp_uchar_t)hour; date[5] = (ipp_uchar_t)minute; date[6] = (ipp_uchar_t)second; date[7] = 0; if (utc_offset < 0) { utc_offset = -utc_offset; date[8] = (ipp_uchar_t)'-'; } else { date[8] = (ipp_uchar_t)'+'; } date[9] = (ipp_uchar_t)(utc_offset / 100); date[10] = (ipp_uchar_t)(utc_offset % 100); return (ippSetDate(ipp, attr, element, date)); } break; case IPP_TAG_RESOLUTION : { int xres, /* X resolution */ yres; /* Y resolution */ char *ptr; /* Pointer into value */ xres = yres = (int)strtol(value, (char **)&ptr, 10); if (ptr > value && xres > 0) { if (*ptr == 'x') yres = (int)strtol(ptr + 1, (char **)&ptr, 10); } if (ptr <= value || xres <= 0 || yres <= 0 || !ptr || (_cups_strcasecmp(ptr, "dpi") && _cups_strcasecmp(ptr, "dpc") && _cups_strcasecmp(ptr, "dpcm") && _cups_strcasecmp(ptr, "other"))) { report_error(f, v, user_data, "Bad resolution value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename); return (0); } if (!_cups_strcasecmp(ptr, "dpi")) return (ippSetResolution(ipp, attr, element, IPP_RES_PER_INCH, xres, yres)); else if (!_cups_strcasecmp(ptr, "dpc") || !_cups_strcasecmp(ptr, "dpcm")) return (ippSetResolution(ipp, attr, element, IPP_RES_PER_CM, xres, yres)); else return (ippSetResolution(ipp, attr, element, (ipp_res_t)0, xres, yres)); } break; case IPP_TAG_RANGE : { int lower, /* Lower value */ upper; /* Upper value */ if (sscanf(value, "%d-%d", &lower, &upper) != 2) { report_error(f, v, user_data, "Bad rangeOfInteger value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename); return (0); } return (ippSetRange(ipp, attr, element, lower, upper)); } break; case IPP_TAG_STRING : return (ippSetOctetString(ipp, attr, element, value, (int)strlen(value))); break; case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : return (ippSetString(ipp, attr, element, value)); break; case IPP_TAG_BEGIN_COLLECTION : { int status; /* Add status */ ipp_t *col; /* Collection value */ if (strcmp(value, "{")) { report_error(f, v, user_data, "Bad ATTR collection value on line %d of \"%s\".", f->linenum, f->filename); return (0); } if ((col = parse_collection(f, v, user_data)) == NULL) return (0); status = ippSetCollection(ipp, attr, element, col); ippDelete(col); return (status); } break; default : report_error(f, v, user_data, "Unsupported ATTR value on line %d of \"%s\".", f->linenum, f->filename); return (0); } return (1); } /* * 'report_error()' - Report an error. */ static void report_error( _ipp_file_t *f, /* I - IPP data file */ _ipp_vars_t *v, /* I - Error callback function, if any */ void *user_data, /* I - User data pointer */ const char *message, /* I - Printf-style message */ ...) /* I - Additional arguments as needed */ { char buffer[8192]; /* Formatted string */ va_list ap; /* Argument pointer */ va_start(ap, message); vsnprintf(buffer, sizeof(buffer), message, ap); va_end(ap); if (v->errorcb) (*v->errorcb)(f, user_data, buffer); else fprintf(stderr, "%s\n", buffer); } ippsample/cups/thread-private.h0000644000175000017500000000631513240604116015606 0ustar tilltill/* * Private threading definitions for CUPS. * * Copyright 2009-2017 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_THREAD_PRIVATE_H_ # define _CUPS_THREAD_PRIVATE_H_ /* * Include necessary headers... */ # include "config.h" /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ # ifdef HAVE_PTHREAD_H /* POSIX threading */ # include typedef void *(*_cups_thread_func_t)(void *arg); typedef pthread_t _cups_thread_t; typedef pthread_cond_t _cups_cond_t; typedef pthread_mutex_t _cups_mutex_t; typedef pthread_rwlock_t _cups_rwlock_t; typedef pthread_key_t _cups_threadkey_t; # define _CUPS_COND_INITIALIZER PTHREAD_COND_INITIALIZER # define _CUPS_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER # define _CUPS_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER # define _CUPS_THREADKEY_INITIALIZER 0 # define _cupsThreadGetData(k) pthread_getspecific(k) # define _cupsThreadSetData(k,p) pthread_setspecific(k,p) # elif defined(WIN32) /* Windows threading */ # include # include typedef void *(__stdcall *_cups_thread_func_t)(void *arg); typedef int _cups_thread_t; typedef char _cups_cond_t; /* TODO: Implement Win32 conditional */ typedef struct _cups_mutex_s { int m_init; /* Flag for on-demand initialization */ CRITICAL_SECTION m_criticalSection; /* Win32 Critical Section */ } _cups_mutex_t; typedef _cups_mutex_t _cups_rwlock_t; /* TODO: Implement Win32 reader/writer lock */ typedef DWORD _cups_threadkey_t; # define _CUPS_COND_INITIALIZER 0 # define _CUPS_MUTEX_INITIALIZER { 0, 0 } # define _CUPS_RWLOCK_INITIALIZER { 0, 0 } # define _CUPS_THREADKEY_INITIALIZER 0 # define _cupsThreadGetData(k) TlsGetValue(k) # define _cupsThreadSetData(k,p) TlsSetValue(k,p) # else /* No threading */ typedef void *(*_cups_thread_func_t)(void *arg); typedef int _cups_thread_t; typedef char _cups_cond_t; typedef char _cups_mutex_t; typedef char _cups_rwlock_t; typedef void *_cups_threadkey_t; # define _CUPS_COND_INITIALIZER 0 # define _CUPS_MUTEX_INITIALIZER 0 # define _CUPS_RWLOCK_INITIALIZER 0 # define _CUPS_THREADKEY_INITIALIZER (void *)0 # define _cupsThreadGetData(k) k # define _cupsThreadSetData(k,p) k=p # endif /* HAVE_PTHREAD_H */ /* * Functions... */ extern void _cupsCondBroadcast(_cups_cond_t *cond); extern void _cupsCondInit(_cups_cond_t *cond); extern void _cupsCondWait(_cups_cond_t *cond, _cups_mutex_t *mutex, double timeout); extern void _cupsMutexInit(_cups_mutex_t *mutex); extern void _cupsMutexLock(_cups_mutex_t *mutex); extern void _cupsMutexUnlock(_cups_mutex_t *mutex); extern void _cupsRWInit(_cups_rwlock_t *rwlock); extern void _cupsRWLockRead(_cups_rwlock_t *rwlock); extern void _cupsRWLockWrite(_cups_rwlock_t *rwlock); extern void _cupsRWUnlock(_cups_rwlock_t *rwlock); extern void _cupsThreadCancel(_cups_thread_t thread); extern _cups_thread_t _cupsThreadCreate(_cups_thread_func_t func, void *arg); extern void _cupsThreadDetach(_cups_thread_t thread); extern void *_cupsThreadWait(_cups_thread_t thread); # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_THREAD_PRIVATE_H_ */ ippsample/cups/string.c0000644000175000017500000003511113240604116014164 0ustar tilltill/* * String functions for CUPS. * * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #define _CUPS_STRING_C_ #include "cups-private.h" #include #include /* * Local globals... */ static _cups_mutex_t sp_mutex = _CUPS_MUTEX_INITIALIZER; /* Mutex to control access to pool */ static cups_array_t *stringpool = NULL; /* Global string pool */ /* * Local functions... */ static int compare_sp_items(_cups_sp_item_t *a, _cups_sp_item_t *b); /* * '_cupsStrAlloc()' - Allocate/reference a string. */ char * /* O - String pointer */ _cupsStrAlloc(const char *s) /* I - String */ { size_t slen; /* Length of string */ _cups_sp_item_t *item, /* String pool item */ *key; /* Search key */ /* * Range check input... */ if (!s) return (NULL); /* * Get the string pool... */ _cupsMutexLock(&sp_mutex); if (!stringpool) stringpool = cupsArrayNew((cups_array_func_t)compare_sp_items, NULL); if (!stringpool) { _cupsMutexUnlock(&sp_mutex); return (NULL); } /* * See if the string is already in the pool... */ key = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str)); if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, key)) != NULL) { /* * Found it, return the cached string... */ item->ref_count ++; #ifdef DEBUG_GUARDS DEBUG_printf(("5_cupsStrAlloc: Using string %p(%s) for \"%s\", guard=%08x, " "ref_count=%d", item, item->str, s, item->guard, item->ref_count)); if (item->guard != _CUPS_STR_GUARD) abort(); #endif /* DEBUG_GUARDS */ _cupsMutexUnlock(&sp_mutex); return (item->str); } /* * Not found, so allocate a new one... */ slen = strlen(s); item = (_cups_sp_item_t *)calloc(1, sizeof(_cups_sp_item_t) + slen); if (!item) { _cupsMutexUnlock(&sp_mutex); return (NULL); } item->ref_count = 1; memcpy(item->str, s, slen + 1); #ifdef DEBUG_GUARDS item->guard = _CUPS_STR_GUARD; DEBUG_printf(("5_cupsStrAlloc: Created string %p(%s) for \"%s\", guard=%08x, " "ref_count=%d", item, item->str, s, item->guard, item->ref_count)); #endif /* DEBUG_GUARDS */ /* * Add the string to the pool and return it... */ cupsArrayAdd(stringpool, item); _cupsMutexUnlock(&sp_mutex); return (item->str); } /* * '_cupsStrDate()' - Return a localized date for a given time value. * * This function works around the locale encoding issues of strftime... */ char * /* O - Buffer */ _cupsStrDate(char *buf, /* I - Buffer */ size_t bufsize, /* I - Size of buffer */ time_t timeval) /* I - Time value */ { struct tm *dateval; /* Local date/time */ char temp[1024]; /* Temporary buffer */ _cups_globals_t *cg = _cupsGlobals(); /* Per-thread globals */ if (!cg->lang_default) cg->lang_default = cupsLangDefault(); dateval = localtime(&timeval); if (cg->lang_default->encoding != CUPS_UTF8) { strftime(temp, sizeof(temp), "%c", dateval); cupsCharsetToUTF8((cups_utf8_t *)buf, temp, (int)bufsize, cg->lang_default->encoding); } else strftime(buf, bufsize, "%c", dateval); return (buf); } /* * '_cupsStrFlush()' - Flush the string pool. */ void _cupsStrFlush(void) { _cups_sp_item_t *item; /* Current item */ DEBUG_printf(("4_cupsStrFlush: %d strings in array", cupsArrayCount(stringpool))); _cupsMutexLock(&sp_mutex); for (item = (_cups_sp_item_t *)cupsArrayFirst(stringpool); item; item = (_cups_sp_item_t *)cupsArrayNext(stringpool)) free(item); cupsArrayDelete(stringpool); stringpool = NULL; _cupsMutexUnlock(&sp_mutex); } /* * '_cupsStrFormatd()' - Format a floating-point number. */ char * /* O - Pointer to end of string */ _cupsStrFormatd(char *buf, /* I - String */ char *bufend, /* I - End of string buffer */ double number, /* I - Number to format */ struct lconv *loc) /* I - Locale data */ { char *bufptr, /* Pointer into buffer */ temp[1024], /* Temporary string */ *tempdec, /* Pointer to decimal point */ *tempptr; /* Pointer into temporary string */ const char *dec; /* Decimal point */ int declen; /* Length of decimal point */ /* * Format the number using the "%.12f" format and then eliminate * unnecessary trailing 0's. */ snprintf(temp, sizeof(temp), "%.12f", number); for (tempptr = temp + strlen(temp) - 1; tempptr > temp && *tempptr == '0'; *tempptr-- = '\0'); /* * Next, find the decimal point... */ if (loc && loc->decimal_point) { dec = loc->decimal_point; declen = (int)strlen(dec); } else { dec = "."; declen = 1; } if (declen == 1) tempdec = strchr(temp, *dec); else tempdec = strstr(temp, dec); /* * Copy everything up to the decimal point... */ if (tempdec) { for (tempptr = temp, bufptr = buf; tempptr < tempdec && bufptr < bufend; *bufptr++ = *tempptr++); tempptr += declen; if (*tempptr && bufptr < bufend) { *bufptr++ = '.'; while (*tempptr && bufptr < bufend) *bufptr++ = *tempptr++; } *bufptr = '\0'; } else { strlcpy(buf, temp, (size_t)(bufend - buf + 1)); bufptr = buf + strlen(buf); } return (bufptr); } /* * '_cupsStrFree()' - Free/dereference a string. */ void _cupsStrFree(const char *s) /* I - String to free */ { _cups_sp_item_t *item, /* String pool item */ *key; /* Search key */ /* * Range check input... */ if (!s) return; /* * Check the string pool... * * We don't need to lock the mutex yet, as we only want to know if * the stringpool is initialized. The rest of the code will still * work if it is initialized before we lock... */ if (!stringpool) return; /* * See if the string is already in the pool... */ _cupsMutexLock(&sp_mutex); key = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str)); #ifdef DEBUG_GUARDS if (key->guard != _CUPS_STR_GUARD) { DEBUG_printf(("5_cupsStrFree: Freeing string %p(%s), guard=%08x, " "ref_count=%d", key, key->str, key->guard, key->ref_count)); abort(); } #endif /* DEBUG_GUARDS */ if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, key)) != NULL && item == key) { /* * Found it, dereference... */ item->ref_count --; if (!item->ref_count) { /* * Remove and free... */ cupsArrayRemove(stringpool, item); free(item); } } _cupsMutexUnlock(&sp_mutex); } /* * '_cupsStrRetain()' - Increment the reference count of a string. * * Note: This function does not verify that the passed pointer is in the * string pool, so any calls to it MUST know they are passing in a * good pointer. */ char * /* O - Pointer to string */ _cupsStrRetain(const char *s) /* I - String to retain */ { _cups_sp_item_t *item; /* Pointer to string pool item */ if (s) { item = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str)); #ifdef DEBUG_GUARDS if (item->guard != _CUPS_STR_GUARD) { DEBUG_printf(("5_cupsStrRetain: Retaining string %p(%s), guard=%08x, " "ref_count=%d", item, s, item->guard, item->ref_count)); abort(); } #endif /* DEBUG_GUARDS */ _cupsMutexLock(&sp_mutex); item->ref_count ++; _cupsMutexUnlock(&sp_mutex); } return ((char *)s); } /* * '_cupsStrScand()' - Scan a string for a floating-point number. * * This function handles the locale-specific BS so that a decimal * point is always the period (".")... */ double /* O - Number */ _cupsStrScand(const char *buf, /* I - Pointer to number */ char **bufptr, /* O - New pointer or NULL on error */ struct lconv *loc) /* I - Locale data */ { char temp[1024], /* Temporary buffer */ *tempptr; /* Pointer into temporary buffer */ /* * Range check input... */ if (!buf) return (0.0); /* * Skip leading whitespace... */ while (_cups_isspace(*buf)) buf ++; /* * Copy leading sign, numbers, period, and then numbers... */ tempptr = temp; if (*buf == '-' || *buf == '+') *tempptr++ = *buf++; while (isdigit(*buf & 255)) if (tempptr < (temp + sizeof(temp) - 1)) *tempptr++ = *buf++; else { if (bufptr) *bufptr = NULL; return (0.0); } if (*buf == '.') { /* * Read fractional portion of number... */ buf ++; if (loc && loc->decimal_point) { strlcpy(tempptr, loc->decimal_point, sizeof(temp) - (size_t)(tempptr - temp)); tempptr += strlen(tempptr); } else if (tempptr < (temp + sizeof(temp) - 1)) *tempptr++ = '.'; else { if (bufptr) *bufptr = NULL; return (0.0); } while (isdigit(*buf & 255)) if (tempptr < (temp + sizeof(temp) - 1)) *tempptr++ = *buf++; else { if (bufptr) *bufptr = NULL; return (0.0); } } if (*buf == 'e' || *buf == 'E') { /* * Read exponent... */ if (tempptr < (temp + sizeof(temp) - 1)) *tempptr++ = *buf++; else { if (bufptr) *bufptr = NULL; return (0.0); } if (*buf == '+' || *buf == '-') { if (tempptr < (temp + sizeof(temp) - 1)) *tempptr++ = *buf++; else { if (bufptr) *bufptr = NULL; return (0.0); } } while (isdigit(*buf & 255)) if (tempptr < (temp + sizeof(temp) - 1)) *tempptr++ = *buf++; else { if (bufptr) *bufptr = NULL; return (0.0); } } /* * Nul-terminate the temporary string and return the value... */ if (bufptr) *bufptr = (char *)buf; *tempptr = '\0'; return (strtod(temp, NULL)); } /* * '_cupsStrStatistics()' - Return allocation statistics for string pool. */ size_t /* O - Number of strings */ _cupsStrStatistics(size_t *alloc_bytes, /* O - Allocated bytes */ size_t *total_bytes) /* O - Total string bytes */ { size_t count, /* Number of strings */ abytes, /* Allocated string bytes */ tbytes, /* Total string bytes */ len; /* Length of string */ _cups_sp_item_t *item; /* Current item */ /* * Loop through strings in pool, counting everything up... */ _cupsMutexLock(&sp_mutex); for (count = 0, abytes = 0, tbytes = 0, item = (_cups_sp_item_t *)cupsArrayFirst(stringpool); item; item = (_cups_sp_item_t *)cupsArrayNext(stringpool)) { /* * Count allocated memory, using a 64-bit aligned buffer as a basis. */ count += item->ref_count; len = (strlen(item->str) + 8) & (size_t)~7; abytes += sizeof(_cups_sp_item_t) + len; tbytes += item->ref_count * len; } _cupsMutexUnlock(&sp_mutex); /* * Return values... */ if (alloc_bytes) *alloc_bytes = abytes; if (total_bytes) *total_bytes = tbytes; return (count); } /* * '_cups_strcpy()' - Copy a string allowing for overlapping strings. */ void _cups_strcpy(char *dst, /* I - Destination string */ const char *src) /* I - Source string */ { while (*src) *dst++ = *src++; *dst = '\0'; } /* * '_cups_strdup()' - Duplicate a string. */ #ifndef HAVE_STRDUP char * /* O - New string pointer */ _cups_strdup(const char *s) /* I - String to duplicate */ { char *t; /* New string pointer */ size_t slen; /* Length of string */ if (!s) return (NULL); slen = strlen(s); if ((t = malloc(slen + 1)) == NULL) return (NULL); return (memcpy(t, s, slen + 1)); } #endif /* !HAVE_STRDUP */ /* * '_cups_strcasecmp()' - Do a case-insensitive comparison. */ int /* O - Result of comparison (-1, 0, or 1) */ _cups_strcasecmp(const char *s, /* I - First string */ const char *t) /* I - Second string */ { while (*s != '\0' && *t != '\0') { if (_cups_tolower(*s) < _cups_tolower(*t)) return (-1); else if (_cups_tolower(*s) > _cups_tolower(*t)) return (1); s ++; t ++; } if (*s == '\0' && *t == '\0') return (0); else if (*s != '\0') return (1); else return (-1); } /* * '_cups_strncasecmp()' - Do a case-insensitive comparison on up to N chars. */ int /* O - Result of comparison (-1, 0, or 1) */ _cups_strncasecmp(const char *s, /* I - First string */ const char *t, /* I - Second string */ size_t n) /* I - Maximum number of characters to compare */ { while (*s != '\0' && *t != '\0' && n > 0) { if (_cups_tolower(*s) < _cups_tolower(*t)) return (-1); else if (_cups_tolower(*s) > _cups_tolower(*t)) return (1); s ++; t ++; n --; } if (n == 0) return (0); else if (*s == '\0' && *t == '\0') return (0); else if (*s != '\0') return (1); else return (-1); } #ifndef HAVE_STRLCAT /* * '_cups_strlcat()' - Safely concatenate two strings. */ size_t /* O - Length of string */ _cups_strlcat(char *dst, /* O - Destination string */ const char *src, /* I - Source string */ size_t size) /* I - Size of destination string buffer */ { size_t srclen; /* Length of source string */ size_t dstlen; /* Length of destination string */ /* * Figure out how much room is left... */ dstlen = strlen(dst); if (size < (dstlen + 1)) return (dstlen); /* No room, return immediately... */ size -= dstlen + 1; /* * Figure out how much room is needed... */ srclen = strlen(src); /* * Copy the appropriate amount... */ if (srclen > size) srclen = size; memmove(dst + dstlen, src, srclen); dst[dstlen + srclen] = '\0'; return (dstlen + srclen); } #endif /* !HAVE_STRLCAT */ #ifndef HAVE_STRLCPY /* * '_cups_strlcpy()' - Safely copy two strings. */ size_t /* O - Length of string */ _cups_strlcpy(char *dst, /* O - Destination string */ const char *src, /* I - Source string */ size_t size) /* I - Size of destination string buffer */ { size_t srclen; /* Length of source string */ /* * Figure out how much room is needed... */ size --; srclen = strlen(src); /* * Copy the appropriate amount... */ if (srclen > size) srclen = size; memmove(dst, src, srclen); dst[srclen] = '\0'; return (srclen); } #endif /* !HAVE_STRLCPY */ /* * 'compare_sp_items()' - Compare two string pool items... */ static int /* O - Result of comparison */ compare_sp_items(_cups_sp_item_t *a, /* I - First item */ _cups_sp_item_t *b) /* I - Second item */ { return (strcmp(a->str, b->str)); } ippsample/cups/testclient.c0000644000175000017500000006651013240604116015043 0ustar tilltill/* * Simulated client test program for CUPS. * * Copyright © 2017-2018 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ /* * Include necessary headers... */ #include #include #include #include #include #include /* * Local types... */ typedef struct _client_monitor_s { const char *uri, /* Printer URI */ *hostname, /* Hostname */ *user, /* Username */ *resource; /* Resource path */ int port; /* Port number */ http_encryption_t encryption; /* Use encryption? */ ipp_pstate_t printer_state; /* Current printer state */ char printer_state_reasons[1024]; /* Current printer-state-reasons */ int job_id; /* Job ID for submitted job */ ipp_jstate_t job_state; /* Current job state */ char job_state_reasons[1024]; /* Current job-state-reasons */ } _client_monitor_t; /* * Local functions... */ static const char *make_raster_file(ipp_t *response, int grayscale, char *tempname, size_t tempsize, const char **format); static void *monitor_printer(_client_monitor_t *monitor); static void show_attributes(const char *title, int request, ipp_t *ipp); static void show_capabilities(ipp_t *response); static void usage(void); /* * 'main()' - Main entry. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ const char *opt, /* Current option */ *uri = NULL, /* Printer URI */ *printfile = NULL, /* Print file */ *printformat = NULL; /* Print format */ int keepfile = 0, /* Keep temp file? */ grayscale = 0, /* Force grayscale? */ verbosity = 0; /* Verbosity */ char tempfile[1024] = "", /* Temporary file (if any) */ scheme[32], /* URI scheme */ userpass[256], /* Username:password */ hostname[256], /* Hostname */ resource[256]; /* Resource path */ int port; /* Port number */ http_encryption_t encryption; /* Encryption mode */ _client_monitor_t monitor; /* Monitoring data */ http_t *http; /* HTTP connection */ ipp_t *request, /* IPP request */ *response; /* IPP response */ ipp_attribute_t *attr; /* IPP attribute */ static const char * const pattrs[] = /* Printer attributes we are interested in */ { "job-template", "printer-defaults", "printer-description", "media-col-database", "media-col-ready" }; /* * Parse command-line options... */ if (argc == 1) return (0); for (i = 1; i < argc; i ++) { if (argv[i][0] == '-') { for (opt = argv[i] + 1; *opt; opt ++) { switch (*opt) { case 'd' : /* -d document-format */ if (printformat) { puts("Document format can only be specified once."); usage(); return (1); } i ++; if (i >= argc) { puts("Expected document format after '-d'."); usage(); return (1); } printformat = argv[i]; break; case 'f' : /* -f print-file */ if (printfile) { puts("Print file can only be specified once."); usage(); return (1); } i ++; if (i >= argc) { puts("Expected print file after '-f'."); usage(); return (1); } printfile = argv[i]; break; case 'g' : grayscale = 1; break; case 'k' : keepfile = 1; break; case 'v' : verbosity ++; break; default : printf("Unknown option '-%c'.\n", *opt); usage(); return (1); } } } else if (uri || (strncmp(argv[i], "ipp://", 6) && strncmp(argv[i], "ipps://", 7))) { printf("Unknown command-line argument '%s'.\n", argv[i]); usage(); return (1); } else uri = argv[i]; } /* * Make sure we have everything we need. */ if (!uri) { puts("Expected printer URI."); usage(); return (1); } /* * Connect to the printer... */ if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) { printf("Bad printer URI '%s'.\n", uri); return (1); } if (!port) port = IPP_PORT; if (!strcmp(scheme, "https") || !strcmp(scheme, "ipps")) encryption = HTTP_ENCRYPTION_ALWAYS; else encryption = HTTP_ENCRYPTION_IF_REQUESTED; if ((http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, 1, 0, NULL)) == NULL) { printf("Unable to connect to '%s' on port %d: %s\n", hostname, port, cupsLastErrorString()); return (1); } /* * Query printer status and capabilities... */ request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs); response = cupsDoRequest(http, request, resource); if (verbosity) show_capabilities(response); /* * Now figure out what we will be printing... */ if (printfile) { /* * User specified a print file, figure out the format... */ if ((opt = strrchr(printfile, '.')) != NULL) { /* * Guess the format from the extension... */ if (!strcmp(opt, ".jpg")) printformat = "image/jpeg"; else if (!strcmp(opt, ".pdf")) printformat = "application/pdf"; else if (!strcmp(opt, ".ps")) printformat = "application/postscript"; else if (!strcmp(opt, ".pwg")) printformat = "image/pwg-raster"; else if (!strcmp(opt, ".urf")) printformat = "image/urf"; else printformat = "application/octet-stream"; } else { /* * Tell the printer to auto-detect... */ printformat = "application/octet-stream"; } } else { /* * No file specified, make something to test with... */ if ((printfile = make_raster_file(response, grayscale, tempfile, sizeof(tempfile), &printformat)) == NULL) return (1); } ippDelete(response); /* * Start monitoring the printer in the background... */ memset(&monitor, 0, sizeof(monitor)); monitor.uri = uri; monitor.hostname = hostname; monitor.resource = resource; monitor.port = port; monitor.encryption = encryption; _cupsThreadCreate((_cups_thread_func_t)monitor_printer, &monitor); /* * Create the job and wait for completion... */ request = ippNewRequest(IPP_OP_CREATE_JOB); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); if ((opt = strrchr(printfile, '/')) != NULL) opt ++; else opt = printfile; ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, opt); if (verbosity) show_attributes("Create-Job request", 1, request); response = cupsDoRequest(http, request, resource); if (verbosity) show_attributes("Create-Job response", 0, response); if (cupsLastError() >= IPP_STATUS_REDIRECTION_OTHER_SITE) { printf("Unable to create print job: %s\n", cupsLastErrorString()); monitor.job_state = IPP_JSTATE_ABORTED; goto cleanup; } if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL) { puts("No job-id returned in Create-Job request."); monitor.job_state = IPP_JSTATE_ABORTED; goto cleanup; } monitor.job_id = ippGetInteger(attr, 0); printf("CREATED JOB %d, sending %s of type %s\n", monitor.job_id, printfile, printformat); ippDelete(response); request = ippNewRequest(IPP_OP_SEND_DOCUMENT); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", monitor.job_id); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, printformat); ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1); if (verbosity) show_attributes("Send-Document request", 1, request); response = cupsDoFileRequest(http, request, resource, printfile); if (verbosity) show_attributes("Send-Document response", 0, response); if (cupsLastError() >= IPP_STATUS_REDIRECTION_OTHER_SITE) { printf("Unable to print file: %s\n", cupsLastErrorString()); monitor.job_state = IPP_JSTATE_ABORTED; goto cleanup; } puts("WAITING FOR JOB TO COMPLETE"); while (monitor.job_state < IPP_JSTATE_CANCELED) sleep(1); /* * Cleanup after ourselves... */ cleanup: httpClose(http); if (tempfile[0] && !keepfile) unlink(tempfile); return (monitor.job_state == IPP_JSTATE_COMPLETED); } /* * 'make_raster_file()' - Create a temporary raster file. */ static const char * /* O - Print filename */ make_raster_file(ipp_t *response, /* I - Printer attributes */ int grayscale, /* I - Force grayscale? */ char *tempname, /* I - Temporary filename buffer */ size_t tempsize, /* I - Size of temp file buffer */ const char **format) /* O - Print format */ { int i, /* Looping var */ count; /* Number of values */ ipp_attribute_t *attr; /* Printer attribute */ const char *type = NULL; /* Raster type (colorspace + bits) */ pwg_media_t *media = NULL; /* Media size */ int xdpi = 0, /* Horizontal resolution */ ydpi = 0; /* Vertical resolution */ int fd; /* Temporary file */ cups_mode_t mode; /* Raster mode */ cups_raster_t *ras; /* Raster stream */ cups_page_header2_t header; /* Page header */ unsigned char *line, /* Line of raster data */ *lineptr; /* Pointer into line */ unsigned y, /* Current position on page */ xcount, ycount, /* Current count for X and Y */ xrep, yrep, /* Repeat count for X and Y */ xoff, yoff, /* Offsets for X and Y */ yend; /* End Y value */ int temprow, /* Row in template */ tempcolor; /* Template color */ const char *template; /* Pointer into template */ const unsigned char *color; /* Current color */ static const unsigned char colors[][3] = { /* Colors for test */ { 191, 191, 191 }, { 127, 127, 127 }, { 63, 63, 63 }, { 0, 0, 0 }, { 255, 0, 0 }, { 255, 127, 0 }, { 255, 255, 0 }, { 127, 255, 0 }, { 0, 255, 0 }, { 0, 255, 127 }, { 0, 255, 255 }, { 0, 127, 255 }, { 0, 0, 255 }, { 127, 0, 255 }, { 255, 0, 255 } }; static const char * const templates[] = { /* Raster template */ " CCC U U PPPP SSS TTTTT EEEEE SSS TTTTT 000 1 222 333 4 55555 66 77777 888 999 ", "C C U U P P S S T E S S T 0 0 11 2 2 3 3 4 4 5 6 7 8 8 9 9 ", "C U U P P S T E S T 0 0 1 2 3 4 4 5 6 7 8 8 9 9 ", "C U U PPPP SSS ----- T EEEE SSS T 0 0 0 1 22 333 44444 555 6666 7 888 9999 ", "C U U P S T E S T 0 0 1 2 3 4 5 6 6 7 8 8 9 ", "C C U U P S S T E S S T 0 0 1 2 3 3 4 5 5 6 6 7 8 8 9 ", " CCC UUU P SSS T EEEEE SSS T 000 111 22222 333 4 555 666 7 888 99 ", " " }; /* * Figure out the output format... */ if ((attr = ippFindAttribute(response, "document-format-supported", IPP_TAG_MIMETYPE)) == NULL) { puts("No supported document formats, aborting."); return (NULL); } if (*format) { if (!ippContainsString(attr, *format)) { printf("Printer does not support document-format '%s'.\n", *format); return (NULL); } if (!strcmp(*format, "image/urf")) mode = CUPS_RASTER_WRITE_APPLE; else if (!strcmp(*format, "image/pwg-raster")) mode = CUPS_RASTER_WRITE_PWG; else { printf("Unable to generate document-format '%s'.\n", *format); return (NULL); } } else if (ippContainsString(attr, "image/urf")) { /* * Apple Raster format... */ *format = "image/urf"; mode = CUPS_RASTER_WRITE_APPLE; } else if (ippContainsString(attr, "image/pwg-raster")) { /* * PWG Raster format... */ *format = "image/pwg-raster"; mode = CUPS_RASTER_WRITE_PWG; } else { /* * No supported raster format... */ puts("Printer does not support Apple or PWG raster files, aborting."); return (NULL); } /* * Figure out the the media, resolution, and color mode... */ if ((attr = ippFindAttribute(response, "media-default", IPP_TAG_KEYWORD)) != NULL) { /* * Use default media... */ media = pwgMediaForPWG(ippGetString(attr, 0, NULL)); } else if ((attr = ippFindAttribute(response, "media-ready", IPP_TAG_KEYWORD)) != NULL) { /* * Use ready media... */ if (ippContainsString(attr, "na_letter_8.5x11in")) media = pwgMediaForPWG("na_letter_8.5x11in"); else if (ippContainsString(attr, "iso_a4_210x297mm")) media = pwgMediaForPWG("iso_a4_210x297mm"); else media = pwgMediaForPWG(ippGetString(attr, 0, NULL)); } else { puts("No default or ready media reported by printer, aborting."); return (NULL); } if (mode == CUPS_RASTER_WRITE_APPLE && (attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL) { for (i = 0, count = ippGetCount(attr); i < count; i ++) { const char *val = ippGetString(attr, i, NULL); if (!strncmp(val, "RS", 2)) xdpi = ydpi = atoi(val + 2); else if (!strncmp(val, "W8", 2) && !type) type = "sgray_8"; else if (!strncmp(val, "SRGB24", 6) && !grayscale) type = "srgb_8"; } } else if (mode == CUPS_RASTER_WRITE_PWG && (attr = ippFindAttribute(response, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION)) != NULL) { for (i = 0, count = ippGetCount(attr); i < count; i ++) { int tempxdpi, tempydpi; ipp_res_t tempunits; tempxdpi = ippGetResolution(attr, 0, &tempydpi, &tempunits); if (i == 0 || tempxdpi < xdpi || tempydpi < ydpi) { xdpi = tempxdpi; ydpi = tempydpi; } } if ((attr = ippFindAttribute(response, "pwg-raster-document-type-supported", IPP_TAG_KEYWORD)) != NULL) { if (!grayscale && ippContainsString(attr, "srgb_8")) type = "srgb_8"; else if (ippContainsString(attr, "sgray_8")) type = "sgray_8"; } } if (xdpi < 72 || ydpi < 72) { puts("No supported raster resolutions, aborting."); return (NULL); } if (!type) { puts("No supported color spaces or bit depths, aborting."); return (NULL); } /* * Make the raster context and details... */ if (!cupsRasterInitPWGHeader(&header, media, type, xdpi, ydpi, "one-sided", NULL)) { printf("Unable to initialize raster context: %s\n", cupsRasterErrorString()); return (NULL); } header.cupsInteger[CUPS_RASTER_PWG_TotalPageCount] = 1; if (header.cupsWidth > (4 * header.HWResolution[0])) { xoff = header.HWResolution[0] / 2; yoff = header.HWResolution[1] / 2; } else { xoff = 0; yoff = 0; } xrep = (header.cupsWidth - 2 * xoff) / 140; yrep = xrep * header.HWResolution[1] / header.HWResolution[0]; yend = header.cupsHeight - yoff; /* * Prepare the raster file... */ if ((line = malloc(header.cupsBytesPerLine)) == NULL) { printf("Unable to allocate %u bytes for raster output: %s\n", header.cupsBytesPerLine, strerror(errno)); return (NULL); } if ((fd = cupsTempFd(tempname, (int)tempsize)) < 0) { printf("Unable to create temporary print file: %s\n", strerror(errno)); free(line); return (NULL); } if ((ras = cupsRasterOpen(fd, mode)) == NULL) { printf("Unable to open raster stream: %s\n", cupsRasterErrorString()); close(fd); free(line); return (NULL); } /* * Write a single page consisting of the template dots repeated over the page. */ cupsRasterWriteHeader2(ras, &header); memset(line, 0xff, header.cupsBytesPerLine); for (y = 0; y < yoff; y ++) cupsRasterWritePixels(ras, line, header.cupsBytesPerLine); for (temprow = 0, tempcolor = 0; y < yend;) { template = templates[temprow]; color = colors[tempcolor]; temprow ++; if (temprow >= (int)(sizeof(templates) / sizeof(templates[0]))) { temprow = 0; tempcolor ++; if (tempcolor >= (int)(sizeof(colors) / sizeof(colors[0]))) tempcolor = 0; else if (tempcolor > 3 && header.cupsColorSpace == CUPS_CSPACE_SW) tempcolor = 0; } memset(line, 0xff, header.cupsBytesPerLine); if (header.cupsColorSpace == CUPS_CSPACE_SW) { /* * Do grayscale output... */ for (lineptr = line + xoff; *template; template ++) { if (*template != ' ') { for (xcount = xrep; xcount > 0; xcount --) *lineptr++ = *color; } else { lineptr += xrep; } } } else { /* * Do color output... */ for (lineptr = line + 3 * xoff; *template; template ++) { if (*template != ' ') { for (xcount = xrep; xcount > 0; xcount --, lineptr += 3) memcpy(lineptr, color, 3); } else { lineptr += 3 * xrep; } } } for (ycount = yrep; ycount > 0 && y < yend; ycount --, y ++) cupsRasterWritePixels(ras, line, header.cupsBytesPerLine); } memset(line, 0xff, header.cupsBytesPerLine); for (y = 0; y < header.cupsHeight; y ++) cupsRasterWritePixels(ras, line, header.cupsBytesPerLine); cupsRasterClose(ras); close(fd); printf("PRINT FILE: %s\n", tempname); return (tempname); } /* * 'monitor_printer()' - Monitor the job and printer states. */ static void * /* O - Thread exit code */ monitor_printer( _client_monitor_t *monitor) /* I - Monitoring data */ { http_t *http; /* Connection to printer */ ipp_t *request, /* IPP request */ *response; /* IPP response */ ipp_attribute_t *attr; /* Attribute in response */ ipp_pstate_t printer_state; /* Printer state */ char printer_state_reasons[1024]; /* Printer state reasons */ ipp_jstate_t job_state; /* Job state */ char job_state_reasons[1024];/* Printer state reasons */ static const char * const jattrs[] = /* Job attributes we want */ { "job-state", "job-state-reasons" }; static const char * const pattrs[] = /* Printer attributes we want */ { "printer-state", "printer-state-reasons" }; /* * Open a connection to the printer... */ http = httpConnect2(monitor->hostname, monitor->port, NULL, AF_UNSPEC, monitor->encryption, 1, 0, NULL); /* * Loop until the job is canceled, aborted, or completed. */ printer_state = (ipp_pstate_t)0; printer_state_reasons[0] = '\0'; job_state = (ipp_jstate_t)0; job_state_reasons[0] = '\0'; while (monitor->job_state < IPP_JSTATE_CANCELED) { /* * Reconnect to the printer as needed... */ if (httpGetFd(http) < 0) httpReconnect2(http, 30000, NULL); if (httpGetFd(http) >= 0) { /* * Connected, so check on the printer state... */ request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, monitor->uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs); response = cupsDoRequest(http, request, monitor->resource); if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) printer_state = (ipp_pstate_t)ippGetInteger(attr, 0); if ((attr = ippFindAttribute(response, "printer-state-reasons", IPP_TAG_KEYWORD)) != NULL) ippAttributeString(attr, printer_state_reasons, sizeof(printer_state_reasons)); if (printer_state != monitor->printer_state || strcmp(printer_state_reasons, monitor->printer_state_reasons)) { printf("PRINTER: %s (%s)\n", ippEnumString("printer-state", printer_state), printer_state_reasons); monitor->printer_state = printer_state; strlcpy(monitor->printer_state_reasons, printer_state_reasons, sizeof(monitor->printer_state_reasons)); } ippDelete(response); if (monitor->job_id > 0) { /* * Check the status of the job itself... */ request = ippNewRequest(IPP_OP_GET_JOB_ATTRIBUTES); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, monitor->uri); ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", monitor->job_id); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(jattrs) / sizeof(jattrs[0])), NULL, jattrs); response = cupsDoRequest(http, request, monitor->resource); if ((attr = ippFindAttribute(response, "job-state", IPP_TAG_ENUM)) != NULL) job_state = (ipp_jstate_t)ippGetInteger(attr, 0); if ((attr = ippFindAttribute(response, "job-state-reasons", IPP_TAG_KEYWORD)) != NULL) ippAttributeString(attr, job_state_reasons, sizeof(job_state_reasons)); if (job_state != monitor->job_state || strcmp(job_state_reasons, monitor->job_state_reasons)) { printf("JOB %d: %s (%s)\n", monitor->job_id, ippEnumString("job-state", job_state), job_state_reasons); monitor->job_state = job_state; strlcpy(monitor->job_state_reasons, job_state_reasons, sizeof(monitor->job_state_reasons)); } ippDelete(response); } } if (monitor->job_state < IPP_JSTATE_CANCELED) { /* * Sleep for 5 seconds... */ sleep(5); } } /* * Cleanup and return... */ httpClose(http); return (NULL); } /* * 'show_attributes()' - Show attributes in a request or response. */ static void show_attributes(const char *title, /* I - Title */ int request, /* I - 1 for request, 0 for response */ ipp_t *ipp) /* I - IPP request/response */ { int minor, major = ippGetVersion(ipp, &minor); /* IPP version number */ ipp_tag_t group = IPP_TAG_ZERO; /* Current group tag */ ipp_attribute_t *attr; /* Current attribute */ const char *name; /* Attribute name */ char buffer[1024]; /* Value */ printf("%s:\n", title); printf(" version=%d.%d\n", major, minor); printf(" request-id=%d\n", ippGetRequestId(ipp)); if (!request) printf(" status-code=%s\n", ippErrorString(ippGetStatusCode(ipp))); for (attr = ippFirstAttribute(ipp); attr; attr = ippNextAttribute(ipp)) { if (group != ippGetGroupTag(attr)) { group = ippGetGroupTag(attr); if (group) printf(" %s:\n", ippTagString(group)); } if ((name = ippGetName(attr)) != NULL) { ippAttributeString(attr, buffer, sizeof(buffer)); printf(" %s(%s%s)=%s\n", name, ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr)), buffer); } } } /* * 'show_capabilities()' - Show printer capabilities. */ static void show_capabilities(ipp_t *response) /* I - Printer attributes */ { int i; /* Looping var */ ipp_attribute_t *attr; /* Attribute */ char buffer[1024]; /* Attribute value buffer */ static const char * const pattrs[] = /* Attributes we want to show */ { "copies-default", "copies-supported", "finishings-default", "finishings-ready", "finishings-supported", "media-default", "media-ready", "media-supported", "output-bin-default", "output-bin-supported", "print-color-mode-default", "print-color-mode-supported", "sides-default", "sides-supported", "document-format-default", "document-format-supported", "pwg-raster-document-resolution-supported", "pwg-raster-document-type-supported", "urf-supported" }; puts("CAPABILITIES:"); for (i = 0; i < (int)(sizeof(pattrs) / sizeof(pattrs[0])); i ++) { if ((attr = ippFindAttribute(response, pattrs[i], IPP_TAG_ZERO)) != NULL) { ippAttributeString(attr, buffer, sizeof(buffer)); printf(" %s=%s\n", pattrs[i], buffer); } } } /* * 'usage()' - Show program usage... */ static void usage(void) { puts("Usage: ./testclient printer-uri [options]"); puts("Options:"); puts(" -d document-format Generate the specified format"); puts(" -f print-file Print the named file"); puts(" -g Force grayscale printing"); puts(" -k Keep temporary files"); puts(" -v Be more verbose"); } ippsample/cups/array.c0000644000175000017500000006634113240604116014005 0ustar tilltill/* * Sorted array routines for CUPS. * * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include #include "string-private.h" #include "debug-private.h" #include "array-private.h" /* * Limits... */ #define _CUPS_MAXSAVE 32 /**** Maximum number of saves ****/ /* * Types and structures... */ struct _cups_array_s /**** CUPS array structure ****/ { /* * The current implementation uses an insertion sort into an array of * sorted pointers. We leave the array type private/opaque so that we * can change the underlying implementation without affecting the users * of this API. */ int num_elements, /* Number of array elements */ alloc_elements, /* Allocated array elements */ current, /* Current element */ insert, /* Last inserted element */ unique, /* Are all elements unique? */ num_saved, /* Number of saved elements */ saved[_CUPS_MAXSAVE]; /* Saved elements */ void **elements; /* Array elements */ cups_array_func_t compare; /* Element comparison function */ void *data; /* User data passed to compare */ cups_ahash_func_t hashfunc; /* Hash function */ int hashsize, /* Size of hash */ *hash; /* Hash array */ cups_acopy_func_t copyfunc; /* Copy function */ cups_afree_func_t freefunc; /* Free function */ }; /* * Local functions... */ static int cups_array_add(cups_array_t *a, void *e, int insert); static int cups_array_find(cups_array_t *a, void *e, int prev, int *rdiff); /* * 'cupsArrayAdd()' - Add an element to the array. * * When adding an element to a sorted array, non-unique elements are * appended at the end of the run of identical elements. For unsorted arrays, * the element is appended to the end of the array. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 1 on success, 0 on failure */ cupsArrayAdd(cups_array_t *a, /* I - Array */ void *e) /* I - Element */ { DEBUG_printf(("2cupsArrayAdd(a=%p, e=%p)", (void *)a, e)); /* * Range check input... */ if (!a || !e) { DEBUG_puts("3cupsArrayAdd: returning 0"); return (0); } /* * Append the element... */ return (cups_array_add(a, e, 0)); } /* * '_cupsArrayAddStrings()' - Add zero or more delimited strings to an array. * * Note: The array MUST be created using the @link _cupsArrayNewStrings@ * function. Duplicate strings are NOT added. If the string pointer "s" is NULL * or the empty string, no strings are added to the array. */ int /* O - 1 on success, 0 on failure */ _cupsArrayAddStrings(cups_array_t *a, /* I - Array */ const char *s, /* I - Delimited strings or NULL */ char delim)/* I - Delimiter character */ { char *buffer, /* Copy of string */ *start, /* Start of string */ *end; /* End of string */ int status = 1; /* Status of add */ DEBUG_printf(("_cupsArrayAddStrings(a=%p, s=\"%s\", delim='%c')", (void *)a, s, delim)); if (!a || !s || !*s) { DEBUG_puts("1_cupsArrayAddStrings: Returning 0"); return (0); } if (delim == ' ') { /* * Skip leading whitespace... */ DEBUG_puts("1_cupsArrayAddStrings: Skipping leading whitespace."); while (*s && isspace(*s & 255)) s ++; DEBUG_printf(("1_cupsArrayAddStrings: Remaining string \"%s\".", s)); } if (!strchr(s, delim) && (delim != ' ' || (!strchr(s, '\t') && !strchr(s, '\n')))) { /* * String doesn't contain a delimiter, so add it as a single value... */ DEBUG_puts("1_cupsArrayAddStrings: No delimiter seen, adding a single " "value."); if (!cupsArrayFind(a, (void *)s)) status = cupsArrayAdd(a, (void *)s); } else if ((buffer = strdup(s)) == NULL) { DEBUG_puts("1_cupsArrayAddStrings: Unable to duplicate string."); status = 0; } else { for (start = end = buffer; *end; start = end) { /* * Find the end of the current delimited string and see if we need to add * it... */ if (delim == ' ') { while (*end && !isspace(*end & 255)) end ++; while (*end && isspace(*end & 255)) *end++ = '\0'; } else if ((end = strchr(start, delim)) != NULL) *end++ = '\0'; else end = start + strlen(start); DEBUG_printf(("1_cupsArrayAddStrings: Adding \"%s\", end=\"%s\"", start, end)); if (!cupsArrayFind(a, start)) status &= cupsArrayAdd(a, start); } free(buffer); } DEBUG_printf(("1_cupsArrayAddStrings: Returning %d.", status)); return (status); } /* * 'cupsArrayClear()' - Clear the array. * * This function is equivalent to removing all elements in the array. * The caller is responsible for freeing the memory used by the * elements themselves. * * @since CUPS 1.2/macOS 10.5@ */ void cupsArrayClear(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return; /* * Free the existing elements as needed.. */ if (a->freefunc) { int i; /* Looping var */ void **e; /* Current element */ for (i = a->num_elements, e = a->elements; i > 0; i --, e ++) (a->freefunc)(*e, a->data); } /* * Set the number of elements to 0; we don't actually free the memory * here - that is done in cupsArrayDelete()... */ a->num_elements = 0; a->current = -1; a->insert = -1; a->unique = 1; a->num_saved = 0; } /* * 'cupsArrayCount()' - Get the number of elements in the array. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - Number of elements */ cupsArrayCount(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return (0); /* * Return the number of elements... */ return (a->num_elements); } /* * 'cupsArrayCurrent()' - Return the current element in the array. * * The current element is undefined until you call @link cupsArrayFind@, * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - Element */ cupsArrayCurrent(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return (NULL); /* * Return the current element... */ if (a->current >= 0 && a->current < a->num_elements) return (a->elements[a->current]); else return (NULL); } /* * 'cupsArrayDelete()' - Free all memory used by the array. * * The caller is responsible for freeing the memory used by the * elements themselves. * * @since CUPS 1.2/macOS 10.5@ */ void cupsArrayDelete(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return; /* * Free the elements if we have a free function (otherwise the caller is * responsible for doing the dirty work...) */ if (a->freefunc) { int i; /* Looping var */ void **e; /* Current element */ for (i = a->num_elements, e = a->elements; i > 0; i --, e ++) (a->freefunc)(*e, a->data); } /* * Free the array of element pointers... */ if (a->alloc_elements) free(a->elements); if (a->hashsize) free(a->hash); free(a); } /* * 'cupsArrayDup()' - Duplicate the array. * * @since CUPS 1.2/macOS 10.5@ */ cups_array_t * /* O - Duplicate array */ cupsArrayDup(cups_array_t *a) /* I - Array */ { cups_array_t *da; /* Duplicate array */ /* * Range check input... */ if (!a) return (NULL); /* * Allocate memory for the array... */ da = calloc(1, sizeof(cups_array_t)); if (!da) return (NULL); da->compare = a->compare; da->data = a->data; da->current = a->current; da->insert = a->insert; da->unique = a->unique; da->num_saved = a->num_saved; memcpy(da->saved, a->saved, sizeof(a->saved)); if (a->num_elements) { /* * Allocate memory for the elements... */ da->elements = malloc((size_t)a->num_elements * sizeof(void *)); if (!da->elements) { free(da); return (NULL); } /* * Copy the element pointers... */ if (a->copyfunc) { /* * Use the copy function to make a copy of each element... */ int i; /* Looping var */ for (i = 0; i < a->num_elements; i ++) da->elements[i] = (a->copyfunc)(a->elements[i], a->data); } else { /* * Just copy raw pointers... */ memcpy(da->elements, a->elements, (size_t)a->num_elements * sizeof(void *)); } da->num_elements = a->num_elements; da->alloc_elements = a->num_elements; } /* * Return the new array... */ return (da); } /* * 'cupsArrayFind()' - Find an element in the array. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - Element found or @code NULL@ */ cupsArrayFind(cups_array_t *a, /* I - Array */ void *e) /* I - Element */ { int current, /* Current element */ diff, /* Difference */ hash; /* Hash index */ /* * Range check input... */ if (!a || !e) return (NULL); /* * See if we have any elements... */ if (!a->num_elements) return (NULL); /* * Yes, look for a match... */ if (a->hash) { hash = (*(a->hashfunc))(e, a->data); if (hash < 0 || hash >= a->hashsize) { current = a->current; hash = -1; } else { current = a->hash[hash]; if (current < 0 || current >= a->num_elements) current = a->current; } } else { current = a->current; hash = -1; } current = cups_array_find(a, e, current, &diff); if (!diff) { /* * Found a match! If the array does not contain unique values, find * the first element that is the same... */ if (!a->unique && a->compare) { /* * The array is not unique, find the first match... */ while (current > 0 && !(*(a->compare))(e, a->elements[current - 1], a->data)) current --; } a->current = current; if (hash >= 0) a->hash[hash] = current; return (a->elements[current]); } else { /* * No match... */ a->current = -1; return (NULL); } } /* * 'cupsArrayFirst()' - Get the first element in the array. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - First element or @code NULL@ if the array is empty */ cupsArrayFirst(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return (NULL); /* * Return the first element... */ a->current = 0; return (cupsArrayCurrent(a)); } /* * 'cupsArrayGetIndex()' - Get the index of the current element. * * The current element is undefined until you call @link cupsArrayFind@, * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@. * * @since CUPS 1.3/macOS 10.5@ */ int /* O - Index of the current element, starting at 0 */ cupsArrayGetIndex(cups_array_t *a) /* I - Array */ { if (!a) return (-1); else return (a->current); } /* * 'cupsArrayGetInsert()' - Get the index of the last inserted element. * * @since CUPS 1.3/macOS 10.5@ */ int /* O - Index of the last inserted element, starting at 0 */ cupsArrayGetInsert(cups_array_t *a) /* I - Array */ { if (!a) return (-1); else return (a->insert); } /* * 'cupsArrayIndex()' - Get the N-th element in the array. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - N-th element or @code NULL@ */ cupsArrayIndex(cups_array_t *a, /* I - Array */ int n) /* I - Index into array, starting at 0 */ { if (!a) return (NULL); a->current = n; return (cupsArrayCurrent(a)); } /* * 'cupsArrayInsert()' - Insert an element in the array. * * When inserting an element in a sorted array, non-unique elements are * inserted at the beginning of the run of identical elements. For unsorted * arrays, the element is inserted at the beginning of the array. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 0 on failure, 1 on success */ cupsArrayInsert(cups_array_t *a, /* I - Array */ void *e) /* I - Element */ { DEBUG_printf(("2cupsArrayInsert(a=%p, e=%p)", (void *)a, e)); /* * Range check input... */ if (!a || !e) { DEBUG_puts("3cupsArrayInsert: returning 0"); return (0); } /* * Insert the element... */ return (cups_array_add(a, e, 1)); } /* * 'cupsArrayLast()' - Get the last element in the array. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - Last element or @code NULL@ if the array is empty */ cupsArrayLast(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return (NULL); /* * Return the last element... */ a->current = a->num_elements - 1; return (cupsArrayCurrent(a)); } /* * 'cupsArrayNew()' - Create a new array. * * The comparison function ("f") is used to create a sorted array. The function * receives pointers to two elements and the user data pointer ("d") - the user * data pointer argument can safely be omitted when not required so functions * like @code strcmp@ can be used for sorted string arrays. * * @since CUPS 1.2/macOS 10.5@ */ cups_array_t * /* O - Array */ cupsArrayNew(cups_array_func_t f, /* I - Comparison function or @code NULL@ for an unsorted array */ void *d) /* I - User data pointer or @code NULL@ */ { return (cupsArrayNew3(f, d, 0, 0, 0, 0)); } /* * 'cupsArrayNew2()' - Create a new array with hash. * * The comparison function ("f") is used to create a sorted array. The function * receives pointers to two elements and the user data pointer ("d") - the user * data pointer argument can safely be omitted when not required so functions * like @code strcmp@ can be used for sorted string arrays. * * The hash function ("h") is used to implement cached lookups with the * specified hash size ("hsize"). * * @since CUPS 1.3/macOS 10.5@ */ cups_array_t * /* O - Array */ cupsArrayNew2(cups_array_func_t f, /* I - Comparison function or @code NULL@ for an unsorted array */ void *d, /* I - User data or @code NULL@ */ cups_ahash_func_t h, /* I - Hash function or @code NULL@ for unhashed lookups */ int hsize) /* I - Hash size (>= 0) */ { return (cupsArrayNew3(f, d, h, hsize, 0, 0)); } /* * 'cupsArrayNew3()' - Create a new array with hash and/or free function. * * The comparison function ("f") is used to create a sorted array. The function * receives pointers to two elements and the user data pointer ("d") - the user * data pointer argument can safely be omitted when not required so functions * like @code strcmp@ can be used for sorted string arrays. * * The hash function ("h") is used to implement cached lookups with the * specified hash size ("hsize"). * * The copy function ("cf") is used to automatically copy/retain elements when * added or the array is copied. * * The free function ("cf") is used to automatically free/release elements when * removed or the array is deleted. * * @since CUPS 1.5/macOS 10.7@ */ cups_array_t * /* O - Array */ cupsArrayNew3(cups_array_func_t f, /* I - Comparison function or @code NULL@ for an unsorted array */ void *d, /* I - User data or @code NULL@ */ cups_ahash_func_t h, /* I - Hash function or @code NULL@ for unhashed lookups */ int hsize, /* I - Hash size (>= 0) */ cups_acopy_func_t cf, /* I - Copy function */ cups_afree_func_t ff) /* I - Free function */ { cups_array_t *a; /* Array */ /* * Allocate memory for the array... */ a = calloc(1, sizeof(cups_array_t)); if (!a) return (NULL); a->compare = f; a->data = d; a->current = -1; a->insert = -1; a->num_saved = 0; a->unique = 1; if (hsize > 0 && h) { a->hashfunc = h; a->hashsize = hsize; a->hash = malloc((size_t)hsize * sizeof(int)); if (!a->hash) { free(a); return (NULL); } memset(a->hash, -1, (size_t)hsize * sizeof(int)); } a->copyfunc = cf; a->freefunc = ff; return (a); } /* * '_cupsArrayNewStrings()' - Create a new array of comma-delimited strings. * * Note: The array automatically manages copies of the strings passed. If the * string pointer "s" is NULL or the empty string, no strings are added to the * newly created array. */ cups_array_t * /* O - Array */ _cupsArrayNewStrings(const char *s, /* I - Delimited strings or NULL */ char delim) /* I - Delimiter character */ { cups_array_t *a; /* Array */ if ((a = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)_cupsStrAlloc, (cups_afree_func_t)_cupsStrFree)) != NULL) _cupsArrayAddStrings(a, s, delim); return (a); } /* * 'cupsArrayNext()' - Get the next element in the array. * * This function is equivalent to "cupsArrayIndex(a, cupsArrayGetIndex(a) + 1)". * * The next element is undefined until you call @link cupsArrayFind@, * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@ * to set the current element. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - Next element or @code NULL@ */ cupsArrayNext(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return (NULL); /* * Return the next element... */ if (a->current < a->num_elements) a->current ++; return (cupsArrayCurrent(a)); } /* * 'cupsArrayPrev()' - Get the previous element in the array. * * This function is equivalent to "cupsArrayIndex(a, cupsArrayGetIndex(a) - 1)". * * The previous element is undefined until you call @link cupsArrayFind@, * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@ * to set the current element. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - Previous element or @code NULL@ */ cupsArrayPrev(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return (NULL); /* * Return the previous element... */ if (a->current >= 0) a->current --; return (cupsArrayCurrent(a)); } /* * 'cupsArrayRemove()' - Remove an element from the array. * * If more than one element matches "e", only the first matching element is * removed. * * The caller is responsible for freeing the memory used by the * removed element. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 1 on success, 0 on failure */ cupsArrayRemove(cups_array_t *a, /* I - Array */ void *e) /* I - Element */ { ssize_t i, /* Looping var */ current; /* Current element */ int diff; /* Difference */ /* * Range check input... */ if (!a || !e) return (0); /* * See if the element is in the array... */ if (!a->num_elements) return (0); current = cups_array_find(a, e, a->current, &diff); if (diff) return (0); /* * Yes, now remove it... */ a->num_elements --; if (a->freefunc) (a->freefunc)(a->elements[current], a->data); if (current < a->num_elements) memmove(a->elements + current, a->elements + current + 1, (size_t)(a->num_elements - current) * sizeof(void *)); if (current <= a->current) a->current --; if (current < a->insert) a->insert --; else if (current == a->insert) a->insert = -1; for (i = 0; i < a->num_saved; i ++) if (current <= a->saved[i]) a->saved[i] --; if (a->num_elements <= 1) a->unique = 1; return (1); } /* * 'cupsArrayRestore()' - Reset the current element to the last @link cupsArraySave@. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - New current element */ cupsArrayRestore(cups_array_t *a) /* I - Array */ { if (!a) return (NULL); if (a->num_saved <= 0) return (NULL); a->num_saved --; a->current = a->saved[a->num_saved]; if (a->current >= 0 && a->current < a->num_elements) return (a->elements[a->current]); else return (NULL); } /* * 'cupsArraySave()' - Mark the current element for a later @link cupsArrayRestore@. * * The current element is undefined until you call @link cupsArrayFind@, * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@ * to set the current element. * * The save/restore stack is guaranteed to be at least 32 elements deep. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 1 on success, 0 on failure */ cupsArraySave(cups_array_t *a) /* I - Array */ { if (!a) return (0); if (a->num_saved >= _CUPS_MAXSAVE) return (0); a->saved[a->num_saved] = a->current; a->num_saved ++; return (1); } /* * 'cupsArrayUserData()' - Return the user data for an array. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - User data */ cupsArrayUserData(cups_array_t *a) /* I - Array */ { if (a) return (a->data); else return (NULL); } /* * 'cups_array_add()' - Insert or append an element to the array. * * @since CUPS 1.2/macOS 10.5@ */ static int /* O - 1 on success, 0 on failure */ cups_array_add(cups_array_t *a, /* I - Array */ void *e, /* I - Element to add */ int insert) /* I - 1 = insert, 0 = append */ { int i, /* Looping var */ current; /* Current element */ int diff; /* Comparison with current element */ DEBUG_printf(("7cups_array_add(a=%p, e=%p, insert=%d)", (void *)a, e, insert)); /* * Verify we have room for the new element... */ if (a->num_elements >= a->alloc_elements) { /* * Allocate additional elements; start with 16 elements, then * double the size until 1024 elements, then add 1024 elements * thereafter... */ void **temp; /* New array elements */ int count; /* New allocation count */ if (a->alloc_elements == 0) { count = 16; temp = malloc((size_t)count * sizeof(void *)); } else { if (a->alloc_elements < 1024) count = a->alloc_elements * 2; else count = a->alloc_elements + 1024; temp = realloc(a->elements, (size_t)count * sizeof(void *)); } DEBUG_printf(("9cups_array_add: count=" CUPS_LLFMT, CUPS_LLCAST count)); if (!temp) { DEBUG_puts("9cups_array_add: allocation failed, returning 0"); return (0); } a->alloc_elements = count; a->elements = temp; } /* * Find the insertion point for the new element; if there is no * compare function or elements, just add it to the beginning or end... */ if (!a->num_elements || !a->compare) { /* * No elements or comparison function, insert/append as needed... */ if (insert) current = 0; /* Insert at beginning */ else current = a->num_elements; /* Append to the end */ } else { /* * Do a binary search for the insertion point... */ current = cups_array_find(a, e, a->insert, &diff); if (diff > 0) { /* * Insert after the current element... */ current ++; } else if (!diff) { /* * Compared equal, make sure we add to the begining or end of * the current run of equal elements... */ a->unique = 0; if (insert) { /* * Insert at beginning of run... */ while (current > 0 && !(*(a->compare))(e, a->elements[current - 1], a->data)) current --; } else { /* * Append at end of run... */ do { current ++; } while (current < a->num_elements && !(*(a->compare))(e, a->elements[current], a->data)); } } } /* * Insert or append the element... */ if (current < a->num_elements) { /* * Shift other elements to the right... */ memmove(a->elements + current + 1, a->elements + current, (size_t)(a->num_elements - current) * sizeof(void *)); if (a->current >= current) a->current ++; for (i = 0; i < a->num_saved; i ++) if (a->saved[i] >= current) a->saved[i] ++; DEBUG_printf(("9cups_array_add: insert element at index " CUPS_LLFMT, CUPS_LLCAST current)); } #ifdef DEBUG else DEBUG_printf(("9cups_array_add: append element at " CUPS_LLFMT, CUPS_LLCAST current)); #endif /* DEBUG */ if (a->copyfunc) { if ((a->elements[current] = (a->copyfunc)(e, a->data)) == NULL) { DEBUG_puts("8cups_array_add: Copy function returned NULL, returning 0"); return (0); } } else a->elements[current] = e; a->num_elements ++; a->insert = current; #ifdef DEBUG for (current = 0; current < a->num_elements; current ++) DEBUG_printf(("9cups_array_add: a->elements[" CUPS_LLFMT "]=%p", CUPS_LLCAST current, a->elements[current])); #endif /* DEBUG */ DEBUG_puts("9cups_array_add: returning 1"); return (1); } /* * 'cups_array_find()' - Find an element in the array. */ static int /* O - Index of match */ cups_array_find(cups_array_t *a, /* I - Array */ void *e, /* I - Element */ int prev, /* I - Previous index */ int *rdiff) /* O - Difference of match */ { int left, /* Left side of search */ right, /* Right side of search */ current, /* Current element */ diff; /* Comparison with current element */ DEBUG_printf(("7cups_array_find(a=%p, e=%p, prev=%d, rdiff=%p)", (void *)a, e, prev, (void *)rdiff)); if (a->compare) { /* * Do a binary search for the element... */ DEBUG_puts("9cups_array_find: binary search"); if (prev >= 0 && prev < a->num_elements) { /* * Start search on either side of previous... */ if ((diff = (*(a->compare))(e, a->elements[prev], a->data)) == 0 || (diff < 0 && prev == 0) || (diff > 0 && prev == (a->num_elements - 1))) { /* * Exact or edge match, return it! */ DEBUG_printf(("9cups_array_find: Returning %d, diff=%d", prev, diff)); *rdiff = diff; return (prev); } else if (diff < 0) { /* * Start with previous on right side... */ left = 0; right = prev; } else { /* * Start wih previous on left side... */ left = prev; right = a->num_elements - 1; } } else { /* * Start search in the middle... */ left = 0; right = a->num_elements - 1; } do { current = (left + right) / 2; diff = (*(a->compare))(e, a->elements[current], a->data); DEBUG_printf(("9cups_array_find: left=%d, right=%d, current=%d, diff=%d", left, right, current, diff)); if (diff == 0) break; else if (diff < 0) right = current; else left = current; } while ((right - left) > 1); if (diff != 0) { /* * Check the last 1 or 2 elements... */ if ((diff = (*(a->compare))(e, a->elements[left], a->data)) <= 0) current = left; else { diff = (*(a->compare))(e, a->elements[right], a->data); current = right; } } } else { /* * Do a linear pointer search... */ DEBUG_puts("9cups_array_find: linear search"); diff = 1; for (current = 0; current < a->num_elements; current ++) if (a->elements[current] == e) { diff = 0; break; } } /* * Return the closest element and the difference... */ DEBUG_printf(("8cups_array_find: Returning %d, diff=%d", current, diff)); *rdiff = diff; return (current); } ippsample/cups/dest-localization.c0000644000175000017500000003122113240604116016301 0ustar tilltill/* * Destination localization support for CUPS. * * Copyright 2012-2017 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" /* * Local functions... */ static void cups_create_localizations(http_t *http, cups_dinfo_t *dinfo); /* * 'cupsLocalizeDestMedia()' - Get the localized string for a destination media * size. * * The returned string is stored in the destination information and will become * invalid if the destination information is deleted. * * @since CUPS 2.0/macOS 10.10@ */ const char * /* O - Localized string */ cupsLocalizeDestMedia( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ unsigned flags, /* I - Media flags */ cups_size_t *size) /* I - Media size */ { cups_lang_t *lang; /* Standard localizations */ _cups_message_t key, /* Search key */ *match; /* Matching entry */ pwg_media_t *pwg; /* PWG media information */ cups_array_t *db; /* Media database */ _cups_media_db_t *mdb; /* Media database entry */ char lstr[1024], /* Localized size name */ temp[256]; /* Temporary string */ const char *lsize, /* Localized media size */ *lsource, /* Localized media source */ *ltype; /* Localized media type */ DEBUG_printf(("cupsLocalizeDestMedia(http=%p, dest=%p, dinfo=%p, flags=%x, size=%p(\"%s\"))", (void *)http, (void *)dest, (void *)dinfo, flags, (void *)size, size ? size->media : "(null)")); /* * Range check input... */ if (!http || !dest || !dinfo || !size) { DEBUG_puts("1cupsLocalizeDestMedia: Returning NULL."); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (NULL); } /* * Find the matching media database entry... */ if (flags & CUPS_MEDIA_FLAGS_READY) db = dinfo->ready_db; else db = dinfo->media_db; DEBUG_printf(("1cupsLocalizeDestMedia: size->media=\"%s\"", size->media)); for (mdb = (_cups_media_db_t *)cupsArrayFirst(db); mdb; mdb = (_cups_media_db_t *)cupsArrayNext(db)) { if (mdb->key && !strcmp(mdb->key, size->media)) break; else if (mdb->size_name && !strcmp(mdb->size_name, size->media)) break; } if (!mdb) { for (mdb = (_cups_media_db_t *)cupsArrayFirst(db); mdb; mdb = (_cups_media_db_t *)cupsArrayNext(db)) { if (mdb->width == size->width && mdb->length == size->length && mdb->bottom == size->bottom && mdb->left == size->left && mdb->right == size->right && mdb->top == size->top) break; } } /* * See if the localization is cached... */ lang = cupsLangDefault(); if (!dinfo->localizations) cups_create_localizations(http, dinfo); snprintf(temp, sizeof(temp), "media.%s", size->media); key.msg = temp; if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, &key)) != NULL) { lsize = match->str; } else { /* * Not a media name, try a media-key name... */ snprintf(temp, sizeof(temp), "media-key.%s", size->media); if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, &key)) != NULL) lsize = match->str; else lsize = NULL; } if (!lsize && (pwg = pwgMediaForSize(size->width, size->length)) != NULL && pwg->ppd) { /* * Get a standard localization... */ snprintf(temp, sizeof(temp), "media.%s", pwg->pwg); if ((lsize = _cupsLangString(lang, temp)) == temp) lsize = NULL; } if (!lsize) { /* * Make a dimensional localization... */ if ((size->width % 635) == 0 && (size->length % 635) == 0) { /* * Use inches since the size is a multiple of 1/4 inch. */ snprintf(temp, sizeof(temp), _cupsLangString(lang, _("%g x %g \"")), size->width / 2540.0, size->length / 2540.0); } else { /* * Use millimeters since the size is not a multiple of 1/4 inch. */ snprintf(temp, sizeof(temp), _cupsLangString(lang, _("%d x %d mm")), (size->width + 50) / 100, (size->length + 50) / 100); } lsize = temp; } if (mdb) { DEBUG_printf(("1cupsLocalizeDestMedia: MATCH mdb%p [key=\"%s\" size_name=\"%s\" source=\"%s\" type=\"%s\" width=%d length=%d B%d L%d R%d T%d]", (void *)mdb, mdb->key, mdb->size_name, mdb->source, mdb->type, mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top)); if ((lsource = cupsLocalizeDestValue(http, dest, dinfo, "media-source", mdb->source)) == mdb->source && mdb->source) lsource = _cupsLangString(lang, _("Other Tray")); if ((ltype = cupsLocalizeDestValue(http, dest, dinfo, "media-type", mdb->type)) == mdb->type && mdb->type) ltype = _cupsLangString(lang, _("Other Media")); } else { lsource = NULL; ltype = NULL; } if (!lsource && !ltype) { if (!size->bottom && !size->left && !size->right && !size->top) snprintf(lstr, sizeof(lstr), _cupsLangString(lang, _("%s (Borderless)")), lsize); else strlcpy(lstr, lsize, sizeof(lstr)); } else if (!lsource) { if (!size->bottom && !size->left && !size->right && !size->top) snprintf(lstr, sizeof(lstr), _cupsLangString(lang, _("%s (Borderless, %s)")), lsize, ltype); else snprintf(lstr, sizeof(lstr), _cupsLangString(lang, _("%s (%s)")), lsize, ltype); } else if (!ltype) { if (!size->bottom && !size->left && !size->right && !size->top) snprintf(lstr, sizeof(lstr), _cupsLangString(lang, _("%s (Borderless, %s)")), lsize, lsource); else snprintf(lstr, sizeof(lstr), _cupsLangString(lang, _("%s (%s)")), lsize, lsource); } else { if (!size->bottom && !size->left && !size->right && !size->top) snprintf(lstr, sizeof(lstr), _cupsLangString(lang, _("%s (Borderless, %s, %s)")), lsize, ltype, lsource); else snprintf(lstr, sizeof(lstr), _cupsLangString(lang, _("%s (%s, %s)")), lsize, ltype, lsource); } if ((match = (_cups_message_t *)calloc(1, sizeof(_cups_message_t))) == NULL) return (NULL); match->msg = strdup(size->media); match->str = strdup(lstr); cupsArrayAdd(dinfo->localizations, match); DEBUG_printf(("1cupsLocalizeDestMedia: Returning \"%s\".", match->str)); return (match->str); } /* * 'cupsLocalizeDestOption()' - Get the localized string for a destination * option. * * The returned string is stored in the destination information and will become * invalid if the destination information is deleted. * * @since CUPS 1.6/macOS 10.8@ */ const char * /* O - Localized string */ cupsLocalizeDestOption( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ const char *option) /* I - Option to localize */ { _cups_message_t key, /* Search key */ *match; /* Matching entry */ const char *localized; /* Localized string */ DEBUG_printf(("cupsLocalizeDestOption(http=%p, dest=%p, dinfo=%p, option=\"%s\")", (void *)http, (void *)dest, (void *)dinfo, option)); if (!http || !dest || !dinfo) return (option); if (!dinfo->localizations) cups_create_localizations(http, dinfo); key.msg = (char *)option; if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, &key)) != NULL) return (match->str); else if ((localized = _cupsLangString(cupsLangDefault(), option)) != NULL) return (localized); else return (option); } /* * 'cupsLocalizeDestValue()' - Get the localized string for a destination * option+value pair. * * The returned string is stored in the destination information and will become * invalid if the destination information is deleted. * * @since CUPS 1.6/macOS 10.8@ */ const char * /* O - Localized string */ cupsLocalizeDestValue( http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ const char *option, /* I - Option to localize */ const char *value) /* I - Value to localize */ { _cups_message_t key, /* Search key */ *match; /* Matching entry */ char pair[256]; /* option.value pair */ const char *localized; /* Localized string */ DEBUG_printf(("cupsLocalizeDestValue(http=%p, dest=%p, dinfo=%p, option=\"%s\", value=\"%s\")", (void *)http, (void *)dest, (void *)dinfo, option, value)); if (!http || !dest || !dinfo) return (value); if (!strcmp(option, "media")) { pwg_media_t *media = pwgMediaForPWG(value); cups_size_t size; strlcpy(size.media, value, sizeof(size.media)); size.width = media ? media->width : 0; size.length = media ? media->length : 0; size.left = 0; size.right = 0; size.bottom = 0; size.top = 0; return (cupsLocalizeDestMedia(http, dest, dinfo, CUPS_MEDIA_FLAGS_DEFAULT, &size)); } if (!dinfo->localizations) cups_create_localizations(http, dinfo); snprintf(pair, sizeof(pair), "%s.%s", option, value); key.msg = pair; if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, &key)) != NULL) return (match->str); else if ((localized = _cupsLangString(cupsLangDefault(), pair)) != NULL && strcmp(localized, pair)) return (localized); else return (value); } /* * 'cups_create_localizations()' - Create the localizations array for a * destination. */ static void cups_create_localizations( http_t *http, /* I - Connection to destination */ cups_dinfo_t *dinfo) /* I - Destination informations */ { http_t *http2; /* Connection for strings file */ http_status_t status; /* Request status */ ipp_attribute_t *attr; /* "printer-strings-uri" attribute */ char scheme[32], /* URI scheme */ userpass[256], /* Username/password info */ hostname[256], /* Hostname */ resource[1024], /* Resource */ http_hostname[256], /* Hostname of connection */ tempfile[1024]; /* Temporary filename */ int port; /* Port number */ http_encryption_t encryption; /* Encryption to use */ cups_file_t *temp; /* Temporary file */ /* * See if there are any localizations... */ if ((attr = ippFindAttribute(dinfo->attrs, "printer-strings-uri", IPP_TAG_URI)) == NULL) { /* * Nope, create an empty message catalog... */ dinfo->localizations = _cupsMessageNew(NULL); DEBUG_puts("4cups_create_localizations: No printer-strings-uri (uri) value."); return; } /* * Pull apart the URI and determine whether we need to try a different * server... */ if (httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) { dinfo->localizations = _cupsMessageNew(NULL); DEBUG_printf(("4cups_create_localizations: Bad printer-strings-uri value \"%s\".", attr->values[0].string.text)); return; } httpGetHostname(http, http_hostname, sizeof(http_hostname)); if (!_cups_strcasecmp(http_hostname, hostname) && port == httpAddrPort(http->hostaddr)) { /* * Use the same connection... */ http2 = http; } else { /* * Connect to the alternate host... */ if (!strcmp(scheme, "https")) encryption = HTTP_ENCRYPTION_ALWAYS; else encryption = HTTP_ENCRYPTION_IF_REQUESTED; if ((http2 = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL) { DEBUG_printf(("4cups_create_localizations: Unable to connect to " "%s:%d: %s", hostname, port, cupsLastErrorString())); return; } } /* * Get a temporary file... */ if ((temp = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL) { DEBUG_printf(("4cups_create_localizations: Unable to create temporary " "file: %s", cupsLastErrorString())); if (http2 != http) httpClose(http2); return; } status = cupsGetFd(http2, resource, cupsFileNumber(temp)); cupsFileClose(temp); DEBUG_printf(("4cups_create_localizations: GET %s = %s", resource, httpStatus(status))); if (status == HTTP_STATUS_OK) { /* * Got the file, read it... */ dinfo->localizations = _cupsMessageLoad(tempfile, _CUPS_MESSAGE_STRINGS); } DEBUG_printf(("4cups_create_localizations: %d messages loaded.", cupsArrayCount(dinfo->localizations))); /* * Cleanup... */ unlink(tempfile); if (http2 != http) httpClose(http2); } ippsample/cups/encode.c0000644000175000017500000006300613240604116014117 0ustar tilltill/* * Option encoding routines for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" /* * Local list of option names, the value tags they should use, and the list of * supported operations... * * **** THIS LIST MUST BE SORTED BY ATTRIBUTE NAME **** */ static const ipp_op_t ipp_job_creation[] = { IPP_OP_PRINT_JOB, IPP_OP_PRINT_URI, IPP_OP_VALIDATE_JOB, IPP_OP_CREATE_JOB, IPP_OP_HOLD_JOB, IPP_OP_SET_JOB_ATTRIBUTES, IPP_OP_CUPS_NONE }; static const ipp_op_t ipp_doc_creation[] = { IPP_OP_PRINT_JOB, IPP_OP_PRINT_URI, IPP_OP_SEND_DOCUMENT, IPP_OP_SEND_URI, IPP_OP_SET_JOB_ATTRIBUTES, IPP_OP_SET_DOCUMENT_ATTRIBUTES, IPP_OP_CUPS_NONE }; static const ipp_op_t ipp_sub_creation[] = { IPP_OP_PRINT_JOB, IPP_OP_PRINT_URI, IPP_OP_CREATE_JOB, IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS, IPP_OP_CREATE_JOB_SUBSCRIPTIONS, IPP_OP_CUPS_NONE }; static const ipp_op_t ipp_all_print[] = { IPP_OP_PRINT_JOB, IPP_OP_PRINT_URI, IPP_OP_VALIDATE_JOB, IPP_OP_CREATE_JOB, IPP_OP_SEND_DOCUMENT, IPP_OP_SEND_URI, IPP_OP_CUPS_NONE }; static const ipp_op_t ipp_set_printer[] = { IPP_OP_SET_PRINTER_ATTRIBUTES, IPP_OP_CUPS_ADD_MODIFY_PRINTER, IPP_OP_CUPS_ADD_MODIFY_CLASS, IPP_OP_CUPS_NONE }; static const ipp_op_t cups_schemes[] = { IPP_OP_CUPS_GET_DEVICES, IPP_OP_CUPS_GET_PPDS, IPP_OP_CUPS_NONE }; static const ipp_op_t cups_get_ppds[] = { IPP_OP_CUPS_GET_PPDS, IPP_OP_CUPS_NONE }; static const ipp_op_t cups_ppd_name[] = { IPP_OP_CUPS_ADD_MODIFY_PRINTER, IPP_OP_CUPS_GET_PPD, IPP_OP_CUPS_NONE }; static const _ipp_option_t ipp_options[] = { { 1, "auth-info", IPP_TAG_TEXT, IPP_TAG_JOB }, { 1, "auth-info-default", IPP_TAG_TEXT, IPP_TAG_PRINTER }, { 1, "auth-info-required", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, { 0, "blackplot", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, { 0, "blackplot-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, { 0, "brightness", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "brightness-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "columns", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "columns-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "compression", IPP_TAG_KEYWORD, IPP_TAG_OPERATION, IPP_TAG_ZERO, ipp_doc_creation }, { 0, "copies", IPP_TAG_INTEGER, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "copies-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "date-time-at-completed",IPP_TAG_DATE, IPP_TAG_ZERO }, /* never send as option */ { 0, "date-time-at-creation", IPP_TAG_DATE, IPP_TAG_ZERO }, /* never send as option */ { 0, "date-time-at-processing",IPP_TAG_DATE, IPP_TAG_ZERO }, /* never send as option */ { 0, "device-uri", IPP_TAG_URI, IPP_TAG_PRINTER }, { 1, "document-copies", IPP_TAG_RANGE, IPP_TAG_JOB, IPP_TAG_DOCUMENT, ipp_doc_creation }, { 0, "document-format", IPP_TAG_MIMETYPE, IPP_TAG_OPERATION, IPP_TAG_ZERO, ipp_doc_creation }, { 0, "document-format-default", IPP_TAG_MIMETYPE, IPP_TAG_PRINTER }, { 1, "document-numbers", IPP_TAG_RANGE, IPP_TAG_JOB, IPP_TAG_DOCUMENT, ipp_all_print }, { 1, "exclude-schemes", IPP_TAG_NAME, IPP_TAG_OPERATION, IPP_TAG_ZERO, cups_schemes }, { 1, "finishings", IPP_TAG_ENUM, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 1, "finishings-default", IPP_TAG_ENUM, IPP_TAG_PRINTER }, { 0, "fit-to-page", IPP_TAG_BOOLEAN, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "fit-to-page-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, { 0, "fitplot", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, { 0, "fitplot-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, { 0, "gamma", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "gamma-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "hue", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "hue-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 1, "include-schemes", IPP_TAG_NAME, IPP_TAG_OPERATION, IPP_TAG_ZERO, cups_schemes }, { 0, "job-account-id", IPP_TAG_NAME, IPP_TAG_JOB }, { 0, "job-account-id-default",IPP_TAG_NAME, IPP_TAG_PRINTER }, { 0, "job-accounting-user-id", IPP_TAG_NAME, IPP_TAG_JOB }, { 0, "job-accounting-user-id-default", IPP_TAG_NAME, IPP_TAG_PRINTER }, { 0, "job-authorization-uri", IPP_TAG_URI, IPP_TAG_OPERATION }, { 0, "job-cancel-after", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "job-cancel-after-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "job-hold-until", IPP_TAG_KEYWORD, IPP_TAG_JOB }, { 0, "job-id", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ { 0, "job-impressions", IPP_TAG_INTEGER, IPP_TAG_OPERATION }, { 0, "job-impressions-completed", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ { 0, "job-k-limit", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "job-k-octets", IPP_TAG_INTEGER, IPP_TAG_OPERATION }, { 0, "job-k-octets-completed",IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ { 0, "job-media-sheets", IPP_TAG_INTEGER, IPP_TAG_OPERATION }, { 0, "job-media-sheets-completed", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ { 0, "job-page-limit", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "job-pages", IPP_TAG_INTEGER, IPP_TAG_OPERATION }, { 0, "job-pages-completed", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ { 0, "job-password", IPP_TAG_STRING, IPP_TAG_OPERATION, IPP_TAG_ZERO, ipp_job_creation }, { 0, "job-password-encryption", IPP_TAG_KEYWORD, IPP_TAG_OPERATION, IPP_TAG_ZERO, ipp_job_creation }, { 0, "job-priority", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "job-quota-period", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 1, "job-sheets", IPP_TAG_NAME, IPP_TAG_JOB }, { 1, "job-sheets-default", IPP_TAG_NAME, IPP_TAG_PRINTER }, { 0, "job-state", IPP_TAG_ENUM, IPP_TAG_ZERO }, /* never send as option */ { 0, "job-state-message", IPP_TAG_TEXT, IPP_TAG_ZERO }, /* never send as option */ { 0, "job-state-reasons", IPP_TAG_KEYWORD, IPP_TAG_ZERO }, /* never send as option */ { 0, "job-uuid", IPP_TAG_URI, IPP_TAG_JOB }, { 0, "landscape", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, { 1, "marker-change-time", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 1, "marker-colors", IPP_TAG_NAME, IPP_TAG_PRINTER }, { 1, "marker-high-levels", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 1, "marker-levels", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 1, "marker-low-levels", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "marker-message", IPP_TAG_TEXT, IPP_TAG_PRINTER }, { 1, "marker-names", IPP_TAG_NAME, IPP_TAG_PRINTER }, { 1, "marker-types", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, { 1, "media", IPP_TAG_KEYWORD, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "media-bottom-margin", IPP_TAG_INTEGER, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "media-col", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "media-col-default", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_PRINTER }, { 0, "media-color", IPP_TAG_KEYWORD, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 1, "media-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, { 0, "media-key", IPP_TAG_KEYWORD, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "media-left-margin", IPP_TAG_INTEGER, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "media-right-margin", IPP_TAG_INTEGER, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "media-size", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "media-size-name", IPP_TAG_KEYWORD, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "media-source", IPP_TAG_KEYWORD, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "media-top-margin", IPP_TAG_INTEGER, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "media-type", IPP_TAG_KEYWORD, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "mirror", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, { 0, "mirror-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, { 0, "natural-scaling", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "natural-scaling-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "notify-charset", IPP_TAG_CHARSET, IPP_TAG_SUBSCRIPTION }, { 1, "notify-events", IPP_TAG_KEYWORD, IPP_TAG_SUBSCRIPTION }, { 1, "notify-events-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, { 0, "notify-lease-duration", IPP_TAG_INTEGER, IPP_TAG_SUBSCRIPTION }, { 0, "notify-lease-duration-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "notify-natural-language", IPP_TAG_LANGUAGE, IPP_TAG_SUBSCRIPTION }, { 0, "notify-pull-method", IPP_TAG_KEYWORD, IPP_TAG_SUBSCRIPTION }, { 0, "notify-recipient-uri", IPP_TAG_URI, IPP_TAG_SUBSCRIPTION }, { 0, "notify-time-interval", IPP_TAG_INTEGER, IPP_TAG_SUBSCRIPTION }, { 0, "notify-user-data", IPP_TAG_STRING, IPP_TAG_SUBSCRIPTION }, { 0, "number-up", IPP_TAG_INTEGER, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "number-up-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "orientation-requested", IPP_TAG_ENUM, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "orientation-requested-default", IPP_TAG_ENUM, IPP_TAG_PRINTER }, { 1, "overrides", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "page-bottom", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "page-bottom-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "page-left", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "page-left-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 1, "page-ranges", IPP_TAG_RANGE, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 1, "page-ranges-default", IPP_TAG_RANGE, IPP_TAG_PRINTER }, { 0, "page-right", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "page-right-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "page-top", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "page-top-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 1, "pages", IPP_TAG_RANGE, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "penwidth", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "penwidth-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "port-monitor", IPP_TAG_NAME, IPP_TAG_PRINTER }, { 0, "ppd-device-id", IPP_TAG_TEXT, IPP_TAG_OPERATION, IPP_TAG_ZERO, cups_get_ppds }, { 0, "ppd-make", IPP_TAG_TEXT, IPP_TAG_OPERATION, IPP_TAG_ZERO, cups_get_ppds }, { 0, "ppd-make-and-model", IPP_TAG_TEXT, IPP_TAG_OPERATION, IPP_TAG_ZERO, cups_get_ppds }, { 0, "ppd-model-number", IPP_TAG_INTEGER, IPP_TAG_OPERATION, IPP_TAG_ZERO, cups_get_ppds }, { 0, "ppd-name", IPP_TAG_NAME, IPP_TAG_OPERATION, IPP_TAG_ZERO, cups_ppd_name }, { 0, "ppd-natural-language", IPP_TAG_LANGUAGE, IPP_TAG_OPERATION, IPP_TAG_ZERO, cups_get_ppds }, { 0, "ppd-product", IPP_TAG_TEXT, IPP_TAG_OPERATION, IPP_TAG_ZERO, cups_get_ppds }, { 0, "ppd-psversion", IPP_TAG_TEXT, IPP_TAG_OPERATION, IPP_TAG_ZERO, cups_get_ppds }, { 0, "ppd-type", IPP_TAG_KEYWORD, IPP_TAG_OPERATION, IPP_TAG_ZERO, cups_get_ppds }, { 0, "ppi", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "ppi-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "prettyprint", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, { 0, "prettyprint-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, { 0, "print-quality", IPP_TAG_ENUM, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "print-quality-default", IPP_TAG_ENUM, IPP_TAG_PRINTER }, { 1, "printer-commands", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, { 0, "printer-error-policy", IPP_TAG_NAME, IPP_TAG_PRINTER }, { 0, "printer-geo-location", IPP_TAG_URI, IPP_TAG_PRINTER }, { 0, "printer-info", IPP_TAG_TEXT, IPP_TAG_PRINTER }, { 0, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, { 0, "printer-is-shared", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, { 0, "printer-is-temporary", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, { 0, "printer-location", IPP_TAG_TEXT, IPP_TAG_PRINTER }, { 0, "printer-make-and-model", IPP_TAG_TEXT, IPP_TAG_PRINTER }, { 0, "printer-more-info", IPP_TAG_URI, IPP_TAG_PRINTER }, { 0, "printer-op-policy", IPP_TAG_NAME, IPP_TAG_PRINTER }, { 0, "printer-resolution", IPP_TAG_RESOLUTION, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "printer-state", IPP_TAG_ENUM, IPP_TAG_PRINTER }, { 0, "printer-state-change-time", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 1, "printer-state-reasons", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, { 0, "printer-type", IPP_TAG_ENUM, IPP_TAG_PRINTER }, { 0, "printer-uri", IPP_TAG_URI, IPP_TAG_OPERATION }, { 1, "printer-uri-supported", IPP_TAG_URI, IPP_TAG_PRINTER }, { 0, "queued-job-count", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "raw", IPP_TAG_MIMETYPE, IPP_TAG_OPERATION }, { 1, "requested-attributes", IPP_TAG_NAME, IPP_TAG_OPERATION }, { 1, "requesting-user-name-allowed", IPP_TAG_NAME, IPP_TAG_PRINTER }, { 1, "requesting-user-name-denied", IPP_TAG_NAME, IPP_TAG_PRINTER }, { 0, "resolution", IPP_TAG_RESOLUTION, IPP_TAG_JOB }, { 0, "resolution-default", IPP_TAG_RESOLUTION, IPP_TAG_PRINTER }, { 0, "saturation", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "saturation-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "scaling", IPP_TAG_INTEGER, IPP_TAG_JOB }, { 0, "scaling-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, { 0, "sides", IPP_TAG_KEYWORD, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "sides-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, { 0, "time-at-completed", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ { 0, "time-at-creation", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ { 0, "time-at-processing", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ { 0, "wrap", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, { 0, "wrap-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, { 0, "x-dimension", IPP_TAG_INTEGER, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "y-dimension", IPP_TAG_INTEGER, IPP_TAG_JOB, IPP_TAG_DOCUMENT } }; /* * Local functions... */ static int compare_ipp_options(_ipp_option_t *a, _ipp_option_t *b); /* * '_cupsEncodeOption()' - Encode a single option as an IPP attribute. */ void _cupsEncodeOption( ipp_t *ipp, /* I - IPP request/response/collection */ ipp_tag_t group_tag, /* I - Group tag */ _ipp_option_t *map, /* I - Option mapping, if any */ const char *name, /* I - Attribute name */ const char *value) /* I - Value */ { int i, /* Looping var */ count; /* Number of values */ char *s, /* Pointer into option value */ *val, /* Pointer to option value */ *copy, /* Copy of option value */ *sep, /* Option separator */ quote; /* Quote character */ ipp_attribute_t *attr; /* IPP attribute */ ipp_tag_t value_tag; /* IPP value tag */ ipp_t *collection; /* Collection value */ int num_cols; /* Number of collection values */ cups_option_t *cols; /* Collection values */ DEBUG_printf(("_cupsEncodeOption(ipp=%p(%s), group=%s, map=%p, name=\"%s\", value=\"%s\")", (void *)ipp, ipp ? ippOpString(ippGetOperation(ipp)) : "", ippTagString(group_tag), (void *)map, name, value)); /* * Figure out the attribute syntax for encoding... */ if (!map) map = _ippFindOption(name); if (map) value_tag = map->value_tag; else if (!_cups_strcasecmp(value, "true") || !_cups_strcasecmp(value, "false")) value_tag = IPP_TAG_BOOLEAN; else if (value[0] == '{') value_tag = IPP_TAG_BEGIN_COLLECTION; else value_tag = IPP_TAG_NAME; /* * Count the number of values... */ if (map && map->multivalue) { for (count = 1, sep = (char *)value, quote = 0; *sep; sep ++) { if (*sep == quote) quote = 0; else if (!quote && (*sep == '\'' || *sep == '\"')) { /* * Skip quoted option value... */ quote = *sep; } else if (*sep == ',' && !quote) count ++; else if (*sep == '\\' && sep[1]) sep ++; } } else count = 1; DEBUG_printf(("2_cupsEncodeOption: value_tag=%s, count=%d", ippTagString(value_tag), count)); /* * Allocate memory for the attribute values... */ if ((attr = ippAddStrings(ipp, group_tag, value_tag, name, count, NULL, NULL)) == NULL) { /* * Ran out of memory! */ DEBUG_puts("1_cupsEncodeOption: Ran out of memory for attributes."); return; } if (count > 1) { /* * Make a copy of the value we can fiddle with... */ if ((copy = strdup(value)) == NULL) { /* * Ran out of memory! */ DEBUG_puts("1_cupsEncodeOption: Ran out of memory for value copy."); ippDeleteAttribute(ipp, attr); return; } val = copy; } else { /* * Since we have a single value, use the value directly... */ val = (char *)value; copy = NULL; } /* * Scan the value string for values... */ for (i = 0, sep = val; i < count; val = sep, i ++) { /* * Find the end of this value and mark it if needed... */ if (count > 1) { for (quote = 0; *sep; sep ++) { if (*sep == quote) { /* * Finish quoted value... */ quote = 0; } else if (!quote && (*sep == '\'' || *sep == '\"')) { /* * Handle quoted option value... */ quote = *sep; } else if (*sep == ',' && count > 1) break; else if (*sep == '\\' && sep[1]) { /* * Skip quoted character... */ memmove(sep, sep + 1, strlen(sep)); } } if (*sep == ',') *sep++ = '\0'; } /* * Copy the option value(s) over as needed by the type... */ switch (attr->value_tag) { case IPP_TAG_INTEGER : case IPP_TAG_ENUM : /* * Integer/enumeration value... */ ippSetInteger(ipp, &attr, i, (int)strtol(val, &s, 10)); break; case IPP_TAG_BOOLEAN : if (!_cups_strcasecmp(val, "true") || !_cups_strcasecmp(val, "on") || !_cups_strcasecmp(val, "yes")) { /* * Boolean value - true... */ ippSetBoolean(ipp, &attr, i, 1); } else { /* * Boolean value - false... */ ippSetBoolean(ipp, &attr, i, 0); } break; case IPP_TAG_RANGE : { /* * Range... */ int lower, upper; /* Lower and upper ranges... */ if (*val == '-') { lower = 1; s = val; } else lower = (int)strtol(val, &s, 10); if (*s == '-') { if (s[1]) upper = (int)strtol(s + 1, NULL, 10); else upper = 2147483647; } else upper = lower; ippSetRange(ipp, &attr, i, lower, upper); } break; case IPP_TAG_RESOLUTION : { /* * Resolution... */ int xres, yres; /* Resolution values */ ipp_res_t units; /* Resolution units */ xres = (int)strtol(val, &s, 10); if (*s == 'x') yres = (int)strtol(s + 1, &s, 10); else yres = xres; if (!_cups_strcasecmp(s, "dpc") || !_cups_strcasecmp(s, "dpcm")) units = IPP_RES_PER_CM; else units = IPP_RES_PER_INCH; ippSetResolution(ipp, &attr, i, units, xres, yres); } break; case IPP_TAG_STRING : /* * octetString */ ippSetOctetString(ipp, &attr, i, val, (int)strlen(val)); break; case IPP_TAG_BEGIN_COLLECTION : /* * Collection value */ num_cols = cupsParseOptions(val, 0, &cols); if ((collection = ippNew()) == NULL) { cupsFreeOptions(num_cols, cols); if (copy) free(copy); ippDeleteAttribute(ipp, attr); return; } ippSetCollection(ipp, &attr, i, collection); cupsEncodeOptions2(collection, num_cols, cols, IPP_TAG_JOB); cupsFreeOptions(num_cols, cols); break; default : ippSetString(ipp, &attr, i, val); break; } } if (copy) free(copy); } /* * 'cupsEncodeOptions()' - Encode printer options into IPP attributes. * * This function adds operation, job, and then subscription attributes, * in that order. Use the @link cupsEncodeOptions2@ function to add attributes * for a single group. */ void cupsEncodeOptions(ipp_t *ipp, /* I - Request to add to */ int num_options, /* I - Number of options */ cups_option_t *options) /* I - Options */ { DEBUG_printf(("cupsEncodeOptions(%p, %d, %p)", (void *)ipp, num_options, (void *)options)); /* * Add the options in the proper groups & order... */ cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_OPERATION); cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_JOB); cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_SUBSCRIPTION); } /* * 'cupsEncodeOptions2()' - Encode printer options into IPP attributes for a group. * * This function only adds attributes for a single group. Call this * function multiple times for each group, or use @link cupsEncodeOptions@ * to add the standard groups. * * @since CUPS 1.2/macOS 10.5@ */ void cupsEncodeOptions2( ipp_t *ipp, /* I - Request to add to */ int num_options, /* I - Number of options */ cups_option_t *options, /* I - Options */ ipp_tag_t group_tag) /* I - Group to encode */ { int i; /* Looping var */ char *val; /* Pointer to option value */ cups_option_t *option; /* Current option */ ipp_op_t op; /* Operation for this request */ const ipp_op_t *ops; /* List of allowed operations */ DEBUG_printf(("cupsEncodeOptions2(ipp=%p(%s), num_options=%d, options=%p, group_tag=%x)", (void *)ipp, ipp ? ippOpString(ippGetOperation(ipp)) : "", num_options, (void *)options, group_tag)); /* * Range check input... */ if (!ipp || num_options < 1 || !options) return; /* * Do special handling for the document-format/raw options... */ op = ippGetOperation(ipp); if (group_tag == IPP_TAG_OPERATION && (op == IPP_OP_PRINT_JOB || op == IPP_OP_PRINT_URI || op == IPP_OP_SEND_DOCUMENT || op == IPP_OP_SEND_URI)) { /* * Handle the document format stuff first... */ if ((val = (char *)cupsGetOption("document-format", num_options, options)) != NULL) ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, val); else if (cupsGetOption("raw", num_options, options)) ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, "application/vnd.cups-raw"); else ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, "application/octet-stream"); } /* * Then loop through the options... */ for (i = num_options, option = options; i > 0; i --, option ++) { _ipp_option_t *match; /* Matching attribute */ /* * Skip document format options that are handled above... */ if (!_cups_strcasecmp(option->name, "raw") || !_cups_strcasecmp(option->name, "document-format") || !option->name[0]) continue; /* * Figure out the proper value and group tags for this option... */ if ((match = _ippFindOption(option->name)) != NULL) { if (match->group_tag != group_tag && match->alt_group_tag != group_tag) continue; if (match->operations) ops = match->operations; else if (group_tag == IPP_TAG_JOB) ops = ipp_job_creation; else if (group_tag == IPP_TAG_DOCUMENT) ops = ipp_doc_creation; else if (group_tag == IPP_TAG_SUBSCRIPTION) ops = ipp_sub_creation; else if (group_tag == IPP_TAG_PRINTER) ops = ipp_set_printer; else { DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); continue; } } else { int namelen; /* Length of name */ namelen = (int)strlen(option->name); if (namelen < 10 || (strcmp(option->name + namelen - 8, "-default") && strcmp(option->name + namelen - 10, "-supported"))) { if (group_tag != IPP_TAG_JOB && group_tag != IPP_TAG_DOCUMENT) { DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); continue; } } else if (group_tag != IPP_TAG_PRINTER) { DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); continue; } if (group_tag == IPP_TAG_JOB) ops = ipp_job_creation; else if (group_tag == IPP_TAG_DOCUMENT) ops = ipp_doc_creation; else ops = ipp_set_printer; } /* * Verify that we send this attribute for this operation... */ while (*ops != IPP_OP_CUPS_NONE) if (op == *ops) break; else ops ++; if (*ops == IPP_OP_CUPS_NONE && op != IPP_OP_CUPS_NONE) { DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); continue; } _cupsEncodeOption(ipp, group_tag, match, option->name, option->value); } } #ifdef DEBUG /* * '_ippCheckOptions()' - Validate that the option array is sorted properly. */ const char * /* O - First out-of-order option or NULL */ _ippCheckOptions(void) { int i; /* Looping var */ for (i = 0; i < (int)(sizeof(ipp_options) / sizeof(ipp_options[0]) - 1); i ++) if (strcmp(ipp_options[i].name, ipp_options[i + 1].name) >= 0) return (ipp_options[i + 1].name); return (NULL); } #endif /* DEBUG */ /* * '_ippFindOption()' - Find the attribute information for an option. */ _ipp_option_t * /* O - Attribute information */ _ippFindOption(const char *name) /* I - Option/attribute name */ { _ipp_option_t key; /* Search key */ /* * Lookup the proper value and group tags for this option... */ key.name = name; return ((_ipp_option_t *)bsearch(&key, ipp_options, sizeof(ipp_options) / sizeof(ipp_options[0]), sizeof(ipp_options[0]), (int (*)(const void *, const void *)) compare_ipp_options)); } /* * 'compare_ipp_options()' - Compare two IPP options. */ static int /* O - Result of comparison */ compare_ipp_options(_ipp_option_t *a, /* I - First option */ _ipp_option_t *b) /* I - Second option */ { return (strcmp(a->name, b->name)); } ippsample/cups/cups.h0000644000175000017500000006130313240604116013637 0ustar tilltill/* * API definitions for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_CUPS_H_ # define _CUPS_CUPS_H_ /* * Include necessary headers... */ # include # if defined(WIN32) && !defined(__CUPS_SSIZE_T_DEFINED) # define __CUPS_SSIZE_T_DEFINED # include /* Windows does not support the ssize_t type, so map it to long... */ typedef long ssize_t; /* @private@ */ # endif /* WIN32 && !__CUPS_SSIZE_T_DEFINED */ # include "file.h" # include "ipp.h" # include "language.h" # include "pwg.h" /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Constants... */ # define CUPS_VERSION 2.0300 # define CUPS_VERSION_MAJOR 2 # define CUPS_VERSION_MINOR 3 # define CUPS_VERSION_PATCH 0 # define CUPS_BC_FD 3 /* Back-channel file descriptor for * select/poll */ # define CUPS_DATE_ANY (time_t)-1 # define CUPS_EXCLUDE_NONE (const char *)0 # define CUPS_FORMAT_AUTO "application/octet-stream" # define CUPS_FORMAT_COMMAND "application/vnd.cups-command" # define CUPS_FORMAT_JPEG "image/jpeg" # define CUPS_FORMAT_PDF "application/pdf" # define CUPS_FORMAT_POSTSCRIPT "application/postscript" # define CUPS_FORMAT_RAW "application/vnd.cups-raw" # define CUPS_FORMAT_TEXT "text/plain" # define CUPS_HTTP_DEFAULT (http_t *)0 # define CUPS_INCLUDE_ALL (const char *)0 # define CUPS_JOBID_ALL -1 # define CUPS_JOBID_CURRENT 0 # define CUPS_LENGTH_VARIABLE (ssize_t)0 # define CUPS_TIMEOUT_DEFAULT 0 # define CUPS_WHICHJOBS_ALL -1 # define CUPS_WHICHJOBS_ACTIVE 0 # define CUPS_WHICHJOBS_COMPLETED 1 /* Flags for cupsConnectDest and cupsEnumDests */ # define CUPS_DEST_FLAGS_NONE 0x00 /* No flags are set */ # define CUPS_DEST_FLAGS_UNCONNECTED 0x01 /* There is no connection */ # define CUPS_DEST_FLAGS_MORE 0x02 /* There are more destinations */ # define CUPS_DEST_FLAGS_REMOVED 0x04 /* The destination has gone away */ # define CUPS_DEST_FLAGS_ERROR 0x08 /* An error occurred */ # define CUPS_DEST_FLAGS_RESOLVING 0x10 /* The destination address is being * resolved */ # define CUPS_DEST_FLAGS_CONNECTING 0x20 /* A connection is being established */ # define CUPS_DEST_FLAGS_CANCELED 0x40 /* Operation was canceled */ # define CUPS_DEST_FLAGS_DEVICE 0x80 /* For @link cupsConnectDest@: Connect to device */ /* Flags for cupsGetDestMediaByName/Size */ # define CUPS_MEDIA_FLAGS_DEFAULT 0x00 /* Find the closest size supported by * the printer */ # define CUPS_MEDIA_FLAGS_BORDERLESS 0x01 /* Find a borderless size */ # define CUPS_MEDIA_FLAGS_DUPLEX 0x02 /* Find a size compatible with 2-sided * printing */ # define CUPS_MEDIA_FLAGS_EXACT 0x04 /* Find an exact match for the size */ # define CUPS_MEDIA_FLAGS_READY 0x08 /* If the printer supports media * sensing, find the size amongst the * "ready" media. */ /* Options and values */ # define CUPS_COPIES "copies" # define CUPS_COPIES_SUPPORTED "copies-supported" # define CUPS_FINISHINGS "finishings" # define CUPS_FINISHINGS_SUPPORTED "finishings-supported" # define CUPS_FINISHINGS_BIND "7" # define CUPS_FINISHINGS_COVER "6" # define CUPS_FINISHINGS_FOLD "10" # define CUPS_FINISHINGS_NONE "3" # define CUPS_FINISHINGS_PUNCH "5" # define CUPS_FINISHINGS_STAPLE "4" # define CUPS_FINISHINGS_TRIM "11" # define CUPS_MEDIA "media" # define CUPS_MEDIA_READY "media-ready" # define CUPS_MEDIA_SUPPORTED "media-supported" # define CUPS_MEDIA_3X5 "na_index-3x5_3x5in" # define CUPS_MEDIA_4X6 "na_index-4x6_4x6in" # define CUPS_MEDIA_5X7 "na_5x7_5x7in" # define CUPS_MEDIA_8X10 "na_govt-letter_8x10in" # define CUPS_MEDIA_A3 "iso_a3_297x420mm" # define CUPS_MEDIA_A4 "iso_a4_210x297mm" # define CUPS_MEDIA_A5 "iso_a5_148x210mm" # define CUPS_MEDIA_A6 "iso_a6_105x148mm" # define CUPS_MEDIA_ENV10 "na_number-10_4.125x9.5in" # define CUPS_MEDIA_ENVDL "iso_dl_110x220mm" # define CUPS_MEDIA_LEGAL "na_legal_8.5x14in" # define CUPS_MEDIA_LETTER "na_letter_8.5x11in" # define CUPS_MEDIA_PHOTO_L "oe_photo-l_3.5x5in" # define CUPS_MEDIA_SUPERBA3 "na_super-b_13x19in" # define CUPS_MEDIA_TABLOID "na_ledger_11x17in" # define CUPS_MEDIA_SOURCE "media-source" # define CUPS_MEDIA_SOURCE_SUPPORTED "media-source-supported" # define CUPS_MEDIA_SOURCE_AUTO "auto" # define CUPS_MEDIA_SOURCE_MANUAL "manual" # define CUPS_MEDIA_TYPE "media-type" # define CUPS_MEDIA_TYPE_SUPPORTED "media-type-supported" # define CUPS_MEDIA_TYPE_AUTO "auto" # define CUPS_MEDIA_TYPE_ENVELOPE "envelope" # define CUPS_MEDIA_TYPE_LABELS "labels" # define CUPS_MEDIA_TYPE_LETTERHEAD "stationery-letterhead" # define CUPS_MEDIA_TYPE_PHOTO "photographic" # define CUPS_MEDIA_TYPE_PHOTO_GLOSSY "photographic-glossy" # define CUPS_MEDIA_TYPE_PHOTO_MATTE "photographic-matte" # define CUPS_MEDIA_TYPE_PLAIN "stationery" # define CUPS_MEDIA_TYPE_TRANSPARENCY "transparency" # define CUPS_NUMBER_UP "number-up" # define CUPS_NUMBER_UP_SUPPORTED "number-up-supported" # define CUPS_ORIENTATION "orientation-requested" # define CUPS_ORIENTATION_SUPPORTED "orientation-requested-supported" # define CUPS_ORIENTATION_PORTRAIT "3" # define CUPS_ORIENTATION_LANDSCAPE "4" # define CUPS_PRINT_COLOR_MODE "print-color-mode" # define CUPS_PRINT_COLOR_MODE_SUPPORTED "print-color-mode-supported" # define CUPS_PRINT_COLOR_MODE_AUTO "auto" # define CUPS_PRINT_COLOR_MODE_MONOCHROME "monochrome" # define CUPS_PRINT_COLOR_MODE_COLOR "color" # define CUPS_PRINT_QUALITY "print-quality" # define CUPS_PRINT_QUALITY_SUPPORTED "print-quality-supported" # define CUPS_PRINT_QUALITY_DRAFT "3" # define CUPS_PRINT_QUALITY_NORMAL "4" # define CUPS_PRINT_QUALITY_HIGH "5" # define CUPS_SIDES "sides" # define CUPS_SIDES_SUPPORTED "sides-supported" # define CUPS_SIDES_ONE_SIDED "one-sided" # define CUPS_SIDES_TWO_SIDED_PORTRAIT "two-sided-long-edge" # define CUPS_SIDES_TWO_SIDED_LANDSCAPE "two-sided-short-edge" /* * Types and structures... */ typedef unsigned cups_ptype_t; /* Printer type/capability bits */ enum cups_ptype_e /* Printer type/capability bit * constants */ { /* Not a typedef'd enum so we can OR */ CUPS_PRINTER_LOCAL = 0x0000, /* Local printer or class */ CUPS_PRINTER_CLASS = 0x0001, /* Printer class */ CUPS_PRINTER_REMOTE = 0x0002, /* Remote printer or class */ CUPS_PRINTER_BW = 0x0004, /* Can do B&W printing */ CUPS_PRINTER_COLOR = 0x0008, /* Can do color printing */ CUPS_PRINTER_DUPLEX = 0x0010, /* Can do two-sided printing */ CUPS_PRINTER_STAPLE = 0x0020, /* Can staple output */ CUPS_PRINTER_COPIES = 0x0040, /* Can do copies in hardware */ CUPS_PRINTER_COLLATE = 0x0080, /* Can quickly collate copies */ CUPS_PRINTER_PUNCH = 0x0100, /* Can punch output */ CUPS_PRINTER_COVER = 0x0200, /* Can cover output */ CUPS_PRINTER_BIND = 0x0400, /* Can bind output */ CUPS_PRINTER_SORT = 0x0800, /* Can sort output */ CUPS_PRINTER_SMALL = 0x1000, /* Can print on Letter/Legal/A4-size media */ CUPS_PRINTER_MEDIUM = 0x2000, /* Can print on Tabloid/B/C/A3/A2-size media */ CUPS_PRINTER_LARGE = 0x4000, /* Can print on D/E/A1/A0-size media */ CUPS_PRINTER_VARIABLE = 0x8000, /* Can print on rolls and custom-size media */ CUPS_PRINTER_IMPLICIT = 0x10000, /* Implicit class @private@ * @since Deprecated@ */ CUPS_PRINTER_DEFAULT = 0x20000, /* Default printer on network */ CUPS_PRINTER_FAX = 0x40000, /* Fax queue */ CUPS_PRINTER_REJECTING = 0x80000, /* Printer is rejecting jobs */ CUPS_PRINTER_DELETE = 0x100000, /* Delete printer * @deprecated@ @exclude all@ */ CUPS_PRINTER_NOT_SHARED = 0x200000, /* Printer is not shared * @since CUPS 1.2/macOS 10.5@ */ CUPS_PRINTER_AUTHENTICATED = 0x400000,/* Printer requires authentication * @since CUPS 1.2/macOS 10.5@ */ CUPS_PRINTER_COMMANDS = 0x800000, /* Printer supports maintenance commands * @since CUPS 1.2/macOS 10.5@ */ CUPS_PRINTER_DISCOVERED = 0x1000000, /* Printer was discovered @since CUPS 1.2/macOS 10.5@ */ CUPS_PRINTER_SCANNER = 0x2000000, /* Scanner-only device * @since CUPS 1.4/macOS 10.6@ @private@ */ CUPS_PRINTER_MFP = 0x4000000, /* Printer with scanning capabilities * @since CUPS 1.4/macOS 10.6@ @private@ */ CUPS_PRINTER_3D = 0x8000000, /* Printer with 3D capabilities @exclude all@ @private@ */ CUPS_PRINTER_OPTIONS = 0x6fffc /* ~(CLASS | REMOTE | IMPLICIT | * DEFAULT | FAX | REJECTING | DELETE | * NOT_SHARED | AUTHENTICATED | * COMMANDS | DISCOVERED) @private@ */ }; typedef struct cups_option_s /**** Printer Options ****/ { char *name; /* Name of option */ char *value; /* Value of option */ } cups_option_t; typedef struct cups_dest_s /**** Destination ****/ { char *name, /* Printer or class name */ *instance; /* Local instance name or NULL */ int is_default; /* Is this printer the default? */ int num_options; /* Number of options */ cups_option_t *options; /* Options */ } cups_dest_t; typedef struct _cups_dinfo_s cups_dinfo_t; /* Destination capability and status * information @since CUPS 1.6/macOS 10.8@ */ typedef struct cups_job_s /**** Job ****/ { int id; /* The job ID */ char *dest; /* Printer or class name */ char *title; /* Title/job name */ char *user; /* User that submitted the job */ char *format; /* Document format */ ipp_jstate_t state; /* Job state */ int size; /* Size in kilobytes */ int priority; /* Priority (1-100) */ time_t completed_time; /* Time the job was completed */ time_t creation_time; /* Time the job was created */ time_t processing_time; /* Time the job was processed */ } cups_job_t; typedef struct cups_size_s /**** Media Size @since CUPS 1.6/macOS 10.8@ ****/ { char media[128]; /* Media name to use */ int width, /* Width in hundredths of millimeters */ length, /* Length in hundredths of * millimeters */ bottom, /* Bottom margin in hundredths of * millimeters */ left, /* Left margin in hundredths of * millimeters */ right, /* Right margin in hundredths of * millimeters */ top; /* Top margin in hundredths of * millimeters */ } cups_size_t; typedef int (*cups_client_cert_cb_t)(http_t *http, void *tls, cups_array_t *distinguished_names, void *user_data); /* Client credentials callback * @since CUPS 1.5/macOS 10.7@ */ typedef int (*cups_dest_cb_t)(void *user_data, unsigned flags, cups_dest_t *dest); /* Destination enumeration callback * @since CUPS 1.6/macOS 10.8@ */ # ifdef __BLOCKS__ typedef int (^cups_dest_block_t)(unsigned flags, cups_dest_t *dest); /* Destination enumeration block * @since CUPS 1.6/macOS 10.8@ * @exclude all@ */ # endif /* __BLOCKS__ */ typedef const char *(*cups_password_cb_t)(const char *prompt); /* Password callback @exclude all@ */ typedef const char *(*cups_password_cb2_t)(const char *prompt, http_t *http, const char *method, const char *resource, void *user_data); /* New password callback * @since CUPS 1.4/macOS 10.6@ */ typedef int (*cups_server_cert_cb_t)(http_t *http, void *tls, cups_array_t *certs, void *user_data); /* Server credentials callback * @since CUPS 1.5/macOS 10.7@ */ /* * Functions... */ extern int cupsCancelJob(const char *name, int job_id); extern ipp_t *cupsDoFileRequest(http_t *http, ipp_t *request, const char *resource, const char *filename); extern ipp_t *cupsDoRequest(http_t *http, ipp_t *request, const char *resource); extern http_encryption_t cupsEncryption(void); extern void cupsFreeJobs(int num_jobs, cups_job_t *jobs); extern int cupsGetClasses(char ***classes) _CUPS_DEPRECATED_MSG("Use cupsEnumDests instead."); extern const char *cupsGetDefault(void); extern int cupsGetJobs(cups_job_t **jobs, const char *name, int myjobs, int whichjobs); extern int cupsGetPrinters(char ***printers) _CUPS_DEPRECATED_MSG("Use cupsEnumDests instead."); extern ipp_status_t cupsLastError(void); extern int cupsPrintFile(const char *name, const char *filename, const char *title, int num_options, cups_option_t *options); extern int cupsPrintFiles(const char *name, int num_files, const char **files, const char *title, int num_options, cups_option_t *options); extern char *cupsTempFile(char *filename, int len) _CUPS_DEPRECATED_MSG("Use cupsTempFd or cupsTempFile2 instead."); extern int cupsTempFd(char *filename, int len); extern int cupsAddDest(const char *name, const char *instance, int num_dests, cups_dest_t **dests); extern void cupsFreeDests(int num_dests, cups_dest_t *dests); extern cups_dest_t *cupsGetDest(const char *name, const char *instance, int num_dests, cups_dest_t *dests); extern int cupsGetDests(cups_dest_t **dests); extern void cupsSetDests(int num_dests, cups_dest_t *dests); extern int cupsAddOption(const char *name, const char *value, int num_options, cups_option_t **options); extern void cupsEncodeOptions(ipp_t *ipp, int num_options, cups_option_t *options); extern void cupsFreeOptions(int num_options, cups_option_t *options); extern const char *cupsGetOption(const char *name, int num_options, cups_option_t *options); extern int cupsParseOptions(const char *arg, int num_options, cups_option_t **options); extern const char *cupsGetPassword(const char *prompt); extern const char *cupsServer(void); extern void cupsSetEncryption(http_encryption_t e); extern void cupsSetPasswordCB(cups_password_cb_t cb); extern void cupsSetServer(const char *server); extern void cupsSetUser(const char *user); extern const char *cupsUser(void); /**** New in CUPS 1.1.20 ****/ extern int cupsDoAuthentication(http_t *http, const char *method, const char *resource) _CUPS_API_1_1_20; extern http_status_t cupsGetFile(http_t *http, const char *resource, const char *filename) _CUPS_API_1_1_20; extern http_status_t cupsGetFd(http_t *http, const char *resource, int fd); extern http_status_t cupsPutFile(http_t *http, const char *resource, const char *filename) _CUPS_API_1_1_20; extern http_status_t cupsPutFd(http_t *http, const char *resource, int fd) _CUPS_API_1_1_20; /**** New in CUPS 1.1.21 ****/ extern const char *cupsGetDefault2(http_t *http) _CUPS_API_1_1_21; extern int cupsGetDests2(http_t *http, cups_dest_t **dests) _CUPS_API_1_1_21; extern int cupsGetJobs2(http_t *http, cups_job_t **jobs, const char *name, int myjobs, int whichjobs) _CUPS_API_1_1_21; extern int cupsPrintFile2(http_t *http, const char *name, const char *filename, const char *title, int num_options, cups_option_t *options) _CUPS_API_1_1_21; extern int cupsPrintFiles2(http_t *http, const char *name, int num_files, const char **files, const char *title, int num_options, cups_option_t *options) _CUPS_API_1_1_21; extern int cupsSetDests2(http_t *http, int num_dests, cups_dest_t *dests) _CUPS_API_1_1_21; /**** New in CUPS 1.2/macOS 10.5 ****/ extern ssize_t cupsBackChannelRead(char *buffer, size_t bytes, double timeout) _CUPS_API_1_2; extern ssize_t cupsBackChannelWrite(const char *buffer, size_t bytes, double timeout) _CUPS_API_1_2; extern void cupsEncodeOptions2(ipp_t *ipp, int num_options, cups_option_t *options, ipp_tag_t group_tag) _CUPS_API_1_2; extern const char *cupsLastErrorString(void) _CUPS_API_1_2; extern char *cupsNotifySubject(cups_lang_t *lang, ipp_t *event) _CUPS_API_1_2; extern char *cupsNotifyText(cups_lang_t *lang, ipp_t *event) _CUPS_API_1_2; extern int cupsRemoveOption(const char *name, int num_options, cups_option_t **options) _CUPS_API_1_2; extern cups_file_t *cupsTempFile2(char *filename, int len) _CUPS_API_1_2; /**** New in CUPS 1.3/macOS 10.5 ****/ extern ipp_t *cupsDoIORequest(http_t *http, ipp_t *request, const char *resource, int infile, int outfile) _CUPS_API_1_3; extern int cupsRemoveDest(const char *name, const char *instance, int num_dests, cups_dest_t **dests) _CUPS_API_1_3; extern void cupsSetDefaultDest(const char *name, const char *instance, int num_dests, cups_dest_t *dests) _CUPS_API_1_3; /**** New in CUPS 1.4/macOS 10.6 ****/ extern ipp_status_t cupsCancelJob2(http_t *http, const char *name, int job_id, int purge) _CUPS_API_1_4; extern int cupsCreateJob(http_t *http, const char *name, const char *title, int num_options, cups_option_t *options) _CUPS_API_1_4; extern ipp_status_t cupsFinishDocument(http_t *http, const char *name) _CUPS_API_1_4; extern cups_dest_t *cupsGetNamedDest(http_t *http, const char *name, const char *instance) _CUPS_API_1_4; extern const char *cupsGetPassword2(const char *prompt, http_t *http, const char *method, const char *resource) _CUPS_API_1_4; extern ipp_t *cupsGetResponse(http_t *http, const char *resource) _CUPS_API_1_4; extern ssize_t cupsReadResponseData(http_t *http, char *buffer, size_t length) _CUPS_API_1_4; extern http_status_t cupsSendRequest(http_t *http, ipp_t *request, const char *resource, size_t length) _CUPS_API_1_4; extern void cupsSetPasswordCB2(cups_password_cb2_t cb, void *user_data) _CUPS_API_1_4; extern http_status_t cupsStartDocument(http_t *http, const char *name, int job_id, const char *docname, const char *format, int last_document) _CUPS_API_1_4; extern http_status_t cupsWriteRequestData(http_t *http, const char *buffer, size_t length) _CUPS_API_1_4; /**** New in CUPS 1.5/macOS 10.7 ****/ extern void cupsSetClientCertCB(cups_client_cert_cb_t cb, void *user_data) _CUPS_API_1_5; extern int cupsSetCredentials(cups_array_t *certs) _CUPS_API_1_5; extern void cupsSetServerCertCB(cups_server_cert_cb_t cb, void *user_data) _CUPS_API_1_5; /**** New in CUPS 1.6/macOS 10.8 ****/ extern ipp_status_t cupsCancelDestJob(http_t *http, cups_dest_t *dest, int job_id) _CUPS_API_1_6; extern int cupsCheckDestSupported(http_t *http, cups_dest_t *dest, cups_dinfo_t *info, const char *option, const char *value) _CUPS_API_1_6; extern ipp_status_t cupsCloseDestJob(http_t *http, cups_dest_t *dest, cups_dinfo_t *info, int job_id) _CUPS_API_1_6; extern http_t *cupsConnectDest(cups_dest_t *dest, unsigned flags, int msec, int *cancel, char *resource, size_t resourcesize, cups_dest_cb_t cb, void *user_data) _CUPS_API_1_6; # ifdef __BLOCKS__ extern http_t *cupsConnectDestBlock(cups_dest_t *dest, unsigned flags, int msec, int *cancel, char *resource, size_t resourcesize, cups_dest_block_t block) _CUPS_API_1_6; # endif /* __BLOCKS__ */ extern int cupsCopyDest(cups_dest_t *dest, int num_dests, cups_dest_t **dests) _CUPS_API_1_6; extern cups_dinfo_t *cupsCopyDestInfo(http_t *http, cups_dest_t *dest) _CUPS_API_1_6; extern int cupsCopyDestConflicts(http_t *http, cups_dest_t *dest, cups_dinfo_t *info, int num_options, cups_option_t *options, const char *new_option, const char *new_value, int *num_conflicts, cups_option_t **conflicts, int *num_resolved, cups_option_t **resolved) _CUPS_API_1_6; extern ipp_status_t cupsCreateDestJob(http_t *http, cups_dest_t *dest, cups_dinfo_t *info, int *job_id, const char *title, int num_options, cups_option_t *options) _CUPS_API_1_6; extern int cupsEnumDests(unsigned flags, int msec, int *cancel, cups_ptype_t type, cups_ptype_t mask, cups_dest_cb_t cb, void *user_data) _CUPS_API_1_6; # ifdef __BLOCKS__ extern int cupsEnumDestsBlock(unsigned flags, int msec, int *cancel, cups_ptype_t type, cups_ptype_t mask, cups_dest_block_t block) _CUPS_API_1_6; # endif /* __BLOCKS__ */ extern ipp_status_t cupsFinishDestDocument(http_t *http, cups_dest_t *dest, cups_dinfo_t *info) _CUPS_API_1_6; extern void cupsFreeDestInfo(cups_dinfo_t *dinfo) _CUPS_API_1_6; extern int cupsGetDestMediaByName(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *media, unsigned flags, cups_size_t *size) _CUPS_API_1_6; extern int cupsGetDestMediaBySize(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, int width, int length, unsigned flags, cups_size_t *size) _CUPS_API_1_6; extern const char *cupsLocalizeDestOption(http_t *http, cups_dest_t *dest, cups_dinfo_t *info, const char *option) _CUPS_API_1_6; extern const char *cupsLocalizeDestValue(http_t *http, cups_dest_t *dest, cups_dinfo_t *info, const char *option, const char *value) _CUPS_API_1_6; extern http_status_t cupsStartDestDocument(http_t *http, cups_dest_t *dest, cups_dinfo_t *info, int job_id, const char *docname, const char *format, int num_options, cups_option_t *options, int last_document) _CUPS_API_1_6; /* New in CUPS 1.7 */ extern ipp_attribute_t *cupsFindDestDefault(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option) _CUPS_API_1_7; extern ipp_attribute_t *cupsFindDestReady(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option) _CUPS_API_1_7; extern ipp_attribute_t *cupsFindDestSupported(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option) _CUPS_API_1_7; extern int cupsGetDestMediaByIndex(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, int n, unsigned flags, cups_size_t *size) _CUPS_API_1_7; extern int cupsGetDestMediaCount(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, unsigned flags) _CUPS_API_1_7; extern int cupsGetDestMediaDefault(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, unsigned flags, cups_size_t *size) _CUPS_API_1_7; extern void cupsSetUserAgent(const char *user_agent) _CUPS_API_1_7; extern const char *cupsUserAgent(void) _CUPS_API_1_7; /* New in CUPS 2.0/macOS 10.10 */ extern cups_dest_t *cupsGetDestWithURI(const char *name, const char *uri) _CUPS_API_2_0; extern const char *cupsLocalizeDestMedia(http_t *http, cups_dest_t *dest, cups_dinfo_t *info, unsigned flags, cups_size_t *size) _CUPS_API_2_0; extern int cupsMakeServerCredentials(const char *path, const char *common_name, int num_alt_names, const char **alt_names, time_t expiration_date) _CUPS_API_2_0; extern int cupsSetServerCredentials(const char *path, const char *common_name, int auto_create) _CUPS_API_2_0; /* New in CUPS 2.2/macOS 10.12 */ extern ssize_t cupsHashData(const char *algorithm, const void *data, size_t datalen, unsigned char *hash, size_t hashsize) _CUPS_API_2_2; /* New in CUPS 2.2.4 */ extern int cupsAddIntegerOption(const char *name, int value, int num_options, cups_option_t **options) _CUPS_API_2_2_4; extern int cupsGetIntegerOption(const char *name, int num_options, cups_option_t *options) _CUPS_API_2_2_4; /* New in CUPS 2.3 */ extern int cupsAddDestMediaOptions(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, unsigned flags, cups_size_t *size, int num_options, cups_option_t **options); extern const char *cupsHashString(const unsigned char *hash, size_t hashsize, char *buffer, size_t bufsize) _CUPS_API_2_3; # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_CUPS_H_ */ ippsample/cups/tls-darwin.c0000644000175000017500000017130413240604116014747 0ustar tilltill/* * TLS support code for CUPS on macOS. * * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /**** This file is included from tls.c ****/ /* * Include necessary headers... */ #include extern char **environ; /* @private@ */ /* * Constants, very secure stuff... */ #define _CUPS_CDSA_PASSWORD "42" /* CUPS keychain password */ #define _CUPS_CDSA_PASSLEN 2 /* Length of keychain password */ /* * Local globals... */ static int tls_auto_create = 0; /* Auto-create self-signed certs? */ static char *tls_common_name = NULL; /* Default common name */ #ifdef HAVE_SECKEYCHAINOPEN static int tls_cups_keychain = 0; /* Opened the CUPS keychain? */ static SecKeychainRef tls_keychain = NULL; /* Server cert keychain */ #else static SecIdentityRef tls_selfsigned = NULL; /* Temporary self-signed cert */ #endif /* HAVE_SECKEYCHAINOPEN */ static char *tls_keypath = NULL; /* Server cert keychain path */ static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER; /* Mutex for keychain/certs */ static int tls_options = -1,/* Options for TLS connections */ tls_min_version = _HTTP_TLS_1_0, tls_max_version = _HTTP_TLS_MAX; /* * Local functions... */ static CFArrayRef http_cdsa_copy_server(const char *common_name); static SecCertificateRef http_cdsa_create_credential(http_credential_t *credential); #ifdef HAVE_SECKEYCHAINOPEN static const char *http_cdsa_default_path(char *buffer, size_t bufsize); static SecKeychainRef http_cdsa_open_keychain(const char *path, char *filename, size_t filesize); static SecKeychainRef http_cdsa_open_system_keychain(void); #endif /* HAVE_SECKEYCHAINOPEN */ static OSStatus http_cdsa_read(SSLConnectionRef connection, void *data, size_t *dataLength); static int http_cdsa_set_credentials(http_t *http); static OSStatus http_cdsa_write(SSLConnectionRef connection, const void *data, size_t *dataLength); /* * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 1 on success, 0 on failure */ cupsMakeServerCredentials( const char *path, /* I - Keychain path or @code NULL@ for default */ const char *common_name, /* I - Common name */ int num_alt_names, /* I - Number of subject alternate names */ const char **alt_names, /* I - Subject Alternate Names */ time_t expiration_date) /* I - Expiration date */ { #if defined(HAVE_SECGENERATESELFSIGNEDCERTIFICATE) int status = 0; /* Return status */ OSStatus err; /* Error code (if any) */ CFStringRef cfcommon_name = NULL; /* CF string for server name */ SecIdentityRef ident = NULL; /* Identity */ SecKeyRef publicKey = NULL, /* Public key */ privateKey = NULL; /* Private key */ SecCertificateRef cert = NULL; /* Self-signed certificate */ CFMutableDictionaryRef keyParams = NULL; /* Key generation parameters */ DEBUG_printf(("cupsMakeServerCredentials(path=\"%s\", common_name=\"%s\", num_alt_names=%d, alt_names=%p, expiration_date=%d)", path, common_name, num_alt_names, alt_names, (int)expiration_date)); (void)path; (void)num_alt_names; (void)alt_names; (void)expiration_date; if (path) { DEBUG_puts("1cupsMakeServerCredentials: No keychain support compiled in, returning 0."); return (0); } if (tls_selfsigned) { DEBUG_puts("1cupsMakeServerCredentials: Using existing self-signed cert."); return (1); } cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name, kCFStringEncodingUTF8); if (!cfcommon_name) { DEBUG_puts("1cupsMakeServerCredentials: Unable to create CF string of common name."); goto cleanup; } /* * Create a public/private key pair... */ keyParams = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (!keyParams) { DEBUG_puts("1cupsMakeServerCredentials: Unable to create key parameters dictionary."); goto cleanup; } CFDictionaryAddValue(keyParams, kSecAttrKeyType, kSecAttrKeyTypeRSA); CFDictionaryAddValue(keyParams, kSecAttrKeySizeInBits, CFSTR("2048")); CFDictionaryAddValue(keyParams, kSecAttrLabel, cfcommon_name); err = SecKeyGeneratePair(keyParams, &publicKey, &privateKey); if (err != noErr) { DEBUG_printf(("1cupsMakeServerCredentials: Unable to generate key pair: %d.", (int)err)); goto cleanup; } /* * Create a self-signed certificate using the public/private key pair... */ CFIndex usageInt = kSecKeyUsageAll; CFNumberRef usage = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &usageInt); CFIndex lenInt = 0; CFNumberRef len = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &lenInt); CFTypeRef certKeys[] = { kSecCSRBasicContraintsPathLen, kSecSubjectAltName, kSecCertificateKeyUsage }; CFTypeRef certValues[] = { len, cfcommon_name, usage }; CFDictionaryRef certParams = CFDictionaryCreate(kCFAllocatorDefault, certKeys, certValues, sizeof(certKeys) / sizeof(certKeys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFRelease(usage); CFRelease(len); const void *ca_o[] = { kSecOidOrganization, CFSTR("") }; const void *ca_cn[] = { kSecOidCommonName, cfcommon_name }; CFArrayRef ca_o_dn = CFArrayCreate(kCFAllocatorDefault, ca_o, 2, NULL); CFArrayRef ca_cn_dn = CFArrayCreate(kCFAllocatorDefault, ca_cn, 2, NULL); const void *ca_dn_array[2]; ca_dn_array[0] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_o_dn, 1, NULL); ca_dn_array[1] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_cn_dn, 1, NULL); CFArrayRef subject = CFArrayCreate(kCFAllocatorDefault, ca_dn_array, 2, NULL); cert = SecGenerateSelfSignedCertificate(subject, certParams, publicKey, privateKey); CFRelease(subject); CFRelease(certParams); if (!cert) { DEBUG_puts("1cupsMakeServerCredentials: Unable to create self-signed certificate."); goto cleanup; } ident = SecIdentityCreate(kCFAllocatorDefault, cert, privateKey); if (ident) { _cupsMutexLock(&tls_mutex); if (tls_selfsigned) CFRelease(ident); else tls_selfsigned = ident; _cupsMutexLock(&tls_mutex); # if 0 /* Someday perhaps SecItemCopyMatching will work for identities, at which point */ CFTypeRef itemKeys[] = { kSecClass, kSecAttrLabel, kSecValueRef }; CFTypeRef itemValues[] = { kSecClassIdentity, cfcommon_name, ident }; CFDictionaryRef itemAttrs = CFDictionaryCreate(kCFAllocatorDefault, itemKeys, itemValues, sizeof(itemKeys) / sizeof(itemKeys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); err = SecItemAdd(itemAttrs, NULL); /* SecItemAdd consumes itemAttrs... */ CFRelease(ident); if (err != noErr) { DEBUG_printf(("1cupsMakeServerCredentials: Unable to add identity to keychain: %d.", (int)err)); goto cleanup; } # endif /* 0 */ status = 1; } else DEBUG_puts("1cupsMakeServerCredentials: Unable to create identity from cert and keys."); /* * Cleanup and return... */ cleanup: if (cfcommon_name) CFRelease(cfcommon_name); if (keyParams) CFRelease(keyParams); if (cert) CFRelease(cert); if (publicKey) CFRelease(publicKey); if (privateKey) CFRelease(privateKey); DEBUG_printf(("1cupsMakeServerCredentials: Returning %d.", status)); return (status); #else /* !HAVE_SECGENERATESELFSIGNEDCERTIFICATE */ int pid, /* Process ID of command */ status, /* Status of command */ i; /* Looping var */ char command[1024], /* Command */ *argv[5], /* Command-line arguments */ *envp[1000], /* Environment variables */ days[32], /* CERTTOOL_EXPIRATION_DAYS env var */ keychain[1024], /* Keychain argument */ infofile[1024], /* Type-in information for cert */ filename[1024]; /* Default keychain path */ cups_file_t *fp; /* Seed/info file */ DEBUG_printf(("cupsMakeServerCredentials(path=\"%s\", common_name=\"%s\", num_alt_names=%d, alt_names=%p, expiration_date=%d)", path, common_name, num_alt_names, (void *)alt_names, (int)expiration_date)); (void)num_alt_names; (void)alt_names; if (!path) path = http_cdsa_default_path(filename, sizeof(filename)); /* * Run the "certtool" command to generate a self-signed certificate... */ if (!cupsFileFind("certtool", getenv("PATH"), 1, command, sizeof(command))) return (-1); /* * Create a file with the certificate information fields... * * Note: This assumes that the default questions are asked by the certtool * command... */ if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL) return (-1); cupsFilePrintf(fp, "CUPS Self-Signed Certificate\n" /* Enter key and certificate label */ "r\n" /* Generate RSA key pair */ "2048\n" /* 2048 bit encryption key */ "y\n" /* OK (y = yes) */ "b\n" /* Usage (b=signing/encryption) */ "2\n" /* Sign with SHA256 */ "y\n" /* OK (y = yes) */ "%s\n" /* Common name */ "\n" /* Country (default) */ "\n" /* Organization (default) */ "\n" /* Organizational unit (default) */ "\n" /* State/Province (default) */ "\n" /* Email address */ "y\n", /* OK (y = yes) */ common_name); cupsFileClose(fp); snprintf(keychain, sizeof(keychain), "k=%s", path); argv[0] = "certtool"; argv[1] = "c"; argv[2] = keychain; argv[3] = NULL; snprintf(days, sizeof(days), "CERTTOOL_EXPIRATION_DAYS=%d", (int)((expiration_date - time(NULL) + 86399) / 86400)); envp[0] = days; for (i = 0; i < (int)(sizeof(envp) / sizeof(envp[0]) - 2) && environ[i]; i ++) envp[i + 1] = environ[i]; envp[i] = NULL; posix_spawn_file_actions_t actions; /* File actions */ posix_spawn_file_actions_init(&actions); posix_spawn_file_actions_addclose(&actions, 0); posix_spawn_file_actions_addopen(&actions, 0, infofile, O_RDONLY, 0); posix_spawn_file_actions_addclose(&actions, 1); posix_spawn_file_actions_addopen(&actions, 1, "/dev/null", O_WRONLY, 0); posix_spawn_file_actions_addclose(&actions, 2); posix_spawn_file_actions_addopen(&actions, 2, "/dev/null", O_WRONLY, 0); if (posix_spawn(&pid, command, &actions, NULL, argv, envp)) { unlink(infofile); return (-1); } posix_spawn_file_actions_destroy(&actions); unlink(infofile); while (waitpid(pid, &status, 0) < 0) if (errno != EINTR) { status = -1; break; } return (!status); #endif /* HAVE_SECGENERATESELFSIGNEDCERTIFICATE && HAVE_SECKEYCHAINOPEN */ } /* * 'cupsSetServerCredentials()' - Set the default server credentials. * * Note: The server credentials are used by all threads in the running process. * This function is threadsafe. * * @since CUPS 2.0/macOS 10.10@ */ int /* O - 1 on success, 0 on failure */ cupsSetServerCredentials( const char *path, /* I - Keychain path or @code NULL@ for default */ const char *common_name, /* I - Default common name for server */ int auto_create) /* I - 1 = automatically create self-signed certificates */ { DEBUG_printf(("cupsSetServerCredentials(path=\"%s\", common_name=\"%s\", auto_create=%d)", path, common_name, auto_create)); #ifdef HAVE_SECKEYCHAINOPEN char filename[1024]; /* Keychain filename */ SecKeychainRef keychain = http_cdsa_open_keychain(path, filename, sizeof(filename)); if (!keychain) { DEBUG_puts("1cupsSetServerCredentials: Unable to open keychain."); return (0); } _cupsMutexLock(&tls_mutex); /* * Close any keychain that is currently open... */ if (tls_keychain) CFRelease(tls_keychain); if (tls_keypath) _cupsStrFree(tls_keypath); if (tls_common_name) _cupsStrFree(tls_common_name); /* * Save the new keychain... */ tls_keychain = keychain; tls_keypath = _cupsStrAlloc(filename); tls_auto_create = auto_create; tls_common_name = _cupsStrAlloc(common_name); _cupsMutexUnlock(&tls_mutex); DEBUG_puts("1cupsSetServerCredentials: Opened keychain, returning 1."); return (1); #else if (path) { DEBUG_puts("1cupsSetServerCredentials: No keychain support compiled in, returning 0."); return (0); } tls_auto_create = auto_create; tls_common_name = _cupsStrAlloc(common_name); return (1); #endif /* HAVE_SECKEYCHAINOPEN */ } /* * 'httpCopyCredentials()' - Copy the credentials associated with the peer in * an encrypted connection. * * @since CUPS 1.5/macOS 10.7@ */ int /* O - Status of call (0 = success) */ httpCopyCredentials( http_t *http, /* I - Connection to server */ cups_array_t **credentials) /* O - Array of credentials */ { OSStatus error; /* Error code */ SecTrustRef peerTrust; /* Peer trust reference */ CFIndex count; /* Number of credentials */ SecCertificateRef secCert; /* Certificate reference */ CFDataRef data; /* Certificate data */ int i; /* Looping var */ DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", (void *)http, (void *)credentials)); if (credentials) *credentials = NULL; if (!http || !http->tls || !credentials) return (-1); if (!(error = SSLCopyPeerTrust(http->tls, &peerTrust)) && peerTrust) { DEBUG_printf(("2httpCopyCredentials: Peer provided %d certificates.", (int)SecTrustGetCertificateCount(peerTrust))); if ((*credentials = cupsArrayNew(NULL, NULL)) != NULL) { count = SecTrustGetCertificateCount(peerTrust); for (i = 0; i < count; i ++) { secCert = SecTrustGetCertificateAtIndex(peerTrust, i); #ifdef DEBUG CFStringRef cf_name = SecCertificateCopySubjectSummary(secCert); char name[1024]; if (cf_name) CFStringGetCString(cf_name, name, sizeof(name), kCFStringEncodingUTF8); else strlcpy(name, "unknown", sizeof(name)); DEBUG_printf(("2httpCopyCredentials: Certificate %d name is \"%s\".", i, name)); #endif /* DEBUG */ if ((data = SecCertificateCopyData(secCert)) != NULL) { DEBUG_printf(("2httpCopyCredentials: Adding %d byte certificate blob.", (int)CFDataGetLength(data))); httpAddCredential(*credentials, CFDataGetBytePtr(data), (size_t)CFDataGetLength(data)); CFRelease(data); } } } CFRelease(peerTrust); } return (error); } /* * '_httpCreateCredentials()' - Create credentials in the internal format. */ http_tls_credentials_t /* O - Internal credentials */ _httpCreateCredentials( cups_array_t *credentials) /* I - Array of credentials */ { CFMutableArrayRef peerCerts; /* Peer credentials reference */ SecCertificateRef secCert; /* Certificate reference */ http_credential_t *credential; /* Credential data */ if (!credentials) return (NULL); if ((peerCerts = CFArrayCreateMutable(kCFAllocatorDefault, cupsArrayCount(credentials), &kCFTypeArrayCallBacks)) == NULL) return (NULL); for (credential = (http_credential_t *)cupsArrayFirst(credentials); credential; credential = (http_credential_t *)cupsArrayNext(credentials)) { if ((secCert = http_cdsa_create_credential(credential)) != NULL) { CFArrayAppendValue(peerCerts, secCert); CFRelease(secCert); } } return (peerCerts); } /* * 'httpCredentialsAreValidForName()' - Return whether the credentials are valid for the given name. * * @since CUPS 2.0/macOS 10.10@ */ int /* O - 1 if valid, 0 otherwise */ httpCredentialsAreValidForName( cups_array_t *credentials, /* I - Credentials */ const char *common_name) /* I - Name to check */ { SecCertificateRef secCert; /* Certificate reference */ CFStringRef cfcert_name = NULL; /* Certificate's common name (CF string) */ char cert_name[256]; /* Certificate's common name (C string) */ int valid = 1; /* Valid name? */ if ((secCert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL) return (0); /* * Compare the common names... */ if ((cfcert_name = SecCertificateCopySubjectSummary(secCert)) == NULL) { /* * Can't get common name, cannot be valid... */ valid = 0; } else if (CFStringGetCString(cfcert_name, cert_name, sizeof(cert_name), kCFStringEncodingUTF8) && _cups_strcasecmp(common_name, cert_name)) { /* * Not an exact match for the common name, check for wildcard certs... */ const char *domain = strchr(common_name, '.'); /* Domain in common name */ if (strncmp(cert_name, "*.", 2) || !domain || _cups_strcasecmp(domain, cert_name + 1)) { /* * Not a wildcard match. */ /* TODO: Check subject alternate names */ valid = 0; } } if (cfcert_name) CFRelease(cfcert_name); CFRelease(secCert); return (valid); } /* * 'httpCredentialsGetTrust()' - Return the trust of credentials. * * @since CUPS 2.0/macOS 10.10@ */ http_trust_t /* O - Level of trust */ httpCredentialsGetTrust( cups_array_t *credentials, /* I - Credentials */ const char *common_name) /* I - Common name for trust lookup */ { SecCertificateRef secCert; /* Certificate reference */ http_trust_t trust = HTTP_TRUST_OK; /* Trusted? */ cups_array_t *tcreds = NULL; /* Trusted credentials */ _cups_globals_t *cg = _cupsGlobals(); /* Per-thread globals */ if (!common_name) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No common name specified."), 1); return (HTTP_TRUST_UNKNOWN); } if ((secCert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create credentials from array."), 1); return (HTTP_TRUST_UNKNOWN); } if (cg->any_root < 0) _cupsSetDefaults(); /* * Look this common name up in the default keychains... */ httpLoadCredentials(NULL, &tcreds, common_name); if (tcreds) { char credentials_str[1024], /* String for incoming credentials */ tcreds_str[1024]; /* String for saved credentials */ httpCredentialsString(credentials, credentials_str, sizeof(credentials_str)); httpCredentialsString(tcreds, tcreds_str, sizeof(tcreds_str)); if (strcmp(credentials_str, tcreds_str)) { /* * Credentials don't match, let's look at the expiration date of the new * credentials and allow if the new ones have a later expiration... */ if (!cg->trust_first) { /* * Do not trust certificates on first use... */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1); trust = HTTP_TRUST_INVALID; } else if (httpCredentialsGetExpiration(credentials) <= httpCredentialsGetExpiration(tcreds)) { /* * The new credentials are not newly issued... */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("New credentials are older than stored credentials."), 1); trust = HTTP_TRUST_INVALID; } else if (!httpCredentialsAreValidForName(credentials, common_name)) { /* * The common name does not match the issued certificate... */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("New credentials are not valid for name."), 1); trust = HTTP_TRUST_INVALID; } else if (httpCredentialsGetExpiration(tcreds) < time(NULL)) { /* * Save the renewed credentials... */ trust = HTTP_TRUST_RENEWED; httpSaveCredentials(NULL, credentials, common_name); } } httpFreeCredentials(tcreds); } else if (cg->validate_certs && !httpCredentialsAreValidForName(credentials, common_name)) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No stored credentials, not valid for name."), 1); trust = HTTP_TRUST_INVALID; } else if (!cg->trust_first) { /* * See if we have a site CA certificate we can compare... */ if (!httpLoadCredentials(NULL, &tcreds, "site")) { if (cupsArrayCount(credentials) != (cupsArrayCount(tcreds) + 1)) { /* * Certificate isn't directly generated from the CA cert... */ trust = HTTP_TRUST_INVALID; } else { /* * Do a tail comparison of the two certificates... */ http_credential_t *a, *b; /* Certificates */ for (a = (http_credential_t *)cupsArrayFirst(tcreds), b = (http_credential_t *)cupsArrayIndex(credentials, 1); a && b; a = (http_credential_t *)cupsArrayNext(tcreds), b = (http_credential_t *)cupsArrayNext(credentials)) if (a->datalen != b->datalen || memcmp(a->data, b->data, a->datalen)) break; if (a || b) trust = HTTP_TRUST_INVALID; } if (trust != HTTP_TRUST_OK) _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Credentials do not validate against site CA certificate."), 1); } else { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1); trust = HTTP_TRUST_INVALID; } } if (trust == HTTP_TRUST_OK && !cg->expired_certs && !SecCertificateIsValid(secCert, CFAbsoluteTimeGetCurrent())) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Credentials have expired."), 1); trust = HTTP_TRUST_EXPIRED; } if (trust == HTTP_TRUST_OK && !cg->any_root && cupsArrayCount(credentials) == 1) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Self-signed credentials are blocked."), 1); trust = HTTP_TRUST_INVALID; } CFRelease(secCert); return (trust); } /* * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials. * * @since CUPS 2.0/macOS 10.10@ */ time_t /* O - Expiration date of credentials */ httpCredentialsGetExpiration( cups_array_t *credentials) /* I - Credentials */ { SecCertificateRef secCert; /* Certificate reference */ time_t expiration; /* Expiration date */ if ((secCert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL) return (0); expiration = (time_t)(SecCertificateNotValidAfter(secCert) + kCFAbsoluteTimeIntervalSince1970); CFRelease(secCert); return (expiration); } /* * 'httpCredentialsString()' - Return a string representing the credentials. * * @since CUPS 2.0/macOS 10.10@ */ size_t /* O - Total size of credentials string */ httpCredentialsString( cups_array_t *credentials, /* I - Credentials */ char *buffer, /* I - Buffer or @code NULL@ */ size_t bufsize) /* I - Size of buffer */ { http_credential_t *first; /* First certificate */ SecCertificateRef secCert; /* Certificate reference */ DEBUG_printf(("httpCredentialsString(credentials=%p, buffer=%p, bufsize=" CUPS_LLFMT ")", (void *)credentials, (void *)buffer, CUPS_LLCAST bufsize)); if (!buffer) return (0); if (buffer && bufsize > 0) *buffer = '\0'; if ((first = (http_credential_t *)cupsArrayFirst(credentials)) != NULL && (secCert = http_cdsa_create_credential(first)) != NULL) { CFStringRef cf_name; /* CF common name string */ char name[256]; /* Common name associated with cert */ time_t expiration; /* Expiration date of cert */ unsigned char md5_digest[16]; /* MD5 result */ if ((cf_name = SecCertificateCopySubjectSummary(secCert)) != NULL) { CFStringGetCString(cf_name, name, (CFIndex)sizeof(name), kCFStringEncodingUTF8); CFRelease(cf_name); } else strlcpy(name, "unknown", sizeof(name)); expiration = (time_t)(SecCertificateNotValidAfter(secCert) + kCFAbsoluteTimeIntervalSince1970); cupsHashData("md5", first->data, first->datalen, md5_digest, sizeof(md5_digest)); snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", name, httpGetDateString(expiration), md5_digest[0], md5_digest[1], md5_digest[2], md5_digest[3], md5_digest[4], md5_digest[5], md5_digest[6], md5_digest[7], md5_digest[8], md5_digest[9], md5_digest[10], md5_digest[11], md5_digest[12], md5_digest[13], md5_digest[14], md5_digest[15]); CFRelease(secCert); } DEBUG_printf(("1httpCredentialsString: Returning \"%s\".", buffer)); return (strlen(buffer)); } /* * '_httpFreeCredentials()' - Free internal credentials. */ void _httpFreeCredentials( http_tls_credentials_t credentials) /* I - Internal credentials */ { if (!credentials) return; CFRelease(credentials); } /* * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 0 on success, -1 on error */ httpLoadCredentials( const char *path, /* I - Keychain path or @code NULL@ for default */ cups_array_t **credentials, /* IO - Credentials */ const char *common_name) /* I - Common name for credentials */ { OSStatus err; /* Error info */ #ifdef HAVE_SECKEYCHAINOPEN char filename[1024]; /* Filename for keychain */ SecKeychainRef keychain = NULL,/* Keychain reference */ syschain = NULL;/* System keychain */ CFArrayRef list; /* Keychain list */ #endif /* HAVE_SECKEYCHAINOPEN */ SecCertificateRef cert = NULL; /* Certificate */ CFDataRef data; /* Certificate data */ SecPolicyRef policy = NULL; /* Policy ref */ CFStringRef cfcommon_name = NULL; /* Server name */ CFMutableDictionaryRef query = NULL; /* Query qualifiers */ DEBUG_printf(("httpLoadCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, (void *)credentials, common_name)); if (!credentials) return (-1); *credentials = NULL; #ifdef HAVE_SECKEYCHAINOPEN keychain = http_cdsa_open_keychain(path, filename, sizeof(filename)); if (!keychain) goto cleanup; syschain = http_cdsa_open_system_keychain(); #else if (path) return (-1); #endif /* HAVE_SECKEYCHAINOPEN */ cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name, kCFStringEncodingUTF8); policy = SecPolicyCreateSSL(1, cfcommon_name); if (cfcommon_name) CFRelease(cfcommon_name); if (!policy) goto cleanup; if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks))) goto cleanup; CFDictionaryAddValue(query, kSecClass, kSecClassCertificate); CFDictionaryAddValue(query, kSecMatchPolicy, policy); CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue); CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne); #ifdef HAVE_SECKEYCHAINOPEN if (syschain) { const void *values[2] = { syschain, keychain }; list = CFArrayCreate(kCFAllocatorDefault, (const void **)values, 2, &kCFTypeArrayCallBacks); } else list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1, &kCFTypeArrayCallBacks); CFDictionaryAddValue(query, kSecMatchSearchList, list); CFRelease(list); #endif /* HAVE_SECKEYCHAINOPEN */ err = SecItemCopyMatching(query, (CFTypeRef *)&cert); if (err) goto cleanup; if (CFGetTypeID(cert) != SecCertificateGetTypeID()) goto cleanup; if ((data = SecCertificateCopyData(cert)) != NULL) { DEBUG_printf(("1httpLoadCredentials: Adding %d byte certificate blob.", (int)CFDataGetLength(data))); *credentials = cupsArrayNew(NULL, NULL); httpAddCredential(*credentials, CFDataGetBytePtr(data), (size_t)CFDataGetLength(data)); CFRelease(data); } cleanup : #ifdef HAVE_SECKEYCHAINOPEN if (keychain) CFRelease(keychain); if (syschain) CFRelease(syschain); #endif /* HAVE_SECKEYCHAINOPEN */ if (cert) CFRelease(cert); if (policy) CFRelease(policy); if (query) CFRelease(query); DEBUG_printf(("1httpLoadCredentials: Returning %d.", *credentials ? 0 : -1)); return (*credentials ? 0 : -1); } /* * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file. * * @since CUPS 2.0/OS 10.10@ */ int /* O - -1 on error, 0 on success */ httpSaveCredentials( const char *path, /* I - Keychain path or @code NULL@ for default */ cups_array_t *credentials, /* I - Credentials */ const char *common_name) /* I - Common name for credentials */ { int ret = -1; /* Return value */ OSStatus err; /* Error info */ #ifdef HAVE_SECKEYCHAINOPEN char filename[1024]; /* Filename for keychain */ SecKeychainRef keychain = NULL;/* Keychain reference */ CFArrayRef list; /* Keychain list */ #endif /* HAVE_SECKEYCHAINOPEN */ SecCertificateRef cert = NULL; /* Certificate */ CFMutableDictionaryRef attrs = NULL; /* Attributes for add */ DEBUG_printf(("httpSaveCredentials(path=\"%s\", credentials=%p, common_name=\"%s\")", path, (void *)credentials, common_name)); if (!credentials) goto cleanup; if (!httpCredentialsAreValidForName(credentials, common_name)) { DEBUG_puts("1httpSaveCredentials: Common name does not match."); return (-1); } if ((cert = http_cdsa_create_credential((http_credential_t *)cupsArrayFirst(credentials))) == NULL) { DEBUG_puts("1httpSaveCredentials: Unable to create certificate."); goto cleanup; } #ifdef HAVE_SECKEYCHAINOPEN keychain = http_cdsa_open_keychain(path, filename, sizeof(filename)); if (!keychain) goto cleanup; #else if (path) return (-1); #endif /* HAVE_SECKEYCHAINOPEN */ if ((attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == NULL) { DEBUG_puts("1httpSaveCredentials: Unable to create dictionary."); goto cleanup; } CFDictionaryAddValue(attrs, kSecClass, kSecClassCertificate); CFDictionaryAddValue(attrs, kSecValueRef, cert); #ifdef HAVE_SECKEYCHAINOPEN if ((list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1, &kCFTypeArrayCallBacks)) == NULL) { DEBUG_puts("1httpSaveCredentials: Unable to create list of keychains."); goto cleanup; } CFDictionaryAddValue(attrs, kSecMatchSearchList, list); CFRelease(list); #endif /* HAVE_SECKEYCHAINOPEN */ /* Note: SecItemAdd consumes "attrs"... */ err = SecItemAdd(attrs, NULL); DEBUG_printf(("1httpSaveCredentials: SecItemAdd returned %d.", (int)err)); cleanup : #ifdef HAVE_SECKEYCHAINOPEN if (keychain) CFRelease(keychain); #endif /* HAVE_SECKEYCHAINOPEN */ if (cert) CFRelease(cert); DEBUG_printf(("1httpSaveCredentials: Returning %d.", ret)); return (ret); } /* * '_httpTLSInitialize()' - Initialize the TLS stack. */ void _httpTLSInitialize(void) { /* * Nothing to do... */ } /* * '_httpTLSPending()' - Return the number of pending TLS-encrypted bytes. */ size_t _httpTLSPending(http_t *http) /* I - HTTP connection */ { size_t bytes; /* Bytes that are available */ if (!SSLGetBufferedReadSize(http->tls, &bytes)) return (bytes); return (0); } /* * '_httpTLSRead()' - Read from a SSL/TLS connection. */ int /* O - Bytes read */ _httpTLSRead(http_t *http, /* I - HTTP connection */ char *buf, /* I - Buffer to store data */ int len) /* I - Length of buffer */ { int result; /* Return value */ OSStatus error; /* Error info */ size_t processed; /* Number of bytes processed */ error = SSLRead(http->tls, buf, (size_t)len, &processed); DEBUG_printf(("6_httpTLSRead: error=%d, processed=%d", (int)error, (int)processed)); switch (error) { case 0 : result = (int)processed; break; case errSSLWouldBlock : if (processed) result = (int)processed; else { result = -1; errno = EINTR; } break; case errSSLClosedGraceful : default : if (processed) result = (int)processed; else { result = -1; errno = EPIPE; } break; } return (result); } /* * '_httpTLSSetOptions()' - Set TLS protocol and cipher suite options. */ void _httpTLSSetOptions(int options, /* I - Options */ int min_version, /* I - Minimum TLS version */ int max_version) /* I - Maximum TLS version */ { if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0) { tls_options = options; tls_min_version = min_version; tls_max_version = max_version; } } /* * '_httpTLSStart()' - Set up SSL/TLS support on a connection. */ int /* O - 0 on success, -1 on failure */ _httpTLSStart(http_t *http) /* I - HTTP connection */ { char hostname[256], /* Hostname */ *hostptr; /* Pointer into hostname */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ OSStatus error; /* Error code */ const char *message = NULL;/* Error message */ cups_array_t *credentials; /* Credentials array */ cups_array_t *names; /* CUPS distinguished names */ CFArrayRef dn_array; /* CF distinguished names array */ CFIndex count; /* Number of credentials */ CFDataRef data; /* Certificate data */ int i; /* Looping var */ http_credential_t *credential; /* Credential data */ DEBUG_printf(("3_httpTLSStart(http=%p)", (void *)http)); if (tls_options < 0) { DEBUG_puts("4_httpTLSStart: Setting defaults."); _cupsSetDefaults(); DEBUG_printf(("4_httpTLSStart: tls_options=%x, tls_min_version=%d, tls_max_version=%d", tls_options, tls_min_version, tls_max_version)); } #ifdef HAVE_SECKEYCHAINOPEN if (http->mode == _HTTP_MODE_SERVER && !tls_keychain) { DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called."); http->error = errno = EINVAL; http->status = HTTP_STATUS_ERROR; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Server credentials not set."), 1); return (-1); } #endif /* HAVE_SECKEYCHAINOPEN */ if ((http->tls = SSLCreateContext(kCFAllocatorDefault, http->mode == _HTTP_MODE_CLIENT ? kSSLClientSide : kSSLServerSide, kSSLStreamType)) == NULL) { DEBUG_puts("4_httpTLSStart: SSLCreateContext failed."); http->error = errno = ENOMEM; http->status = HTTP_STATUS_ERROR; _cupsSetHTTPError(HTTP_STATUS_ERROR); return (-1); } error = SSLSetConnection(http->tls, http); DEBUG_printf(("4_httpTLSStart: SSLSetConnection, error=%d", (int)error)); if (!error) { error = SSLSetIOFuncs(http->tls, http_cdsa_read, http_cdsa_write); DEBUG_printf(("4_httpTLSStart: SSLSetIOFuncs, error=%d", (int)error)); } if (!error) { error = SSLSetSessionOption(http->tls, kSSLSessionOptionBreakOnServerAuth, true); DEBUG_printf(("4_httpTLSStart: SSLSetSessionOption, error=%d", (int)error)); } if (!error) { static const SSLProtocol protocols[] = /* Min/max protocol versions */ { kSSLProtocol3, kTLSProtocol1, kTLSProtocol11, kTLSProtocol12, kTLSProtocol12, /* TODO: update to 1.3 when 1.3 is supported */ kTLSProtocol12 /* TODO: update to 1.3 when 1.3 is supported */ }; error = SSLSetProtocolVersionMin(http->tls, protocols[tls_min_version]); DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", protocols[tls_min_version], (int)error)); if (!error) { error = SSLSetProtocolVersionMax(http->tls, protocols[tls_max_version]); DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMax(%d), error=%d", protocols[tls_max_version], (int)error)); } } # if HAVE_SSLSETENABLEDCIPHERS if (!error) { SSLCipherSuite supported[100]; /* Supported cipher suites */ size_t num_supported; /* Number of supported cipher suites */ SSLCipherSuite enabled[100]; /* Cipher suites to enable */ size_t num_enabled; /* Number of cipher suites to enable */ num_supported = sizeof(supported) / sizeof(supported[0]); error = SSLGetSupportedCiphers(http->tls, supported, &num_supported); if (!error) { DEBUG_printf(("4_httpTLSStart: %d cipher suites supported.", (int)num_supported)); for (i = 0, num_enabled = 0; i < (int)num_supported && num_enabled < (sizeof(enabled) / sizeof(enabled[0])); i ++) { switch (supported[i]) { /* Obviously insecure cipher suites that we never want to use */ case SSL_NULL_WITH_NULL_NULL : case SSL_RSA_WITH_NULL_MD5 : case SSL_RSA_WITH_NULL_SHA : case SSL_RSA_EXPORT_WITH_RC4_40_MD5 : case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 : case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA : case SSL_RSA_WITH_DES_CBC_SHA : case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA : case SSL_DH_DSS_WITH_DES_CBC_SHA : case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA : case SSL_DH_RSA_WITH_DES_CBC_SHA : case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA : case SSL_DHE_DSS_WITH_DES_CBC_SHA : case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA : case SSL_DHE_RSA_WITH_DES_CBC_SHA : case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 : case SSL_DH_anon_WITH_RC4_128_MD5 : case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA : case SSL_DH_anon_WITH_DES_CBC_SHA : case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA : case SSL_FORTEZZA_DMS_WITH_NULL_SHA : case TLS_DH_anon_WITH_AES_128_CBC_SHA : case TLS_DH_anon_WITH_AES_256_CBC_SHA : case TLS_ECDH_ECDSA_WITH_NULL_SHA : case TLS_ECDHE_RSA_WITH_NULL_SHA : case TLS_ECDH_anon_WITH_NULL_SHA : case TLS_ECDH_anon_WITH_RC4_128_SHA : case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA : case TLS_ECDH_anon_WITH_AES_128_CBC_SHA : case TLS_ECDH_anon_WITH_AES_256_CBC_SHA : case TLS_RSA_WITH_NULL_SHA256 : case TLS_DH_anon_WITH_AES_128_CBC_SHA256 : case TLS_DH_anon_WITH_AES_256_CBC_SHA256 : case TLS_PSK_WITH_NULL_SHA : case TLS_DHE_PSK_WITH_NULL_SHA : case TLS_RSA_PSK_WITH_NULL_SHA : case TLS_DH_anon_WITH_AES_128_GCM_SHA256 : case TLS_DH_anon_WITH_AES_256_GCM_SHA384 : case TLS_PSK_WITH_NULL_SHA256 : case TLS_PSK_WITH_NULL_SHA384 : case TLS_DHE_PSK_WITH_NULL_SHA256 : case TLS_DHE_PSK_WITH_NULL_SHA384 : case TLS_RSA_PSK_WITH_NULL_SHA256 : case TLS_RSA_PSK_WITH_NULL_SHA384 : case SSL_RSA_WITH_DES_CBC_MD5 : DEBUG_printf(("4_httpTLSStart: Excluding insecure cipher suite %d", supported[i])); break; /* RC4 cipher suites that should only be used as a last resort */ case SSL_RSA_WITH_RC4_128_MD5 : case SSL_RSA_WITH_RC4_128_SHA : case TLS_ECDH_ECDSA_WITH_RC4_128_SHA : case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA : case TLS_ECDH_RSA_WITH_RC4_128_SHA : case TLS_ECDHE_RSA_WITH_RC4_128_SHA : case TLS_PSK_WITH_RC4_128_SHA : case TLS_DHE_PSK_WITH_RC4_128_SHA : case TLS_RSA_PSK_WITH_RC4_128_SHA : if (tls_options & _HTTP_TLS_ALLOW_RC4) enabled[num_enabled ++] = supported[i]; else DEBUG_printf(("4_httpTLSStart: Excluding RC4 cipher suite %d", supported[i])); break; /* DH/DHE cipher suites that are problematic with parameters < 1024 bits */ case TLS_DH_DSS_WITH_AES_128_CBC_SHA : case TLS_DH_RSA_WITH_AES_128_CBC_SHA : case TLS_DHE_DSS_WITH_AES_128_CBC_SHA : case TLS_DHE_RSA_WITH_AES_128_CBC_SHA : case TLS_DH_DSS_WITH_AES_256_CBC_SHA : case TLS_DH_RSA_WITH_AES_256_CBC_SHA : case TLS_DHE_DSS_WITH_AES_256_CBC_SHA : case TLS_DHE_RSA_WITH_AES_256_CBC_SHA : case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA : case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA : case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA : case TLS_DH_DSS_WITH_AES_128_CBC_SHA256 : case TLS_DH_RSA_WITH_AES_128_CBC_SHA256 : case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 : case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 : case TLS_DH_DSS_WITH_AES_256_CBC_SHA256 : case TLS_DH_RSA_WITH_AES_256_CBC_SHA256 : case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 : case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 : case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA : case TLS_DHE_PSK_WITH_AES_128_CBC_SHA : case TLS_DHE_PSK_WITH_AES_256_CBC_SHA : case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 : case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 : if (tls_options & _HTTP_TLS_DENY_CBC) { DEBUG_printf(("4_httpTLSStart: Excluding CBC cipher suite %d", supported[i])); break; } // case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 : // case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 : case TLS_DH_RSA_WITH_AES_128_GCM_SHA256 : case TLS_DH_RSA_WITH_AES_256_GCM_SHA384 : // case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 : // case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 : case TLS_DH_DSS_WITH_AES_128_GCM_SHA256 : case TLS_DH_DSS_WITH_AES_256_GCM_SHA384 : case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 : case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 : if (tls_options & _HTTP_TLS_ALLOW_DH) enabled[num_enabled ++] = supported[i]; else DEBUG_printf(("4_httpTLSStart: Excluding DH/DHE cipher suite %d", supported[i])); break; case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA : case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 : case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 : case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 : case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 : case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 : case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 : case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 : case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 : case TLS_RSA_WITH_3DES_EDE_CBC_SHA : case TLS_RSA_WITH_AES_128_CBC_SHA : case TLS_RSA_WITH_AES_256_CBC_SHA : if (tls_options & _HTTP_TLS_DENY_CBC) { DEBUG_printf(("4_httpTLSStart: Excluding CBC cipher suite %d", supported[i])); break; } /* Anything else we'll assume is "secure" */ default : enabled[num_enabled ++] = supported[i]; break; } } DEBUG_printf(("4_httpTLSStart: %d cipher suites enabled.", (int)num_enabled)); error = SSLSetEnabledCiphers(http->tls, enabled, num_enabled); } } #endif /* HAVE_SSLSETENABLEDCIPHERS */ if (!error && http->mode == _HTTP_MODE_CLIENT) { /* * Client: set client-side credentials, if any... */ if (cg->client_cert_cb) { error = SSLSetSessionOption(http->tls, kSSLSessionOptionBreakOnCertRequested, true); DEBUG_printf(("4_httpTLSStart: kSSLSessionOptionBreakOnCertRequested, " "error=%d", (int)error)); } else { error = http_cdsa_set_credentials(http); DEBUG_printf(("4_httpTLSStart: http_cdsa_set_credentials, error=%d", (int)error)); } } else if (!error) { /* * Server: find/create a certificate for TLS... */ if (http->fields[HTTP_FIELD_HOST]) { /* * Use hostname for TLS upgrade... */ strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname)); } else { /* * Resolve hostname from connection address... */ http_addr_t addr; /* Connection address */ socklen_t addrlen; /* Length of address */ addrlen = sizeof(addr); if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen)) { DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno))); hostname[0] = '\0'; } else if (httpAddrLocalhost(&addr)) hostname[0] = '\0'; else { httpAddrLookup(&addr, hostname, sizeof(hostname)); DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname)); } } if (isdigit(hostname[0] & 255) || hostname[0] == '[') hostname[0] = '\0'; /* Don't allow numeric addresses */ if (hostname[0]) http->tls_credentials = http_cdsa_copy_server(hostname); else if (tls_common_name) http->tls_credentials = http_cdsa_copy_server(tls_common_name); if (!http->tls_credentials && tls_auto_create && (hostname[0] || tls_common_name)) { DEBUG_printf(("4_httpTLSStart: Auto-create credentials for \"%s\".", hostname[0] ? hostname : tls_common_name)); if (!cupsMakeServerCredentials(tls_keypath, hostname[0] ? hostname : tls_common_name, 0, NULL, time(NULL) + 365 * 86400)) { DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed."); http->error = errno = EINVAL; http->status = HTTP_STATUS_ERROR; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1); return (-1); } http->tls_credentials = http_cdsa_copy_server(hostname[0] ? hostname : tls_common_name); } if (!http->tls_credentials) { DEBUG_puts("4_httpTLSStart: Unable to find server credentials."); http->error = errno = EINVAL; http->status = HTTP_STATUS_ERROR; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to find server credentials."), 1); return (-1); } error = SSLSetCertificate(http->tls, http->tls_credentials); DEBUG_printf(("4_httpTLSStart: SSLSetCertificate, error=%d", (int)error)); } DEBUG_printf(("4_httpTLSStart: tls_credentials=%p", (void *)http->tls_credentials)); /* * Let the server know which hostname/domain we are trying to connect to * in case it wants to serve up a certificate with a matching common name. */ if (!error && http->mode == _HTTP_MODE_CLIENT) { /* * Client: get the hostname to use for TLS... */ if (httpAddrLocalhost(http->hostaddr)) { strlcpy(hostname, "localhost", sizeof(hostname)); } else { /* * Otherwise make sure the hostname we have does not end in a trailing dot. */ strlcpy(hostname, http->hostname, sizeof(hostname)); if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && *hostptr == '.') *hostptr = '\0'; } error = SSLSetPeerDomainName(http->tls, hostname, strlen(hostname)); DEBUG_printf(("4_httpTLSStart: SSLSetPeerDomainName, error=%d", (int)error)); } if (!error) { int done = 0; /* Are we done yet? */ while (!error && !done) { error = SSLHandshake(http->tls); DEBUG_printf(("4_httpTLSStart: SSLHandshake returned %d.", (int)error)); switch (error) { case noErr : done = 1; break; case errSSLWouldBlock : error = noErr; /* Force a retry */ usleep(1000); /* in 1 millisecond */ break; case errSSLServerAuthCompleted : error = 0; if (cg->server_cert_cb) { error = httpCopyCredentials(http, &credentials); if (!error) { error = (cg->server_cert_cb)(http, http->tls, credentials, cg->server_cert_data); httpFreeCredentials(credentials); } DEBUG_printf(("4_httpTLSStart: Server certificate callback " "returned %d.", (int)error)); } break; case errSSLClientCertRequested : error = 0; if (cg->client_cert_cb) { names = NULL; if (!(error = SSLCopyDistinguishedNames(http->tls, &dn_array)) && dn_array) { if ((names = cupsArrayNew(NULL, NULL)) != NULL) { for (i = 0, count = CFArrayGetCount(dn_array); i < count; i++) { data = (CFDataRef)CFArrayGetValueAtIndex(dn_array, i); if ((credential = malloc(sizeof(*credential))) != NULL) { credential->datalen = (size_t)CFDataGetLength(data); if ((credential->data = malloc(credential->datalen))) { memcpy((void *)credential->data, CFDataGetBytePtr(data), credential->datalen); cupsArrayAdd(names, credential); } else free(credential); } } } CFRelease(dn_array); } if (!error) { error = (cg->client_cert_cb)(http, http->tls, names, cg->client_cert_data); DEBUG_printf(("4_httpTLSStart: Client certificate callback " "returned %d.", (int)error)); } httpFreeCredentials(names); } break; case errSSLUnknownRootCert : message = _("Unable to establish a secure connection to host " "(untrusted certificate)."); break; case errSSLNoRootCert : message = _("Unable to establish a secure connection to host " "(self-signed certificate)."); break; case errSSLCertExpired : message = _("Unable to establish a secure connection to host " "(expired certificate)."); break; case errSSLCertNotYetValid : message = _("Unable to establish a secure connection to host " "(certificate not yet valid)."); break; case errSSLHostNameMismatch : message = _("Unable to establish a secure connection to host " "(host name mismatch)."); break; case errSSLXCertChainInvalid : message = _("Unable to establish a secure connection to host " "(certificate chain invalid)."); break; case errSSLConnectionRefused : message = _("Unable to establish a secure connection to host " "(peer dropped connection before responding)."); break; default : break; } } } if (error) { http->error = error; http->status = HTTP_STATUS_ERROR; errno = ECONNREFUSED; CFRelease(http->tls); http->tls = NULL; /* * If an error string wasn't set by the callbacks use a generic one... */ if (!message) #ifdef HAVE_CSSMERRORSTRING message = cssmErrorString(error); #else message = _("Unable to establish a secure connection to host."); #endif /* HAVE_CSSMERRORSTRING */ _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, message, 1); return (-1); } return (0); } /* * '_httpTLSStop()' - Shut down SSL/TLS on a connection. */ void _httpTLSStop(http_t *http) /* I - HTTP connection */ { while (SSLClose(http->tls) == errSSLWouldBlock) usleep(1000); CFRelease(http->tls); if (http->tls_credentials) CFRelease(http->tls_credentials); http->tls = NULL; http->tls_credentials = NULL; } /* * '_httpTLSWrite()' - Write to a SSL/TLS connection. */ int /* O - Bytes written */ _httpTLSWrite(http_t *http, /* I - HTTP connection */ const char *buf, /* I - Buffer holding data */ int len) /* I - Length of buffer */ { ssize_t result; /* Return value */ OSStatus error; /* Error info */ size_t processed; /* Number of bytes processed */ DEBUG_printf(("2_httpTLSWrite(http=%p, buf=%p, len=%d)", (void *)http, (void *)buf, len)); error = SSLWrite(http->tls, buf, (size_t)len, &processed); switch (error) { case 0 : result = (int)processed; break; case errSSLWouldBlock : if (processed) { result = (int)processed; } else { result = -1; errno = EINTR; } break; case errSSLClosedGraceful : default : if (processed) { result = (int)processed; } else { result = -1; errno = EPIPE; } break; } DEBUG_printf(("3_httpTLSWrite: Returning %d.", (int)result)); return ((int)result); } /* * 'http_cdsa_copy_server()' - Find and copy server credentials from the keychain. */ static CFArrayRef /* O - Array of certificates or NULL */ http_cdsa_copy_server( const char *common_name) /* I - Server's hostname */ { #ifdef HAVE_SECKEYCHAINOPEN OSStatus err; /* Error info */ SecIdentityRef identity = NULL;/* Identity */ CFArrayRef certificates = NULL; /* Certificate array */ SecPolicyRef policy = NULL; /* Policy ref */ CFStringRef cfcommon_name = NULL; /* Server name */ CFMutableDictionaryRef query = NULL; /* Query qualifiers */ CFArrayRef list = NULL; /* Keychain list */ SecKeychainRef syschain = NULL;/* System keychain */ SecKeychainStatus status = 0; /* Keychain status */ DEBUG_printf(("3http_cdsa_copy_server(common_name=\"%s\")", common_name)); cfcommon_name = CFStringCreateWithCString(kCFAllocatorDefault, common_name, kCFStringEncodingUTF8); policy = SecPolicyCreateSSL(1, cfcommon_name); if (!policy) { DEBUG_puts("4http_cdsa_copy_server: Unable to create SSL policy."); goto cleanup; } if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks))) { DEBUG_puts("4http_cdsa_copy_server: Unable to create query dictionary."); goto cleanup; } _cupsMutexLock(&tls_mutex); err = SecKeychainGetStatus(tls_keychain, &status); if (err == noErr && !(status & kSecUnlockStateStatus) && tls_cups_keychain) SecKeychainUnlock(tls_keychain, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, TRUE); CFDictionaryAddValue(query, kSecClass, kSecClassIdentity); CFDictionaryAddValue(query, kSecMatchPolicy, policy); CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue); CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne); syschain = http_cdsa_open_system_keychain(); if (syschain) { const void *values[2] = { syschain, tls_keychain }; list = CFArrayCreate(kCFAllocatorDefault, (const void **)values, 2, &kCFTypeArrayCallBacks); } else list = CFArrayCreate(kCFAllocatorDefault, (const void **)&tls_keychain, 1, &kCFTypeArrayCallBacks); CFDictionaryAddValue(query, kSecMatchSearchList, list); CFRelease(list); err = SecItemCopyMatching(query, (CFTypeRef *)&identity); _cupsMutexUnlock(&tls_mutex); if (err != noErr) { DEBUG_printf(("4http_cdsa_copy_server: SecItemCopyMatching failed with status %d.", (int)err)); goto cleanup; } if (CFGetTypeID(identity) != SecIdentityGetTypeID()) { DEBUG_puts("4http_cdsa_copy_server: Search returned something that is not an identity."); goto cleanup; } if ((certificates = CFArrayCreate(NULL, (const void **)&identity, 1, &kCFTypeArrayCallBacks)) == NULL) { DEBUG_puts("4http_cdsa_copy_server: Unable to create array of certificates."); goto cleanup; } cleanup : if (syschain) CFRelease(syschain); if (identity) CFRelease(identity); if (policy) CFRelease(policy); if (cfcommon_name) CFRelease(cfcommon_name); if (query) CFRelease(query); DEBUG_printf(("4http_cdsa_copy_server: Returning %p.", (void *)certificates)); return (certificates); #else if (!tls_selfsigned) return (NULL); return (CFArrayCreate(NULL, (const void **)&tls_selfsigned, 1, &kCFTypeArrayCallBacks)); #endif /* HAVE_SECKEYCHAINOPEN */ } /* * 'http_cdsa_create_credential()' - Create a single credential in the internal format. */ static SecCertificateRef /* O - Certificate */ http_cdsa_create_credential( http_credential_t *credential) /* I - Credential */ { if (!credential) return (NULL); return (SecCertificateCreateWithBytes(kCFAllocatorDefault, credential->data, (CFIndex)credential->datalen)); } #ifdef HAVE_SECKEYCHAINOPEN /* * 'http_cdsa_default_path()' - Get the default keychain path. */ static const char * /* O - Keychain path */ http_cdsa_default_path(char *buffer, /* I - Path buffer */ size_t bufsize) /* I - Size of buffer */ { const char *home = getenv("HOME"); /* HOME environment variable */ /* * Determine the default keychain path. Note that the login and system * keychains are no longer accessible to user applications starting in macOS * 10.11.4 (!), so we need to create our own keychain just for CUPS. */ if (getuid() && home) snprintf(buffer, bufsize, "%s/.cups/ssl.keychain", home); else strlcpy(buffer, "/etc/cups/ssl.keychain", bufsize); DEBUG_printf(("1http_cdsa_default_path: Using default path \"%s\".", buffer)); return (buffer); } /* * 'http_cdsa_open_keychain()' - Open (or create) a keychain. */ static SecKeychainRef /* O - Keychain or NULL */ http_cdsa_open_keychain( const char *path, /* I - Path to keychain */ char *filename, /* I - Keychain filename */ size_t filesize) /* I - Size of filename buffer */ { SecKeychainRef keychain = NULL;/* Temporary keychain */ OSStatus err; /* Error code */ Boolean interaction; /* Interaction allowed? */ SecKeychainStatus status = 0; /* Keychain status */ /* * Get the keychain filename... */ if (!path) { path = http_cdsa_default_path(filename, filesize); tls_cups_keychain = 1; } else { strlcpy(filename, path, filesize); tls_cups_keychain = 0; } /* * Save the interaction setting and disable while we open the keychain... */ SecKeychainGetUserInteractionAllowed(&interaction); SecKeychainSetUserInteractionAllowed(FALSE); if (access(path, R_OK) && tls_cups_keychain) { /* * Create a new keychain at the given path... */ err = SecKeychainCreate(path, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, FALSE, NULL, &keychain); } else { /* * Open the existing keychain and unlock as needed... */ err = SecKeychainOpen(path, &keychain); if (err == noErr) err = SecKeychainGetStatus(keychain, &status); if (err == noErr && !(status & kSecUnlockStateStatus) && tls_cups_keychain) err = SecKeychainUnlock(keychain, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, TRUE); } /* * Restore interaction setting... */ SecKeychainSetUserInteractionAllowed(interaction); /* * Release the keychain if we had any errors... */ if (err != noErr) { /* TODO: Set cups last error string */ DEBUG_printf(("4http_cdsa_open_keychain: Unable to open keychain (%d), returning NULL.", (int)err)); if (keychain) { CFRelease(keychain); keychain = NULL; } } /* * Return the keychain or NULL... */ return (keychain); } /* * 'http_cdsa_open_system_keychain()' - Open the System keychain. */ static SecKeychainRef http_cdsa_open_system_keychain(void) { SecKeychainRef keychain = NULL;/* Temporary keychain */ OSStatus err; /* Error code */ Boolean interaction; /* Interaction allowed? */ SecKeychainStatus status = 0; /* Keychain status */ /* * Save the interaction setting and disable while we open the keychain... */ SecKeychainGetUserInteractionAllowed(&interaction); SecKeychainSetUserInteractionAllowed(TRUE); err = SecKeychainOpen("/Library/Keychains/System.keychain", &keychain); if (err == noErr) err = SecKeychainGetStatus(keychain, &status); if (err == noErr && !(status & kSecUnlockStateStatus)) err = errSecInteractionNotAllowed; /* * Restore interaction setting... */ SecKeychainSetUserInteractionAllowed(interaction); /* * Release the keychain if we had any errors... */ if (err != noErr) { /* TODO: Set cups last error string */ DEBUG_printf(("4http_cdsa_open_system_keychain: Unable to open keychain (%d), returning NULL.", (int)err)); if (keychain) { CFRelease(keychain); keychain = NULL; } } /* * Return the keychain or NULL... */ return (keychain); } #endif /* HAVE_SECKEYCHAINOPEN */ /* * 'http_cdsa_read()' - Read function for the CDSA library. */ static OSStatus /* O - -1 on error, 0 on success */ http_cdsa_read( SSLConnectionRef connection, /* I - SSL/TLS connection */ void *data, /* I - Data buffer */ size_t *dataLength) /* IO - Number of bytes */ { OSStatus result; /* Return value */ ssize_t bytes; /* Number of bytes read */ http_t *http; /* HTTP connection */ http = (http_t *)connection; if (!http->blocking) { /* * Make sure we have data before we read... */ while (!_httpWait(http, http->wait_value, 0)) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; http->error = ETIMEDOUT; return (-1); } } do { bytes = recv(http->fd, data, *dataLength, 0); } while (bytes == -1 && (errno == EINTR || errno == EAGAIN)); if ((size_t)bytes == *dataLength) { result = 0; } else if (bytes > 0) { *dataLength = (size_t)bytes; result = errSSLWouldBlock; } else { *dataLength = 0; if (bytes == 0) result = errSSLClosedGraceful; else if (errno == EAGAIN) result = errSSLWouldBlock; else result = errSSLClosedAbort; } return (result); } /* * 'http_cdsa_set_credentials()' - Set the TLS credentials. */ static int /* O - Status of connection */ http_cdsa_set_credentials(http_t *http) /* I - HTTP connection */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ OSStatus error = 0; /* Error code */ http_tls_credentials_t credentials = NULL; /* TLS credentials */ DEBUG_printf(("7http_tls_set_credentials(%p)", (void *)http)); /* * Prefer connection specific credentials... */ if ((credentials = http->tls_credentials) == NULL) credentials = cg->tls_credentials; if (credentials) { error = SSLSetCertificate(http->tls, credentials); DEBUG_printf(("4http_tls_set_credentials: SSLSetCertificate, error=%d", (int)error)); } else DEBUG_puts("4http_tls_set_credentials: No credentials to set."); return (error); } /* * 'http_cdsa_write()' - Write function for the CDSA library. */ static OSStatus /* O - -1 on error, 0 on success */ http_cdsa_write( SSLConnectionRef connection, /* I - SSL/TLS connection */ const void *data, /* I - Data buffer */ size_t *dataLength) /* IO - Number of bytes */ { OSStatus result; /* Return value */ ssize_t bytes; /* Number of bytes read */ http_t *http; /* HTTP connection */ http = (http_t *)connection; do { bytes = write(http->fd, data, *dataLength); } while (bytes == -1 && (errno == EINTR || errno == EAGAIN)); if ((size_t)bytes == *dataLength) { result = 0; } else if (bytes >= 0) { *dataLength = (size_t)bytes; result = errSSLWouldBlock; } else { *dataLength = 0; if (errno == EAGAIN) result = errSSLWouldBlock; else result = errSSLClosedAbort; } return (result); } ippsample/cups/md5passwd.c0000644000175000017500000000513313240604116014566 0ustar tilltill/* * MD5 password support for CUPS (deprecated). * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2005 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include #include "http-private.h" #include "string-private.h" /* * 'httpMD5()' - Compute the MD5 sum of the username:group:password. * * @deprecated@ */ char * /* O - MD5 sum */ httpMD5(const char *username, /* I - User name */ const char *realm, /* I - Realm name */ const char *passwd, /* I - Password string */ char md5[33]) /* O - MD5 string */ { unsigned char sum[16]; /* Sum data */ char line[256]; /* Line to sum */ /* * Compute the MD5 sum of the user name, group name, and password. */ snprintf(line, sizeof(line), "%s:%s:%s", username, realm, passwd); cupsHashData("md5", (unsigned char *)line, strlen(line), sum, sizeof(sum)); /* * Return the sum... */ return ((char *)cupsHashString(sum, sizeof(sum), md5, 33)); } /* * 'httpMD5Final()' - Combine the MD5 sum of the username, group, and password * with the server-supplied nonce value, method, and * request-uri. * * @deprecated@ */ char * /* O - New sum */ httpMD5Final(const char *nonce, /* I - Server nonce value */ const char *method, /* I - METHOD (GET, POST, etc.) */ const char *resource, /* I - Resource path */ char md5[33]) /* IO - MD5 sum */ { unsigned char sum[16]; /* Sum data */ char line[1024]; /* Line of data */ char a2[33]; /* Hash of method and resource */ /* * First compute the MD5 sum of the method and resource... */ snprintf(line, sizeof(line), "%s:%s", method, resource); cupsHashData("md5", (unsigned char *)line, strlen(line), sum, sizeof(sum)); cupsHashString(sum, sizeof(sum), a2, sizeof(a2)); /* * Then combine A1 (MD5 of username, realm, and password) with the nonce * and A2 (method + resource) values to get the final MD5 sum for the * request... */ snprintf(line, sizeof(line), "%s:%s:%s", md5, nonce, a2); cupsHashData("md5", (unsigned char *)line, strlen(line), sum, sizeof(sum)); return ((char *)cupsHashString(sum, sizeof(sum), md5, 33)); } /* * 'httpMD5String()' - Convert an MD5 sum to a character string. * * @deprecated@ */ char * /* O - MD5 sum in hex */ httpMD5String(const unsigned char *sum, /* I - MD5 sum data */ char md5[33]) /* O - MD5 sum in hex */ { return ((char *)cupsHashString(sum, 16, md5, 33)); } ippsample/cups/notify.c0000644000175000017500000001113013240604116014161 0ustar tilltill/* * Notification routines for CUPS. * * Copyright 2007-2013 by Apple Inc. * Copyright 2005-2006 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" /* * 'cupsNotifySubject()' - Return the subject for the given notification message. * * The returned string must be freed by the caller using @code free@. * * @since CUPS 1.2/macOS 10.5@ */ char * /* O - Subject string or @code NULL@ */ cupsNotifySubject(cups_lang_t *lang, /* I - Language data */ ipp_t *event) /* I - Event data */ { char buffer[1024]; /* Subject buffer */ const char *prefix, /* Prefix on subject */ *state; /* Printer/job state string */ ipp_attribute_t *job_id, /* notify-job-id */ *job_name, /* job-name */ *job_state, /* job-state */ *printer_name, /* printer-name */ *printer_state, /* printer-state */ *printer_uri, /* notify-printer-uri */ *subscribed; /* notify-subscribed-event */ /* * Range check input... */ if (!event || !lang) return (NULL); /* * Get the required attributes... */ job_id = ippFindAttribute(event, "notify-job-id", IPP_TAG_INTEGER); job_name = ippFindAttribute(event, "job-name", IPP_TAG_NAME); job_state = ippFindAttribute(event, "job-state", IPP_TAG_ENUM); printer_name = ippFindAttribute(event, "printer-name", IPP_TAG_NAME); printer_state = ippFindAttribute(event, "printer-state", IPP_TAG_ENUM); printer_uri = ippFindAttribute(event, "notify-printer-uri", IPP_TAG_URI); subscribed = ippFindAttribute(event, "notify-subscribed-event", IPP_TAG_KEYWORD); if (job_id && printer_name && printer_uri && job_state) { /* * Job event... */ prefix = _cupsLangString(lang, _("Print Job:")); switch (job_state->values[0].integer) { case IPP_JSTATE_PENDING : state = _cupsLangString(lang, _("pending")); break; case IPP_JSTATE_HELD : state = _cupsLangString(lang, _("held")); break; case IPP_JSTATE_PROCESSING : state = _cupsLangString(lang, _("processing")); break; case IPP_JSTATE_STOPPED : state = _cupsLangString(lang, _("stopped")); break; case IPP_JSTATE_CANCELED : state = _cupsLangString(lang, _("canceled")); break; case IPP_JSTATE_ABORTED : state = _cupsLangString(lang, _("aborted")); break; case IPP_JSTATE_COMPLETED : state = _cupsLangString(lang, _("completed")); break; default : state = _cupsLangString(lang, _("unknown")); break; } snprintf(buffer, sizeof(buffer), "%s %s-%d (%s) %s", prefix, printer_name->values[0].string.text, job_id->values[0].integer, job_name ? job_name->values[0].string.text : _cupsLangString(lang, _("untitled")), state); } else if (printer_uri && printer_name && printer_state) { /* * Printer event... */ prefix = _cupsLangString(lang, _("Printer:")); switch (printer_state->values[0].integer) { case IPP_PSTATE_IDLE : state = _cupsLangString(lang, _("idle")); break; case IPP_PSTATE_PROCESSING : state = _cupsLangString(lang, _("processing")); break; case IPP_PSTATE_STOPPED : state = _cupsLangString(lang, _("stopped")); break; default : state = _cupsLangString(lang, _("unknown")); break; } snprintf(buffer, sizeof(buffer), "%s %s %s", prefix, printer_name->values[0].string.text, state); } else if (subscribed) strlcpy(buffer, subscribed->values[0].string.text, sizeof(buffer)); else return (NULL); /* * Duplicate and return the subject string... */ return (strdup(buffer)); } /* * 'cupsNotifyText()' - Return the text for the given notification message. * * The returned string must be freed by the caller using @code free@. * * @since CUPS 1.2/macOS 10.5@ */ char * /* O - Message text or @code NULL@ */ cupsNotifyText(cups_lang_t *lang, /* I - Language data */ ipp_t *event) /* I - Event data */ { ipp_attribute_t *notify_text; /* notify-text */ /* * Range check input... */ if (!event || !lang) return (NULL); /* * Get the notify-text attribute from the server... */ if ((notify_text = ippFindAttribute(event, "notify-text", IPP_TAG_TEXT)) == NULL) return (NULL); /* * Return a copy... */ return (strdup(notify_text->values[0].string.text)); } ippsample/cups/dir.h0000644000175000017500000000220613240604116013440 0ustar tilltill/* * Public directory definitions for CUPS. * * This set of APIs abstracts enumeration of directory entries. * * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_DIR_H_ # define _CUPS_DIR_H_ /* * Include necessary headers... */ # include "versioning.h" # include /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Data types... */ typedef struct _cups_dir_s cups_dir_t; /**** Directory type ****/ typedef struct cups_dentry_s /**** Directory entry type ****/ { char filename[260]; /* File name */ struct stat fileinfo; /* File information */ } cups_dentry_t; /* * Prototypes... */ extern void cupsDirClose(cups_dir_t *dp) _CUPS_API_1_2; extern cups_dir_t *cupsDirOpen(const char *directory) _CUPS_API_1_2; extern cups_dentry_t *cupsDirRead(cups_dir_t *dp) _CUPS_API_1_2; extern void cupsDirRewind(cups_dir_t *dp) _CUPS_API_1_2; # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_DIR_H_ */ ippsample/cups/http-addrlist.c0000644000175000017500000005440013240604116015443 0ustar tilltill/* * HTTP address list routines for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include "cups-private.h" #ifdef HAVE_RESOLV_H # include #endif /* HAVE_RESOLV_H */ #ifdef HAVE_POLL # include #endif /* HAVE_POLL */ #ifndef WIN32 # include #endif /* WIN32 */ /* * 'httpAddrConnect()' - Connect to any of the addresses in the list. * * @since CUPS 1.2/macOS 10.5@ @exclude all@ */ http_addrlist_t * /* O - Connected address or NULL on failure */ httpAddrConnect( http_addrlist_t *addrlist, /* I - List of potential addresses */ int *sock) /* O - Socket */ { DEBUG_printf(("httpAddrConnect(addrlist=%p, sock=%p)", (void *)addrlist, (void *)sock)); return (httpAddrConnect2(addrlist, sock, 30000, NULL)); } /* * 'httpAddrConnect2()' - Connect to any of the addresses in the list with a * timeout and optional cancel. * * @since CUPS 1.7/macOS 10.9@ */ http_addrlist_t * /* O - Connected address or NULL on failure */ httpAddrConnect2( http_addrlist_t *addrlist, /* I - List of potential addresses */ int *sock, /* O - Socket */ int msec, /* I - Timeout in milliseconds */ int *cancel) /* I - Pointer to "cancel" variable */ { int val; /* Socket option value */ #ifndef WIN32 int flags; /* Socket flags */ #endif /* !WIN32 */ int remaining; /* Remaining timeout */ int i, j, /* Looping vars */ nfds, /* Number of file descriptors */ fds[100], /* Socket file descriptors */ result; /* Result from select() or poll() */ http_addrlist_t *addrs[100]; /* Addresses */ #ifndef HAVE_POLL int max_fd = -1; /* Highest file descriptor */ #endif /* !HAVE_POLL */ #ifdef O_NONBLOCK # ifdef HAVE_POLL struct pollfd pfds[100]; /* Polled file descriptors */ # else fd_set input_set, /* select() input set */ output_set, /* select() output set */ error_set; /* select() error set */ struct timeval timeout; /* Timeout */ # endif /* HAVE_POLL */ #endif /* O_NONBLOCK */ #ifdef DEBUG socklen_t len; /* Length of value */ http_addr_t peer; /* Peer address */ char temp[256]; /* Temporary address string */ #endif /* DEBUG */ DEBUG_printf(("httpAddrConnect2(addrlist=%p, sock=%p, msec=%d, cancel=%p)", (void *)addrlist, (void *)sock, msec, (void *)cancel)); if (!sock) { errno = EINVAL; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); return (NULL); } if (cancel && *cancel) return (NULL); if (msec <= 0) msec = INT_MAX; /* * Loop through each address until we connect or run out of addresses... */ nfds = 0; remaining = msec; while (remaining > 0) { if (cancel && *cancel) { while (nfds > 0) { nfds --; httpAddrClose(NULL, fds[nfds]); } return (NULL); } if (addrlist && nfds < (int)(sizeof(fds) / sizeof(fds[0]))) { /* * Create the socket... */ DEBUG_printf(("2httpAddrConnect2: Trying %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)))); if ((fds[nfds] = (int)socket(httpAddrFamily(&(addrlist->addr)), SOCK_STREAM, 0)) < 0) { /* * Don't abort yet, as this could just be an issue with the local * system not being configured with IPv4/IPv6/domain socket enabled. * * Just skip this address... */ addrlist = addrlist->next; continue; } /* * Set options... */ val = 1; setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val)); #ifdef SO_REUSEPORT val = 1; setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEPORT, CUPS_SOCAST &val, sizeof(val)); #endif /* SO_REUSEPORT */ #ifdef SO_NOSIGPIPE val = 1; setsockopt(fds[nfds], SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val)); #endif /* SO_NOSIGPIPE */ /* * Using TCP_NODELAY improves responsiveness, especially on systems * with a slow loopback interface... */ val = 1; setsockopt(fds[nfds], IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val)); #ifdef FD_CLOEXEC /* * Close this socket when starting another process... */ fcntl(fds[nfds], F_SETFD, FD_CLOEXEC); #endif /* FD_CLOEXEC */ #ifdef O_NONBLOCK /* * Do an asynchronous connect by setting the socket non-blocking... */ DEBUG_printf(("httpAddrConnect2: Setting non-blocking connect()")); flags = fcntl(fds[nfds], F_GETFL, 0); fcntl(fds[nfds], F_SETFL, flags | O_NONBLOCK); #endif /* O_NONBLOCK */ /* * Then connect... */ if (!connect(fds[nfds], &(addrlist->addr.addr), (socklen_t)httpAddrLength(&(addrlist->addr)))) { DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)))); #ifdef O_NONBLOCK fcntl(fds[nfds], F_SETFL, flags); #endif /* O_NONBLOCK */ *sock = fds[nfds]; while (nfds > 0) { nfds --; httpAddrClose(NULL, fds[nfds]); } return (addrlist); } #ifdef WIN32 if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK) #else if (errno != EINPROGRESS && errno != EWOULDBLOCK) #endif /* WIN32 */ { DEBUG_printf(("1httpAddrConnect2: Unable to connect to %s:%d: %s", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)), strerror(errno))); httpAddrClose(NULL, fds[nfds]); addrlist = addrlist->next; continue; } #ifndef WIN32 fcntl(fds[nfds], F_SETFL, flags); #endif /* !WIN32 */ #ifndef HAVE_POLL if (fds[nfds] > max_fd) max_fd = fds[nfds]; #endif /* !HAVE_POLL */ addrs[nfds] = addrlist; nfds ++; addrlist = addrlist->next; } if (!addrlist && nfds == 0) break; /* * See if we can connect to any of the addresses so far... */ #ifdef O_NONBLOCK DEBUG_puts("1httpAddrConnect2: Finishing async connect()"); do { if (cancel && *cancel) { /* * Close this socket and return... */ DEBUG_puts("1httpAddrConnect2: Canceled connect()"); while (nfds > 0) { nfds --; httpAddrClose(NULL, fds[nfds]); } *sock = -1; return (NULL); } # ifdef HAVE_POLL for (i = 0; i < nfds; i ++) { pfds[i].fd = fds[i]; pfds[i].events = POLLIN | POLLOUT; } result = poll(pfds, (nfds_t)nfds, addrlist ? 100 : remaining > 250 ? 250 : remaining); DEBUG_printf(("1httpAddrConnect2: poll() returned %d (%d)", result, errno)); # else FD_ZERO(&input_set); for (i = 0; i < nfds; i ++) FD_SET(fds[i], &input_set); output_set = input_set; error_set = input_set; timeout.tv_sec = 0; timeout.tv_usec = (addrlist ? 100 : remaining > 250 ? 250 : remaining) * 1000; result = select(max_fd + 1, &input_set, &output_set, &error_set, &timeout); DEBUG_printf(("1httpAddrConnect2: select() returned %d (%d)", result, errno)); # endif /* HAVE_POLL */ } # ifdef WIN32 while (result < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)); # else while (result < 0 && (errno == EINTR || errno == EAGAIN)); # endif /* WIN32 */ if (result > 0) { http_addrlist_t *connaddr = NULL; /* Connected address, if any */ for (i = 0; i < nfds; i ++) { # ifdef HAVE_POLL DEBUG_printf(("pfds[%d].revents=%x\n", i, pfds[i].revents)); if (pfds[i].revents && !(pfds[i].revents & (POLLERR | POLLHUP))) # else if (FD_ISSET(fds[i], &input_set) && !FD_ISSET(fds[i], &error_set)) # endif /* HAVE_POLL */ { *sock = fds[i]; connaddr = addrs[i]; # ifdef DEBUG len = sizeof(peer); if (!getpeername(fds[i], (struct sockaddr *)&peer, &len)) DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&peer, temp, sizeof(temp)), httpAddrPort(&peer))); # endif /* DEBUG */ break; } # ifdef HAVE_POLL else if (pfds[i].revents & (POLLERR | POLLHUP)) # else else if (FD_ISSET(fds[i], &error_set)) # endif /* HAVE_POLL */ { /* * Error on socket, remove from the "pool"... */ httpAddrClose(NULL, fds[i]); nfds --; if (i < nfds) { memmove(fds + i, fds + i + 1, (size_t)(nfds - i) * (sizeof(fds[0]))); memmove(addrs + i, addrs + i + 1, (size_t)(nfds - i) * (sizeof(addrs[0]))); } i --; } } if (connaddr) { /* * Connected on one address, close all of the other sockets we have so * far and return... */ for (j = 0; j < i; j ++) httpAddrClose(NULL, fds[j]); for (j ++; j < nfds; j ++) httpAddrClose(NULL, fds[j]); return (connaddr); } } #endif /* O_NONBLOCK */ if (addrlist) remaining -= 100; else remaining -= 250; } while (nfds > 0) { nfds --; httpAddrClose(NULL, fds[nfds]); } #ifdef WIN32 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, "Connection failed", 0); #else _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, strerror(errno), 0); #endif /* WIN32 */ return (NULL); } /* * 'httpAddrCopyList()' - Copy an address list. * * @since CUPS 1.7/macOS 10.9@ */ http_addrlist_t * /* O - New address list or @code NULL@ on error */ httpAddrCopyList( http_addrlist_t *src) /* I - Source address list */ { http_addrlist_t *dst = NULL, /* First list entry */ *prev = NULL, /* Previous list entry */ *current = NULL;/* Current list entry */ while (src) { if ((current = malloc(sizeof(http_addrlist_t))) == NULL) { current = dst; while (current) { prev = current; current = current->next; free(prev); } return (NULL); } memcpy(current, src, sizeof(http_addrlist_t)); current->next = NULL; if (prev) prev->next = current; else dst = current; prev = current; src = src->next; } return (dst); } /* * 'httpAddrFreeList()' - Free an address list. * * @since CUPS 1.2/macOS 10.5@ */ void httpAddrFreeList( http_addrlist_t *addrlist) /* I - Address list to free */ { http_addrlist_t *next; /* Next address in list */ /* * Free each address in the list... */ while (addrlist) { next = addrlist->next; free(addrlist); addrlist = next; } } /* * 'httpAddrGetList()' - Get a list of addresses for a hostname. * * @since CUPS 1.2/macOS 10.5@ */ http_addrlist_t * /* O - List of addresses or NULL */ httpAddrGetList(const char *hostname, /* I - Hostname, IP address, or NULL for passive listen address */ int family, /* I - Address family or AF_UNSPEC */ const char *service) /* I - Service name or port number */ { http_addrlist_t *first, /* First address in list */ *addr, /* Current address in list */ *temp; /* New address */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ #ifdef DEBUG _cups_debug_printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, " "service=\"%s\")\n", hostname ? hostname : "(nil)", family == AF_UNSPEC ? "UNSPEC" : # ifdef AF_LOCAL family == AF_LOCAL ? "LOCAL" : # endif /* AF_LOCAL */ # ifdef AF_INET6 family == AF_INET6 ? "INET6" : # endif /* AF_INET6 */ family == AF_INET ? "INET" : "???", service); #endif /* DEBUG */ #ifdef HAVE_RES_INIT /* * STR #2920: Initialize resolver after failure in cups-polld * * If the previous lookup failed, re-initialize the resolver to prevent * temporary network errors from persisting. This *should* be handled by * the resolver libraries, but apparently the glibc folks do not agree. * * We set a flag at the end of this function if we encounter an error that * requires reinitialization of the resolver functions. We then call * res_init() if the flag is set on the next call here or in httpAddrLookup(). */ if (cg->need_res_init) { res_init(); cg->need_res_init = 0; } #endif /* HAVE_RES_INIT */ /* * Lookup the address the best way we can... */ first = addr = NULL; #ifdef AF_LOCAL if (hostname && hostname[0] == '/') { /* * Domain socket address... */ if ((first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t))) != NULL) { addr = first; first->addr.un.sun_family = AF_LOCAL; strlcpy(first->addr.un.sun_path, hostname, sizeof(first->addr.un.sun_path)); } } else #endif /* AF_LOCAL */ if (!hostname || _cups_strcasecmp(hostname, "localhost")) { #ifdef HAVE_GETADDRINFO struct addrinfo hints, /* Address lookup hints */ *results, /* Address lookup results */ *current; /* Current result */ char ipv6[64], /* IPv6 address */ *ipv6zone; /* Pointer to zone separator */ int ipv6len; /* Length of IPv6 address */ int error; /* getaddrinfo() error */ /* * Lookup the address as needed... */ memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_flags = hostname ? 0 : AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; if (hostname && *hostname == '[') { /* * Remove brackets from numeric IPv6 address... */ if (!strncmp(hostname, "[v1.", 4)) { /* * Copy the newer address format which supports link-local addresses... */ strlcpy(ipv6, hostname + 4, sizeof(ipv6)); if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']') { ipv6[ipv6len] = '\0'; hostname = ipv6; /* * Convert "+zone" in address to "%zone"... */ if ((ipv6zone = strrchr(ipv6, '+')) != NULL) *ipv6zone = '%'; } } else { /* * Copy the regular non-link-local IPv6 address... */ strlcpy(ipv6, hostname + 1, sizeof(ipv6)); if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']') { ipv6[ipv6len] = '\0'; hostname = ipv6; } } } if ((error = getaddrinfo(hostname, service, &hints, &results)) == 0) { /* * Copy the results to our own address list structure... */ for (current = results; current; current = current->ai_next) if (current->ai_family == AF_INET || current->ai_family == AF_INET6) { /* * Copy the address over... */ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); if (!temp) { httpAddrFreeList(first); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); return (NULL); } if (current->ai_family == AF_INET6) memcpy(&(temp->addr.ipv6), current->ai_addr, sizeof(temp->addr.ipv6)); else memcpy(&(temp->addr.ipv4), current->ai_addr, sizeof(temp->addr.ipv4)); /* * Append the address to the list... */ if (!first) first = temp; if (addr) addr->next = temp; addr = temp; } /* * Free the results from getaddrinfo()... */ freeaddrinfo(results); } else { if (error == EAI_FAIL) cg->need_res_init = 1; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerror(error), 0); } #else if (hostname) { int i; /* Looping vars */ unsigned ip[4]; /* IPv4 address components */ const char *ptr; /* Pointer into hostname */ struct hostent *host; /* Result of lookup */ struct servent *port; /* Port number for service */ int portnum; /* Port number */ /* * Lookup the service... */ if (!service) portnum = 0; else if (isdigit(*service & 255)) portnum = atoi(service); else if ((port = getservbyname(service, NULL)) != NULL) portnum = ntohs(port->s_port); else if (!strcmp(service, "http")) portnum = 80; else if (!strcmp(service, "https")) portnum = 443; else if (!strcmp(service, "ipp") || !strcmp(service, "ipps")) portnum = 631; else if (!strcmp(service, "lpd")) portnum = 515; else if (!strcmp(service, "socket")) portnum = 9100; else return (NULL); /* * This code is needed because some operating systems have a * buggy implementation of gethostbyname() that does not support * IPv4 addresses. If the hostname string is an IPv4 address, then * sscanf() is used to extract the IPv4 components. We then pack * the components into an IPv4 address manually, since the * inet_aton() function is deprecated. We use the htonl() macro * to get the right byte order for the address. */ for (ptr = hostname; isdigit(*ptr & 255) || *ptr == '.'; ptr ++); if (!*ptr) { /* * We have an IPv4 address; break it up and create an IPv4 address... */ if (sscanf(hostname, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) == 4 && ip[0] <= 255 && ip[1] <= 255 && ip[2] <= 255 && ip[3] <= 255) { first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); if (!first) return (NULL); first->addr.ipv4.sin_family = AF_INET; first->addr.ipv4.sin_addr.s_addr = htonl((((((((unsigned)ip[0] << 8) | (unsigned)ip[1]) << 8) | (unsigned)ip[2]) << 8) | (unsigned)ip[3])); first->addr.ipv4.sin_port = htons(portnum); } } else if ((host = gethostbyname(hostname)) != NULL && # ifdef AF_INET6 (host->h_addrtype == AF_INET || host->h_addrtype == AF_INET6)) # else host->h_addrtype == AF_INET) # endif /* AF_INET6 */ { for (i = 0; host->h_addr_list[i]; i ++) { /* * Copy the address over... */ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); if (!temp) { httpAddrFreeList(first); return (NULL); } # ifdef AF_INET6 if (host->h_addrtype == AF_INET6) { temp->addr.ipv6.sin6_family = AF_INET6; memcpy(&(temp->addr.ipv6.sin6_addr), host->h_addr_list[i], sizeof(temp->addr.ipv6)); temp->addr.ipv6.sin6_port = htons(portnum); } else # endif /* AF_INET6 */ { temp->addr.ipv4.sin_family = AF_INET; memcpy(&(temp->addr.ipv4.sin_addr), host->h_addr_list[i], sizeof(temp->addr.ipv4)); temp->addr.ipv4.sin_port = htons(portnum); } /* * Append the address to the list... */ if (!first) first = temp; if (addr) addr->next = temp; addr = temp; } } else { if (h_errno == NO_RECOVERY) cg->need_res_init = 1; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, hstrerror(h_errno), 0); } } #endif /* HAVE_GETADDRINFO */ } /* * Detect some common errors and handle them sanely... */ if (!addr && (!hostname || !_cups_strcasecmp(hostname, "localhost"))) { struct servent *port; /* Port number for service */ int portnum; /* Port number */ /* * Lookup the service... */ if (!service) portnum = 0; else if (isdigit(*service & 255)) portnum = atoi(service); else if ((port = getservbyname(service, NULL)) != NULL) portnum = ntohs(port->s_port); else if (!strcmp(service, "http")) portnum = 80; else if (!strcmp(service, "https")) portnum = 443; else if (!strcmp(service, "ipp") || !strcmp(service, "ipps")) portnum = 631; else if (!strcmp(service, "lpd")) portnum = 515; else if (!strcmp(service, "socket")) portnum = 9100; else { httpAddrFreeList(first); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown service name."), 1); return (NULL); } if (hostname && !_cups_strcasecmp(hostname, "localhost")) { /* * Unfortunately, some users ignore all of the warnings in the * /etc/hosts file and delete "localhost" from it. If we get here * then we were unable to resolve the name, so use the IPv6 and/or * IPv4 loopback interface addresses... */ #ifdef AF_INET6 if (family != AF_INET) { /* * Add [::1] to the address list... */ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); if (!temp) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); httpAddrFreeList(first); return (NULL); } temp->addr.ipv6.sin6_family = AF_INET6; temp->addr.ipv6.sin6_port = htons(portnum); # ifdef WIN32 temp->addr.ipv6.sin6_addr.u.Byte[15] = 1; # else temp->addr.ipv6.sin6_addr.s6_addr32[3] = htonl(1); # endif /* WIN32 */ if (!first) first = temp; addr = temp; } if (family != AF_INET6) #endif /* AF_INET6 */ { /* * Add 127.0.0.1 to the address list... */ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); if (!temp) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); httpAddrFreeList(first); return (NULL); } temp->addr.ipv4.sin_family = AF_INET; temp->addr.ipv4.sin_port = htons(portnum); temp->addr.ipv4.sin_addr.s_addr = htonl(0x7f000001); if (!first) first = temp; if (addr) addr->next = temp; } } else if (!hostname) { /* * Provide one or more passive listening addresses... */ #ifdef AF_INET6 if (family != AF_INET) { /* * Add [::] to the address list... */ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); if (!temp) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); httpAddrFreeList(first); return (NULL); } temp->addr.ipv6.sin6_family = AF_INET6; temp->addr.ipv6.sin6_port = htons(portnum); if (!first) first = temp; addr = temp; } if (family != AF_INET6) #endif /* AF_INET6 */ { /* * Add 0.0.0.0 to the address list... */ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); if (!temp) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); httpAddrFreeList(first); return (NULL); } temp->addr.ipv4.sin_family = AF_INET; temp->addr.ipv4.sin_port = htons(portnum); if (!first) first = temp; if (addr) addr->next = temp; } } } /* * Return the address list... */ return (first); } ippsample/cups/raster.h0000644000175000017500000004371613240604116014175 0ustar tilltill/* * Raster file definitions for CUPS. * * Copyright 2007-2016 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * This file is part of the CUPS Imaging library. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ #ifndef _CUPS_RASTER_H_ # define _CUPS_RASTER_H_ /* * Include necessary headers... */ # include "cups.h" # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Every non-PostScript printer driver that supports raster images * should use the application/vnd.cups-raster image file format. * Since both the PostScript RIP (pstoraster, based on GNU/GPL * Ghostscript) and Image RIP (imagetoraster, located in the filter * directory) use it, using this format saves you a lot of work. * Also, the PostScript RIP passes any printer options that are in * a PS file to your driver this way as well... */ /* * Constants... */ # define CUPS_RASTER_SYNC 0x52615333 /* RaS3 */ # define CUPS_RASTER_REVSYNC 0x33536152 /* 3SaR */ # define CUPS_RASTER_SYNCv1 0x52615374 /* RaSt */ # define CUPS_RASTER_REVSYNCv1 0x74536152 /* tSaR */ # define CUPS_RASTER_SYNCv2 0x52615332 /* RaS2 */ # define CUPS_RASTER_REVSYNCv2 0x32536152 /* 2SaR */ # define CUPS_RASTER_SYNCapple 0x554E4952 /* UNIR */ # define CUPS_RASTER_REVSYNCapple 0x52494E55 /* RINU */ # define CUPS_RASTER_SYNC_PWG CUPS_RASTER_SYNCv2 /* * The following definition can be used to determine if the * colorimetric colorspaces (CIEXYZ, CIELAB, and ICCn) are * defined... */ # define CUPS_RASTER_HAVE_COLORIMETRIC 1 /* * The following definition can be used to determine if the * device colorspaces (DEVICEn) are defined... */ # define CUPS_RASTER_HAVE_DEVICE 1 /* * The following definition can be used to determine if PWG Raster is supported. */ # define CUPS_RASTER_HAVE_PWGRASTER 1 /* * The following definition can be used to determine if Apple Raster is * supported (beta). */ # define CUPS_RASTER_HAVE_APPLERASTER 1 /* * The following PWG 5102.4 definitions specify indices into the * cupsInteger[] array in the raster header. */ # define CUPS_RASTER_PWG_TotalPageCount 0 # define CUPS_RASTER_PWG_CrossFeedTransform 1 # define CUPS_RASTER_PWG_FeedTransform 2 # define CUPS_RASTER_PWG_ImageBoxLeft 3 # define CUPS_RASTER_PWG_ImageBoxTop 4 # define CUPS_RASTER_PWG_ImageBoxRight 5 # define CUPS_RASTER_PWG_ImageBoxBottom 6 # define CUPS_RASTER_PWG_AlternatePrimary 7 # define CUPS_RASTER_PWG_PrintQuality 8 # define CUPS_RASTER_PWG_VendorIdentifier 14 # define CUPS_RASTER_PWG_VendorLength 15 /* * Types... */ typedef enum cups_adv_e /**** AdvanceMedia attribute values ****/ { CUPS_ADVANCE_NONE = 0, /* Never advance the roll */ CUPS_ADVANCE_FILE = 1, /* Advance the roll after this file */ CUPS_ADVANCE_JOB = 2, /* Advance the roll after this job */ CUPS_ADVANCE_SET = 3, /* Advance the roll after this set */ CUPS_ADVANCE_PAGE = 4 /* Advance the roll after this page */ } cups_adv_t; typedef enum cups_bool_e /**** Boolean type ****/ { CUPS_FALSE = 0, /* Logical false */ CUPS_TRUE = 1 /* Logical true */ } cups_bool_t; typedef enum cups_cspace_e /**** cupsColorSpace attribute values ****/ { CUPS_CSPACE_W = 0, /* Luminance (DeviceGray, gamma 2.2 by default) */ CUPS_CSPACE_RGB = 1, /* Red, green, blue (DeviceRGB, sRGB by default) */ CUPS_CSPACE_RGBA = 2, /* Red, green, blue, alpha (DeviceRGB, sRGB by default) */ CUPS_CSPACE_K = 3, /* Black (DeviceK) */ CUPS_CSPACE_CMY = 4, /* Cyan, magenta, yellow (DeviceCMY) */ CUPS_CSPACE_YMC = 5, /* Yellow, magenta, cyan @deprecated@ */ CUPS_CSPACE_CMYK = 6, /* Cyan, magenta, yellow, black (DeviceCMYK) */ CUPS_CSPACE_YMCK = 7, /* Yellow, magenta, cyan, black @deprecated@ */ CUPS_CSPACE_KCMY = 8, /* Black, cyan, magenta, yellow @deprecated@ */ CUPS_CSPACE_KCMYcm = 9, /* Black, cyan, magenta, yellow, light-cyan, light-magenta @deprecated@ */ CUPS_CSPACE_GMCK = 10, /* Gold, magenta, yellow, black @deprecated@ */ CUPS_CSPACE_GMCS = 11, /* Gold, magenta, yellow, silver @deprecated@ */ CUPS_CSPACE_WHITE = 12, /* White ink (as black) @deprecated@ */ CUPS_CSPACE_GOLD = 13, /* Gold foil @deprecated@ */ CUPS_CSPACE_SILVER = 14, /* Silver foil @deprecated@ */ CUPS_CSPACE_CIEXYZ = 15, /* CIE XYZ @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_CIELab = 16, /* CIE Lab @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_RGBW = 17, /* Red, green, blue, white (DeviceRGB, sRGB by default) @since CUPS 1.2/macOS 10.5@ */ CUPS_CSPACE_SW = 18, /* Luminance (gamma 2.2) @since CUPS 1.4.5@ */ CUPS_CSPACE_SRGB = 19, /* Red, green, blue (sRGB) @since CUPS 1.4.5@ */ CUPS_CSPACE_ADOBERGB = 20, /* Red, green, blue (Adobe RGB) @since CUPS 1.4.5@ */ CUPS_CSPACE_ICC1 = 32, /* ICC-based, 1 color @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_ICC2 = 33, /* ICC-based, 2 colors @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_ICC3 = 34, /* ICC-based, 3 colors @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_ICC4 = 35, /* ICC-based, 4 colors @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_ICC5 = 36, /* ICC-based, 5 colors @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_ICC6 = 37, /* ICC-based, 6 colors @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_ICC7 = 38, /* ICC-based, 7 colors @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_ICC8 = 39, /* ICC-based, 8 colors @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_ICC9 = 40, /* ICC-based, 9 colors @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_ICCA = 41, /* ICC-based, 10 colors @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_ICCB = 42, /* ICC-based, 11 colors @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_ICCC = 43, /* ICC-based, 12 colors @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_ICCD = 44, /* ICC-based, 13 colors @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_ICCE = 45, /* ICC-based, 14 colors @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_ICCF = 46, /* ICC-based, 15 colors @since CUPS 1.1.19/macOS 10.3@ */ CUPS_CSPACE_DEVICE1 = 48, /* DeviceN, 1 color @since CUPS 1.4.5@ */ CUPS_CSPACE_DEVICE2 = 49, /* DeviceN, 2 colors @since CUPS 1.4.5@ */ CUPS_CSPACE_DEVICE3 = 50, /* DeviceN, 3 colors @since CUPS 1.4.5@ */ CUPS_CSPACE_DEVICE4 = 51, /* DeviceN, 4 colors @since CUPS 1.4.5@ */ CUPS_CSPACE_DEVICE5 = 52, /* DeviceN, 5 colors @since CUPS 1.4.5@ */ CUPS_CSPACE_DEVICE6 = 53, /* DeviceN, 6 colors @since CUPS 1.4.5@ */ CUPS_CSPACE_DEVICE7 = 54, /* DeviceN, 7 colors @since CUPS 1.4.5@ */ CUPS_CSPACE_DEVICE8 = 55, /* DeviceN, 8 colors @since CUPS 1.4.5@ */ CUPS_CSPACE_DEVICE9 = 56, /* DeviceN, 9 colors @since CUPS 1.4.5@ */ CUPS_CSPACE_DEVICEA = 57, /* DeviceN, 10 colors @since CUPS 1.4.5@ */ CUPS_CSPACE_DEVICEB = 58, /* DeviceN, 11 colors @since CUPS 1.4.5@ */ CUPS_CSPACE_DEVICEC = 59, /* DeviceN, 12 colors @since CUPS 1.4.5@ */ CUPS_CSPACE_DEVICED = 60, /* DeviceN, 13 colors @since CUPS 1.4.5@ */ CUPS_CSPACE_DEVICEE = 61, /* DeviceN, 14 colors @since CUPS 1.4.5@ */ CUPS_CSPACE_DEVICEF = 62 /* DeviceN, 15 colors @since CUPS 1.4.5@ */ } cups_cspace_t; typedef enum cups_cut_e /**** CutMedia attribute values ****/ { CUPS_CUT_NONE = 0, /* Never cut the roll */ CUPS_CUT_FILE = 1, /* Cut the roll after this file */ CUPS_CUT_JOB = 2, /* Cut the roll after this job */ CUPS_CUT_SET = 3, /* Cut the roll after this set */ CUPS_CUT_PAGE = 4 /* Cut the roll after this page */ } cups_cut_t; typedef enum cups_edge_e /**** LeadingEdge attribute values ****/ { CUPS_EDGE_TOP = 0, /* Leading edge is the top of the page */ CUPS_EDGE_RIGHT = 1, /* Leading edge is the right of the page */ CUPS_EDGE_BOTTOM = 2, /* Leading edge is the bottom of the page */ CUPS_EDGE_LEFT = 3 /* Leading edge is the left of the page */ } cups_edge_t; typedef enum cups_jog_e /**** Jog attribute values ****/ { CUPS_JOG_NONE = 0, /* Never move pages */ CUPS_JOG_FILE = 1, /* Move pages after this file */ CUPS_JOG_JOB = 2, /* Move pages after this job */ CUPS_JOG_SET = 3 /* Move pages after this set */ } cups_jog_t; enum cups_mode_e /**** cupsRasterOpen modes ****/ { CUPS_RASTER_READ = 0, /* Open stream for reading */ CUPS_RASTER_WRITE = 1, /* Open stream for writing */ CUPS_RASTER_WRITE_COMPRESSED = 2, /* Open stream for compressed writing @since CUPS 1.3/macOS 10.5@ */ CUPS_RASTER_WRITE_PWG = 3, /* Open stream for compressed writing in PWG Raster mode @since CUPS 1.5/macOS 10.7@ */ CUPS_RASTER_WRITE_APPLE = 4 /* Open stream for compressed writing in AppleRaster mode (beta) @private@ */ }; typedef enum cups_mode_e cups_mode_t; /**** cupsRasterOpen modes ****/ typedef enum cups_order_e /**** cupsColorOrder attribute values ****/ { CUPS_ORDER_CHUNKED = 0, /* CMYK CMYK CMYK ... */ CUPS_ORDER_BANDED = 1, /* CCC MMM YYY KKK ... */ CUPS_ORDER_PLANAR = 2 /* CCC ... MMM ... YYY ... KKK ... */ } cups_order_t; typedef enum cups_orient_e /**** Orientation attribute values ****/ { CUPS_ORIENT_0 = 0, /* Don't rotate the page */ CUPS_ORIENT_90 = 1, /* Rotate the page counter-clockwise */ CUPS_ORIENT_180 = 2, /* Turn the page upside down */ CUPS_ORIENT_270 = 3 /* Rotate the page clockwise */ } cups_orient_t; /* * The page header structure contains the standard PostScript page device * dictionary, along with some CUPS-specific parameters that are provided * by the RIPs... * * The API supports a "version 1" (from CUPS 1.0 and 1.1) and a "version 2" * (from CUPS 1.2 and higher) page header, for binary compatibility. */ typedef struct cups_page_header_s /**** Version 1 page header @deprecated@ ****/ { /**** Standard Page Device Dictionary String Values ****/ char MediaClass[64]; /* MediaClass string */ char MediaColor[64]; /* MediaColor string */ char MediaType[64]; /* MediaType string */ char OutputType[64]; /* OutputType string */ /**** Standard Page Device Dictionary Integer Values ****/ unsigned AdvanceDistance; /* AdvanceDistance value in points */ cups_adv_t AdvanceMedia; /* AdvanceMedia value (@link cups_adv_t@) */ cups_bool_t Collate; /* Collated copies value */ cups_cut_t CutMedia; /* CutMedia value (@link cups_cut_t@) */ cups_bool_t Duplex; /* Duplexed (double-sided) value */ unsigned HWResolution[2]; /* Resolution in dots-per-inch */ unsigned ImagingBoundingBox[4]; /* Pixel region that is painted (points, left, bottom, right, top) */ cups_bool_t InsertSheet; /* InsertSheet value */ cups_jog_t Jog; /* Jog value (@link cups_jog_t@) */ cups_edge_t LeadingEdge; /* LeadingEdge value (@link cups_edge_t@) */ unsigned Margins[2]; /* Lower-lefthand margins in points */ cups_bool_t ManualFeed; /* ManualFeed value */ unsigned MediaPosition; /* MediaPosition value */ unsigned MediaWeight; /* MediaWeight value in grams/m^2 */ cups_bool_t MirrorPrint; /* MirrorPrint value */ cups_bool_t NegativePrint; /* NegativePrint value */ unsigned NumCopies; /* Number of copies to produce */ cups_orient_t Orientation; /* Orientation value (@link cups_orient_t@) */ cups_bool_t OutputFaceUp; /* OutputFaceUp value */ unsigned PageSize[2]; /* Width and length of page in points */ cups_bool_t Separations; /* Separations value */ cups_bool_t TraySwitch; /* TraySwitch value */ cups_bool_t Tumble; /* Tumble value */ /**** CUPS Page Device Dictionary Values ****/ unsigned cupsWidth; /* Width of page image in pixels */ unsigned cupsHeight; /* Height of page image in pixels */ unsigned cupsMediaType; /* Media type code */ unsigned cupsBitsPerColor; /* Number of bits for each color */ unsigned cupsBitsPerPixel; /* Number of bits for each pixel */ unsigned cupsBytesPerLine; /* Number of bytes per line */ cups_order_t cupsColorOrder; /* Order of colors */ cups_cspace_t cupsColorSpace; /* True colorspace */ unsigned cupsCompression; /* Device compression to use */ unsigned cupsRowCount; /* Rows per band */ unsigned cupsRowFeed; /* Feed between bands */ unsigned cupsRowStep; /* Spacing between lines */ } cups_page_header_t; /**** New in CUPS 1.2 ****/ typedef struct cups_page_header2_s /**** Version 2 page header @since CUPS 1.2/macOS 10.5@ ****/ { /**** Standard Page Device Dictionary String Values ****/ char MediaClass[64]; /* MediaClass string */ char MediaColor[64]; /* MediaColor string */ char MediaType[64]; /* MediaType string */ char OutputType[64]; /* OutputType string */ /**** Standard Page Device Dictionary Integer Values ****/ unsigned AdvanceDistance; /* AdvanceDistance value in points */ cups_adv_t AdvanceMedia; /* AdvanceMedia value (@link cups_adv_t@) */ cups_bool_t Collate; /* Collated copies value */ cups_cut_t CutMedia; /* CutMedia value (@link cups_cut_t@) */ cups_bool_t Duplex; /* Duplexed (double-sided) value */ unsigned HWResolution[2]; /* Resolution in dots-per-inch */ unsigned ImagingBoundingBox[4]; /* Pixel region that is painted (points, left, bottom, right, top) */ cups_bool_t InsertSheet; /* InsertSheet value */ cups_jog_t Jog; /* Jog value (@link cups_jog_t@) */ cups_edge_t LeadingEdge; /* LeadingEdge value (@link cups_edge_t@) */ unsigned Margins[2]; /* Lower-lefthand margins in points */ cups_bool_t ManualFeed; /* ManualFeed value */ unsigned MediaPosition; /* MediaPosition value */ unsigned MediaWeight; /* MediaWeight value in grams/m^2 */ cups_bool_t MirrorPrint; /* MirrorPrint value */ cups_bool_t NegativePrint; /* NegativePrint value */ unsigned NumCopies; /* Number of copies to produce */ cups_orient_t Orientation; /* Orientation value (@link cups_orient_t@) */ cups_bool_t OutputFaceUp; /* OutputFaceUp value */ unsigned PageSize[2]; /* Width and length of page in points */ cups_bool_t Separations; /* Separations value */ cups_bool_t TraySwitch; /* TraySwitch value */ cups_bool_t Tumble; /* Tumble value */ /**** CUPS Page Device Dictionary Values ****/ unsigned cupsWidth; /* Width of page image in pixels */ unsigned cupsHeight; /* Height of page image in pixels */ unsigned cupsMediaType; /* Media type code */ unsigned cupsBitsPerColor; /* Number of bits for each color */ unsigned cupsBitsPerPixel; /* Number of bits for each pixel */ unsigned cupsBytesPerLine; /* Number of bytes per line */ cups_order_t cupsColorOrder; /* Order of colors */ cups_cspace_t cupsColorSpace; /* True colorspace */ unsigned cupsCompression; /* Device compression to use */ unsigned cupsRowCount; /* Rows per band */ unsigned cupsRowFeed; /* Feed between bands */ unsigned cupsRowStep; /* Spacing between lines */ /**** Version 2 Dictionary Values ****/ unsigned cupsNumColors; /* Number of color compoents @since CUPS 1.2/macOS 10.5@ */ float cupsBorderlessScalingFactor; /* Scaling that was applied to page data @since CUPS 1.2/macOS 10.5@ */ float cupsPageSize[2]; /* Floating point PageSize (scaling * * factor not applied) @since CUPS 1.2/macOS 10.5@ */ float cupsImagingBBox[4]; /* Floating point ImagingBoundingBox * (scaling factor not applied, left, * bottom, right, top) @since CUPS 1.2/macOS 10.5@ */ unsigned cupsInteger[16]; /* User-defined integer values @since CUPS 1.2/macOS 10.5@ */ float cupsReal[16]; /* User-defined floating-point values @since CUPS 1.2/macOS 10.5@ */ char cupsString[16][64]; /* User-defined string values @since CUPS 1.2/macOS 10.5@ */ char cupsMarkerType[64]; /* Ink/toner type @since CUPS 1.2/macOS 10.5@ */ char cupsRenderingIntent[64];/* Color rendering intent @since CUPS 1.2/macOS 10.5@ */ char cupsPageSizeName[64]; /* PageSize name @since CUPS 1.2/macOS 10.5@ */ } cups_page_header2_t; typedef struct _cups_raster_s cups_raster_t; /**** Raster stream data ****/ typedef int (*cups_interpret_cb_t)(cups_page_header2_t *header, int preferred_bits); /**** cupsRasterInterpretPPD callback function * * This function is called by * @link cupsRasterInterpretPPD@ to * validate (and update, as needed) * the page header attributes. The * "preferred_bits" argument provides * the value of the * @code cupsPreferredBitsPerColor@ * key from the PostScript page device * dictionary and is 0 if undefined. ****/ /**** New in CUPS 1.5 ****/ typedef ssize_t (*cups_raster_iocb_t)(void *ctx, unsigned char *buffer, size_t length); /**** cupsRasterOpenIO callback function * * This function is specified when * creating a raster stream with * @link cupsRasterOpenIO@ and handles * generic reading and writing of raster * data. It must return -1 on error or * the number of bytes specified by * "length" on success. ****/ /* * Prototypes... */ extern void cupsRasterClose(cups_raster_t *r); extern cups_raster_t *cupsRasterOpen(int fd, cups_mode_t mode); extern unsigned cupsRasterReadHeader(cups_raster_t *r, cups_page_header_t *h) _CUPS_DEPRECATED_MSG("Use cupsRasterReadHeader2 instead."); extern unsigned cupsRasterReadPixels(cups_raster_t *r, unsigned char *p, unsigned len); extern unsigned cupsRasterWriteHeader(cups_raster_t *r, cups_page_header_t *h) _CUPS_DEPRECATED_MSG("Use cupsRasterWriteHeader2 instead."); extern unsigned cupsRasterWritePixels(cups_raster_t *r, unsigned char *p, unsigned len); /**** New in CUPS 1.2 ****/ extern unsigned cupsRasterReadHeader2(cups_raster_t *r, cups_page_header2_t *h) _CUPS_API_1_2; extern unsigned cupsRasterWriteHeader2(cups_raster_t *r, cups_page_header2_t *h) _CUPS_API_1_2; /**** New in CUPS 1.3 ****/ extern const char *cupsRasterErrorString(void) _CUPS_API_1_3; /**** New in CUPS 1.5 ****/ extern cups_raster_t *cupsRasterOpenIO(cups_raster_iocb_t iocb, void *ctx, cups_mode_t mode); /**** New in CUPS 2.2/macOS 10.12 ****/ extern int cupsRasterInitPWGHeader(cups_page_header2_t *h, pwg_media_t *media, const char *type, int xdpi, int ydpi, const char *sides, const char *sheet_back) _CUPS_API_2_2; # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_RASTER_H_ */ ippsample/.travis.yml0000644000175000017500000000106613240604116013653 0ustar tilltill# # Travis CI configuration file for the IPP sample project. # # Copyright © 2018 by the IEEE-ISTO Printer Working Group. # # Licensed under Apache License v2.0. See the file "LICENSE" for more # information. # language: c matrix: include: # Linux-specific build stuff - os: linux before_install: - sudo apt-get -qq update - sudo apt-get install -y avahi-daemon avahi-utils libavahi-client-dev libgnutls28-dev libjpeg-dev libnss-mdns libpng-dev zlib1g-dev # macOS-specific build stuff - os: osx osx_image: xcode9.2 ippsample/examples/0000755000175000017500000000000013240604116013355 5ustar tilltillippsample/examples/set-attrs-hold.test0000644000175000017500000000751613240604116017141 0ustar tilltill# Test print-job and later job-hold-until attribute { # The name of the test... NAME "Disable printer..." # The resource to use for the POST RESOURCE /admin/ # The operation to use OPERATION pause-printer # Attributes, starting in the operation group... GROUP operation ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $uri ATTR name requesting-user-name $user # What statuses are OK? STATUS successful-ok STATUS successful-ok-ignored-or-substituted-attributes } { # The name of the test... NAME "Print job" # The resource to use for the POST # RESOURCE /admin # The operation to use OPERATION print-job # Attributes, starting in the operation group... GROUP operation ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $uri ATTR name requesting-user-name $user ATTR mimetype document-format application/postscript GROUP job ATTR integer copies 1 FILE ../data/testprint.ps # What statuses are OK? STATUS successful-ok STATUS successful-ok-ignored-or-substituted-attributes # What attributes do we expect? EXPECT job-id EXPECT job-uri } { # The name of the test... NAME "Get job attrs" # The resource to use for the POST RESOURCE / # The operation to use OPERATION get-job-attributes # Attributes, starting in the operation group... GROUP operation ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $uri ATTR integer job-id $job-id # What statuses are OK? STATUS successful-ok STATUS successful-ok-ignored-or-substituted-attributes # What attributes do we expect? EXPECT job-state EXPECT job-hold-until } { # The name of the test... NAME "Set job attrs with job-hold-until" # The resource to use for the POST # RESOURCE /admin # The operation to use OPERATION set-job-attributes # Attributes, starting in the operation group... GROUP operation ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $uri ATTR integer job-id $job-id ATTR name requesting-user-name $user GROUP job ATTR name job-hold-until 00:30:00 # What statuses are OK? STATUS successful-ok STATUS successful-ok-ignored-or-substituted-attributes } { # The name of the test... NAME "Get job attrs again" # The resource to use for the POST RESOURCE / # The operation to use OPERATION get-job-attributes # Attributes, starting in the operation group... GROUP operation ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $uri ATTR integer job-id $job-id # What statuses are OK? STATUS successful-ok STATUS successful-ok-ignored-or-substituted-attributes # What attributes do we expect? EXPECT job-state EXPECT job-hold-until } { # The name of the test... NAME "Enable printer..." # The resource to use for the POST RESOURCE /admin/ # The operation to use OPERATION resume-printer # Attributes, starting in the operation group... GROUP operation ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $uri ATTR name requesting-user-name $user # What statuses are OK? STATUS successful-ok STATUS successful-ok-ignored-or-substituted-attributes } { # The name of the test... NAME "Get job attrs (last time)" # The resource to use for the POST RESOURCE / # The operation to use OPERATION get-job-attributes # Attributes, starting in the operation group... GROUP operation ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $uri ATTR integer job-id $job-id # What statuses are OK? STATUS successful-ok STATUS successful-ok-ignored-or-substituted-attributes # What attributes do we expect? EXPECT job-state EXPECT job-hold-until } ippsample/examples/testfile.ps0000644000175000017500000004165113240604116015547 0ustar tilltill%!PS-Adobe-3.0 %%BoundingBox: 0 0 612 792 %%Pages: 1 %%LanguageLevel: 1 %%DocumentData: Clean7Bit %%DocumentSuppliedResources: procset testprint/1.3 %%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman %%Creator: Michael Sweet, Apple Inc. %%CreationDate: D:20070606214000+0500 %%Title: Test Page %%EndComments %%BeginProlog %%BeginResource procset testprint 1.3 0 % % PostScript test page for CUPS. % % Copyright 2007-2011 Apple Inc. % Copyright 1993-2007 Easy Software Products % % These coded instructions, statements, and computer programs are the % property of Apple Inc. and are protected by Federal copyright law. % Distribution and use rights are outlined in the file "LICENSE.txt" % which is included with the CUPS source distribution. % /SEXTANT { % Draw a color wheel sextant... % (name) white radius r g b SEXTANT - % Loop through 100 shades... 0 0.010101 0.98 { % Set the color... dup 0.75 le { % Get "white" value % Start from black dup 0.75 div % val2 = val / 0.75 0 index 5 index mul % R = R * val2 1 index 5 index mul % G = G * val2 2 index 5 index mul % B = B * val2 4 -1 roll pop % Discard val2 } { % Fade to white dup neg 1 add 4 mul % val2 = (1 - val) * 4 0 index 5 index mul % R = R * val2 1 index neg 1 add add % + (1 - val2) 1 index 5 index mul % G = G * val2 2 index neg 1 add add % + (1 - val2) 2 index 5 index mul % B = B * val2 3 index neg 1 add add % + (1 - val2) 4 -1 roll pop % Discard val2 } ifelse setrgbcolor % Set the color... % Draw the polygon... newpath % Start a new path... dup 5 index mul % r1 = radius * val 0 0 3 -1 roll 0 60 arc % Draw the inner arc dup 0.010101 add 5 index mul% r2 = (radius + 0.010101) * val 0 0 3 -1 roll 60 0 arcn % Draw the outer arc closepath % Close the path fill % Fill it... pop % Pop value... } for % Draw a line around the polygons... pop pop pop dup % Pop R, G, B, start 0 setgray % Black newpath 0 0 moveto % Center 0 0 3 -1 roll 0 60 arc % Arc around octant closepath % Back to center stroke % Stroke it... % Draw the label... dup % Save radius dup 30 cos mul % X = radius * cos(30) exch 30 sin mul % Y = radius * sin(30) moveto % Position label gsave 30 rotate % Rotate label dup 0.05 mul % Offset to the right exch -0.05 mul % and down... rmoveto % Offset label show % Show label grestore } bind def /CENTER { % Draw centered text % (name) CENTER - dup stringwidth pop % Get the width of the string 0.5 mul neg 0 rmoveto % Shift left 1/2 of the distance show % Show the string } bind def /RIGHT { % Draw right-justified text % (name) RIGHT - dup stringwidth pop % Get the width of the string neg 0 rmoveto % Shift left the entire distance show % Show the string } bind def /NUMBER { % Draw a number % power n NUMBER - 1 index 1 eq { % power == 1? round cvi exch pop % Convert "n" to integer } { 1 index mul round exch div % Truncate extra decimal places } ifelse 100 string cvs show % Convert to a string and show it... } bind def /CUPSLOGO { % Draw the CUPS logo % height CUPSLOGO % Start with a big C... /Helvetica findfont 1 index scalefont setfont 0 setgray 0 0 moveto (C) show % Then "UNIX Printing System" much smaller... /Helvetica-Bold findfont 1 index 9 div scalefont setfont 0.25 mul dup dup 2.0 mul moveto (UNIX) show dup dup 1.6 mul moveto (Printing) show dup 1.2 mul moveto (System) show } bind def %%EndResource %%EndProlog %%Page: 1 1 gsave % Determine the imageable area and device resolution... initclip newpath clippath pathbbox % Get bounding rectangle 72 div /pageTop exch def % Get top margin in inches 72 div /pageRight exch def % Get right margin in inches 72 div /pageBottom exch def % Get bottom margin in inches 72 div /pageLeft exch def % Get left margin in inches 4 setlinewidth % Draw wide lines 0 setgray closepath stroke % Draw a clipping rectangle /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom 72 72 dtransform % Get device resolution per inch /yResolution exch abs def % yResolution = abs(yres) /xResolution exch abs def % xResolution = abs(xres) % Figure out the sizes of things... /wheelSize % size of wheels pageWidth pageHeight lt { pageWidth 9 mul } { pageHeight 7 mul } ifelse def % Create fonts... /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold pageHeight 3 mul scalefont def % size = pageHeight * 3 (nominally 33) /mediumFont /Helvetica findfont % mediumFont = Helvetica pageHeight 1.5 mul scalefont def % size = pageHeight * 1.5 (nominally 16.5) /smallFont /Times-Roman findfont % smallFont = Times-Roman pageHeight scalefont def % size = pageHeight (nominally 11) % Draw rulers along the edges... /CENTIMETER 72 2.54 div def /MILLIMETER 72 25.4 div def /Times-Roman findfont % Font for ruler numbers 11 scalefont setfont % 11 points gsave % Left side inches pageLeft 72 mul 0 translate % Offset left edge 1 setlinewidth % Draw normal lines 72 72 pageTop 72 mul { % Height inches dup dup 0 exch moveto 24 0 rlineto stroke % Draw tic mark 24 exch pageHeight sub moveto % Draw number 72 div cvi 10 string cvs RIGHT } for 0.5 setlinewidth % Draw thin lines 18 18 pageTop 72 mul { % 1/4 inches 0 exch moveto 15 0 rlineto stroke % Draw tic mark } for 9 9 pageTop 72 mul { % 1/8 inches 0 exch moveto 6 0 rlineto stroke % Draw tic mark } for grestore gsave % Bottom inches 0 pageBottom 72 mul translate % Offset bottom edge 1 setlinewidth % Draw normal lines 72 72 pageRight 72 mul { % Width inches dup dup 0 moveto 0 24 rlineto stroke % Draw tic mark 3 add 27 pageHeight sub moveto % Draw number 72 div cvi 10 string cvs show } for 0.5 setlinewidth % Draw thin lines 18 18 pageRight 72 mul { % 1/4 inches 0 moveto 0 15 rlineto stroke % Draw tic mark } for 9 9 pageRight 72 mul { % 1/8 inches 0 moveto 0 6 rlineto stroke % Draw tic mark } for grestore gsave % Right side centimeters pageRight 72 mul 0 translate % Offset right edge 1 setlinewidth % Draw normal lines CENTIMETER CENTIMETER pageTop 72 mul { % Height centimeters 0 exch moveto -24 0 rlineto stroke% Draw tic mark } for 1 1 pageTop 2.54 mul { % Height labels dup -24 exch CENTIMETER mul pageHeight sub moveto % Draw number cvi 10 string cvs show } for 0.5 setlinewidth % Draw thin lines 0 0.5 CENTIMETER mul pageTop 72 mul { % 1/2 centimeters 0 exch moveto -15 0 rlineto stroke% Draw tic mark } for 0 MILLIMETER pageTop 72 mul { % Millimeters 0 exch moveto -6 0 rlineto stroke % Draw tic mark } for grestore gsave % Top centimeters 0 pageTop 72 mul translate % Offset top edge 1 setlinewidth % Draw normal lines CENTIMETER CENTIMETER pageRight 72 mul { % Width centimeters 0 moveto 0 -24 rlineto stroke % Draw tic mark } for 1 1 pageRight 2.54 mul { % Width labels dup CENTIMETER mul 3 add -24 moveto % Draw number cvi 10 string cvs show } for 0.5 setlinewidth % Draw thin lines 0 0.5 CENTIMETER mul pageRight 72 mul { % 1/2 centimeters 0 moveto 0 -15 rlineto stroke % Draw tic mark } for 0 MILLIMETER pageRight 72 mul { % Millimeters 0 moveto 0 -6 rlineto stroke % Draw tic mark } for grestore % Offset page to account for lower-left margin... pageLeft 72 mul pageBottom 72 mul translate % Set text font and color... mediumFont setfont % Font 0 setgray % Color 1 setlinewidth % Draw normal lines % Draw the color wheel... gsave % Position the wheel on the left side... pageWidth 18 mul % x = pageWidth * 1/4 * 72 pageHeight 54 mul % y = pageHeight * 3/4 * 72 translate % Size the wheel... wheelSize % Draw the colors... dup (C) 3 -1 roll 0 1 1 SEXTANT 60 rotate dup (M) 3 -1 roll 1 0 1 SEXTANT 60 rotate dup (Y) 3 -1 roll 1 1 0 SEXTANT 60 rotate dup (R) 3 -1 roll 1 0 0 SEXTANT 60 rotate dup (G) 3 -1 roll 0 1 0 SEXTANT 60 rotate dup (B) 3 -1 roll 0 0 1 SEXTANT 60 rotate pop grestore % Label the color wheel... pageWidth 18 mul % x = pageWidth * 1/4 * 72 pageHeight 43 mul % y = pageHeight * 19/32 * 72 moveto % Position the text (Color Wheel) CENTER % Show the text centered % Draw the gray ramp... gsave % Position the gray ramp in the center... pageWidth 36 mul % x = pageWidth * 1/2 * 72 pageHeight 54 mul % y = pageHeight * 3/4 * 72 wheelSize sub % - wheelSize translate % Loop through 100 shades... 0 0.010101 0.98 { % Set the color... dup setgray % Set the grayscale... % Draw the polygon... newpath % Start a new path... wheelSize -0.2 mul % X = -wheelSize / 5 1 index 2 mul wheelSize mul % Y = val * 2 * wheelSize moveto % Move there... wheelSize 0.4 mul 0 rlineto % Right side... wheelSize 0.2 mul % X = wheelSize / 5 1 index 0.010101 add 2 mul wheelSize mul % Y = (val + 0.010101) * 2 * wheelSize lineto % Move there... wheelSize -0.4 mul 0 rlineto % Left side... closepath % Close the path fill % Fill it... pop % Pop value... } for 0 setgray % Black newpath % Start a new path wheelSize -0.2 mul 0 moveto % Bottom left wheelSize 0.4 mul 0 rlineto % Bottom right 0 wheelSize 2 mul rlineto % Upper right wheelSize -0.4 mul 0 rlineto % Upper left closepath % Close the path stroke % Stroke it... 0 wheelSize -0.2 mul moveto % Center bottom for label (K) CENTER % Center K at bottom 0 wheelSize 2.05 mul moveto % Center top for label (W) CENTER % Center W at top grestore % Label the gray ramp... pageWidth 36 mul % x = pageWidth * 1/2 * 72 pageHeight 43 mul % y = pageHeight * 19/32 * 72 moveto % Position the text (Gray Ramp) CENTER % Show the text centered % Draw radial lines... gsave 0 setlinewidth % 1 pixel lines % Position the lines on the left side... pageWidth 54 mul % x = pageWidth * 3/4 * 72 pageHeight 54 mul % y = pageHeight * 3/4 * 72 translate % Size the wheel... wheelSize % Loop at 1 degree increments 0 1 359 { pop % Discard angle - not used 0 0 moveto % Start line at the center dup 0 lineto % Draw to the radius 1 rotate % Rotate 1 degree } for pop % Discard radius - not needed anymore stroke % Draw lines... grestore % Label the lines... pageWidth 54 mul % x = pageWidth * 3/4 * 72 pageHeight 43 mul % y = pageHeight * 19/32 * 72 moveto % Position the text (1 Degree Radial Lines) CENTER % Show the text centered % Imageable area... pageHeight 15 mul % Height of imageable area pageWidth 4.5 mul % x = pageWidth * 1/16 * 72 pageHeight 35.5 mul % y = pageHeight * 1/2 * 72 2 index sub % y -= height pageWidth 28 mul % width = pageWidth * 1/4 * 72 3 index % height 0.5 setgray rectfill % Draw a shadow pageWidth 4 mul % x = pageWidth * 1/16 * 72 pageHeight 36 mul % y = pageHeight * 1/2 * 72 2 index sub % y -= height pageWidth 28 mul % width = pageWidth * 3/8 * 72 3 index % height 4 copy 1 setgray rectfill % Clear the box to white 0 setgray rectstroke % Draw a black box around it... pop % Discard height % Label the imageable area... pageWidth 4 mul % x = pageWidth * 1/16 * 72 pageHeight 37 mul % y = pageHeight * 1/2 * 72 moveto % Position the text mediumFont setfont % Font (Imageable Area) show % Show the text smallFont setfont % Font pageWidth 14 mul % x = pageWidth * 3/16 * 72 pageHeight 36 mul % y = pageWidth * 1/2 * 72 pageHeight -2 mul add % y -= 2 * smallFont height % Page Size inches 2 copy moveto % Move to x & y (Page Size: ) RIGHT % Label 100 pageWidth NUMBER % pageWidth (x) show % "x" 100 pageHeight NUMBER % pageHeight (in) show % "in" % Page Size millimeters pageHeight sub % Move down... 2 copy moveto % Move to x & y 10 pageWidth 25.4 mul NUMBER % pageWidth (x) show % "x" 10 pageHeight 25.4 mul NUMBER % pageHeight (mm) show % "mm" % Lower-left inches pageHeight 2 mul sub % Move down... 2 copy moveto % Move to x & y (Lower-Left: ) RIGHT % Label 100 pageLeft NUMBER % pageLeft (x) show % "x" 100 pageBottom NUMBER % pageBottom (in) show % "in" % Lower-left millimeters pageHeight sub % Move down... 2 copy moveto % Move to x & y 10 pageLeft 25.4 mul NUMBER % pageLeft (x) show % "x" 10 pageBottom 25.4 mul NUMBER % pageBottom (mm) show % "mm" % Upper-right inches pageHeight 2 mul sub % Move down... 2 copy moveto % Move to x & y (Upper-Right: ) RIGHT % Label 100 pageRight NUMBER % pageRight (x) show % "x" 100 pageTop NUMBER % pageTop (in) show % "in" % Upper-right millimeters pageHeight sub % Move down... 2 copy moveto % Move to x & y 10 pageRight 25.4 mul NUMBER % pageRight (x) show % "x" 10 pageTop 25.4 mul NUMBER % pageTop (mm) show % "mm" % Resolution dots-per-inch pageHeight 2 mul sub % Move down... 2 copy moveto % Move to x & y (Resolution: ) RIGHT % Label 1 xResolution NUMBER % xResolution (x) show % "x" 1 yResolution NUMBER % yResolution (dpi) show % "dpi" % Resolution dots-per-meter pageHeight sub % Move down... moveto % Move to x & y 1 xResolution 39.27 mul NUMBER % xResolution (x) show % "x" 1 yResolution 39.27 mul NUMBER % yResolution (dpm) show % "dpm" % Interpreter Information... pageHeight 15 mul % Height of interpreter information pageWidth 40.5 mul % x = pageWidth * 9/16 * 72 pageHeight 35.5 mul % y = pageHeight * 1/2 * 72 2 index sub % y -= height pageWidth 28 mul % width = pageWidth * 1/4 * 72 3 index % height 0.5 setgray rectfill % Draw a shadow pageWidth 40 mul % x = pageWidth * 9/16 * 72 pageHeight 36 mul % y = pageHeight * 1/2 * 72 2 index sub % y -= height pageWidth 28 mul % width = pageWidth * 3/8 * 72 3 index % height 4 copy 1 setgray rectfill % Clear the box to white 0 setgray rectstroke % Draw a black box around it... pop % Discard height % Label the interpreter info... pageWidth 40 mul % x = pageWidth * 9/16 * 72 pageHeight 37 mul % y = pageHeight * 1/2 * 72 moveto % Position the text mediumFont setfont % Font (Interpreter Information) show % Show the text smallFont setfont % Font pageWidth 49 mul % x = pageWidth * 11/16 * 72 pageHeight 36 mul % y = pageWidth * 1/2 * 72 pageHeight 2 mul sub % y -= 2 * smallFont height % Language level 2 copy moveto % Move to x & y (PostScript: ) RIGHT % Label (Level ) show % "Level " 1 languagelevel NUMBER % Language level % Version pageHeight 2 mul sub % Move down... 2 copy moveto % Move to x & y (Version: ) RIGHT % Label version show % Version ( \() show % " (" 1 revision NUMBER % Revision (\)) show % ")" % Product pageHeight 2 mul sub % Move down... 2 copy moveto % Move to x & y (Product: ) RIGHT % Label product show % Product name % Serial Number pageHeight 2 mul sub % Move down... moveto % Move to x & y (Serial #: ) RIGHT % Label 1 serialnumber NUMBER % S/N % Draw the label at the top... pageWidth 36 mul % Center of page pageHeight 66 mul % Top of page (11/12ths) moveto % Position text bigFont setfont % Font (Printer Test Page) CENTER % Show text centered % Draw the copyright notice at the bottom... pageWidth 17 mul % Center of page pageHeight 10 mul % Bottom of page moveto % Position text (Printed Using CUPS v1.3.x) show pageWidth 17 mul % Left side of page pageHeight 8 mul % Move down... 2 copy moveto % Position text smallFont setfont % Font (Copyright 2007 Apple Inc., All Rights Reserved. CUPS and the CUPS logo are the trademark) show pageHeight 2 add sub % Move down... 2 copy moveto % Position text (property of Apple Inc., 1 Infinite Loop, Cupertino, CA 95014, USA.) show pageHeight 2 mul 4 add sub % Move down... moveto % Position text (Need help? Contact your operating system vendor or visit "http://www.cups.org/".) show % Then the CUPS logo.... gsave pageWidth 4 mul pageHeight 4 mul translate pageWidth 15 mul CUPSLOGO grestore % Show the page... grestore showpage % % End of "$Id: testfile.ps 6649 2007-07-11 21:46:42Z mike $". % %%EOF ippsample/examples/create-job-sheets.test0000644000175000017500000000236313240604116017566 0ustar tilltill# Test create-job + send-document with job-sheets attribute { # The name of the test... NAME "Print test page using create-job" # The resource to use for the POST # RESOURCE /admin # The operation to use OPERATION create-job # Attributes, starting in the operation group... GROUP operation ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $uri ATTR name requesting-user-name $user GROUP job ATTR integer copies 1 ATTR name job-sheets standard # What statuses are OK? STATUS successful-ok STATUS successful-ok-ignored-or-substituted-attributes # What attributes do we expect? EXPECT job-id EXPECT job-uri } { # The name of the test... NAME "... and send-document" # The resource to use for the POST # RESOURCE /admin # The operation to use OPERATION send-document # Attributes, starting in the operation group... GROUP operation ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $uri ATTR integer job-id $job-id ATTR name requesting-user-name $user ATTR boolean last-document true FILE ../data/testprint.ps # What statuses are OK? STATUS successful-ok STATUS successful-ok-ignored-or-substituted-attributes } ippsample/examples/onepage-letter.ps0000644000175000017500000174421313240604116016650 0ustar tilltill%!PS-Adobe-3.0 %XpdfVersion: 3.03 %%Creator: Scribus 1.4.0.rc5 %%Title: %%LanguageLevel: 3 %%DocumentSuppliedResources: (atend) %%DocumentMedia: plain 612 792 0 () () %%BoundingBox: 0 0 612 792 %%Pages: 1 %%EndComments %%BeginDefaults %%PageMedia: plain %%EndDefaults %%BeginProlog %%BeginResource: procset xpdf 3.03 0 %%Copyright: Copyright 1996-2011 Glyph & Cog, LLC /xpdf 75 dict def xpdf begin % PDF special state /pdfDictSize 15 def /pdfSetup { /setpagedevice where { pop 2 dict begin /Policies 1 dict dup begin /PageSize 6 def end def { /Duplex true def } if currentdict end setpagedevice } { pop } ifelse } def /pdfSetupPaper { 2 array astore /setpagedevice where { pop 2 dict begin /PageSize exch def /ImagingBBox null def currentdict end setpagedevice } { pop } ifelse } def /pdfStartPage { pdfDictSize dict begin /pdfFillCS [] def /pdfFillXform {} def /pdfStrokeCS [] def /pdfStrokeXform {} def /pdfFill [0] def /pdfStroke [0] def /pdfFillOP false def /pdfStrokeOP false def /pdfLastFill false def /pdfLastStroke false def /pdfTextMat [1 0 0 1 0 0] def /pdfFontSize 0 def /pdfCharSpacing 0 def /pdfTextRender 0 def /pdfTextRise 0 def /pdfWordSpacing 0 def /pdfHorizScaling 1 def /pdfTextClipPath [] def } def /pdfEndPage { end } def % PDF color state /cs { /pdfFillXform exch def dup /pdfFillCS exch def setcolorspace } def /CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def setcolorspace } def /sc { pdfLastFill not { pdfFillCS setcolorspace } if dup /pdfFill exch def aload pop pdfFillXform setcolor /pdfLastFill true def /pdfLastStroke false def } def /SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if dup /pdfStroke exch def aload pop pdfStrokeXform setcolor /pdfLastStroke true def /pdfLastFill false def } def /op { /pdfFillOP exch def pdfLastFill { pdfFillOP setoverprint } if } def /OP { /pdfStrokeOP exch def pdfLastStroke { pdfStrokeOP setoverprint } if } def /fCol { pdfLastFill not { pdfFillCS setcolorspace pdfFill aload pop pdfFillXform setcolor pdfFillOP setoverprint /pdfLastFill true def /pdfLastStroke false def } if } def /sCol { pdfLastStroke not { pdfStrokeCS setcolorspace pdfStroke aload pop pdfStrokeXform setcolor pdfStrokeOP setoverprint /pdfLastStroke true def /pdfLastFill false def } if } def % build a font /pdfMakeFont { 4 3 roll findfont 4 2 roll matrix scale makefont dup length dict begin { 1 index /FID ne { def } { pop pop } ifelse } forall /Encoding exch def currentdict end definefont pop } def /pdfMakeFont16 { exch findfont dup length dict begin { 1 index /FID ne { def } { pop pop } ifelse } forall /WMode exch def currentdict end definefont pop } def /pdfMakeFont16L3 { 1 index /CIDFont resourcestatus { pop pop 1 index /CIDFont findresource /CIDFontType known } { false } ifelse { 0 eq { /Identity-H } { /Identity-V } ifelse exch 1 array astore composefont pop } { pdfMakeFont16 } ifelse } def % graphics state operators /q { gsave pdfDictSize dict begin } def /Q { end grestore /pdfLastFill where { pop pdfLastFill { pdfFillOP setoverprint } { pdfStrokeOP setoverprint } ifelse } if } def /cm { concat } def /d { setdash } def /i { setflat } def /j { setlinejoin } def /J { setlinecap } def /M { setmiterlimit } def /w { setlinewidth } def % path segment operators /m { moveto } def /l { lineto } def /c { curveto } def /re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath } def /h { closepath } def % path painting operators /S { sCol stroke } def /Sf { fCol stroke } def /f { fCol fill } def /f* { fCol eofill } def % clipping operators /W { clip newpath } def /W* { eoclip newpath } def /Ws { strokepath clip newpath } def % text state operators /Tc { /pdfCharSpacing exch def } def /Tf { dup /pdfFontSize exch def dup pdfHorizScaling mul exch matrix scale pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put exch findfont exch makefont setfont } def /Tr { /pdfTextRender exch def } def /Ts { /pdfTextRise exch def } def /Tw { /pdfWordSpacing exch def } def /Tz { /pdfHorizScaling exch def } def % text positioning operators /Td { pdfTextMat transform moveto } def /Tm { /pdfTextMat exch def } def % text string operators /xyshow where { pop /xyshow2 { dup length array 0 2 2 index length 1 sub { 2 index 1 index 2 copy get 3 1 roll 1 add get pdfTextMat dtransform 4 2 roll 2 copy 6 5 roll put 1 add 3 1 roll dup 4 2 roll put } for exch pop xyshow } def }{ /xyshow2 { currentfont /FontType get 0 eq { 0 2 3 index length 1 sub { currentpoint 4 index 3 index 2 getinterval show moveto 2 copy get 2 index 3 2 roll 1 add get pdfTextMat dtransform rmoveto } for } { 0 1 3 index length 1 sub { currentpoint 4 index 3 index 1 getinterval show moveto 2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get pdfTextMat dtransform rmoveto } for } ifelse pop pop } def } ifelse /cshow where { pop /xycp { 0 3 2 roll { pop pop currentpoint 3 2 roll 1 string dup 0 4 3 roll put false charpath moveto 2 copy get 2 index 2 index 1 add get pdfTextMat dtransform rmoveto 2 add } exch cshow pop pop } def }{ /xycp { currentfont /FontType get 0 eq { 0 2 3 index length 1 sub { currentpoint 4 index 3 index 2 getinterval false charpath moveto 2 copy get 2 index 3 2 roll 1 add get pdfTextMat dtransform rmoveto } for } { 0 1 3 index length 1 sub { currentpoint 4 index 3 index 1 getinterval false charpath moveto 2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get pdfTextMat dtransform rmoveto } for } ifelse pop pop } def } ifelse /Tj { fCol 0 pdfTextRise pdfTextMat dtransform rmoveto currentpoint 4 2 roll pdfTextRender 1 and 0 eq { 2 copy xyshow2 } if pdfTextRender 3 and dup 1 eq exch 2 eq or { 3 index 3 index moveto 2 copy currentfont /FontType get 3 eq { fCol } { sCol } ifelse xycp currentpoint stroke moveto } if pdfTextRender 4 and 0 ne { 4 2 roll moveto xycp /pdfTextClipPath [ pdfTextClipPath aload pop {/moveto cvx} {/lineto cvx} {/curveto cvx} {/closepath cvx} pathforall ] def currentpoint newpath moveto } { pop pop pop pop } ifelse 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def /TJm { 0.001 mul pdfFontSize mul pdfHorizScaling mul neg 0 pdfTextMat dtransform rmoveto } def /TJmV { 0.001 mul pdfFontSize mul neg 0 exch pdfTextMat dtransform rmoveto } def /Tclip { pdfTextClipPath cvx exec clip newpath /pdfTextClipPath [] def } def % Level 2/3 image operators /pdfImBuf 100 string def /pdfImStr { 2 copy exch length lt { 2 copy get exch 1 add exch } { () } ifelse } def /skipEOD { { currentfile pdfImBuf readline not { pop exit } if (%-EOD-) eq { exit } if } loop } def /pdfIm { image skipEOD } def /pdfMask { /ReusableStreamDecode filter skipEOD /maskStream exch def } def /pdfMaskEnd { maskStream closefile } def /pdfMaskInit { /maskArray exch def /maskIdx 0 def } def /pdfMaskSrc { maskIdx maskArray length lt { maskArray maskIdx get /maskIdx maskIdx 1 add def } { () } ifelse } def /pdfImM { fCol imagemask skipEOD } def /pr { 2 index 2 index 3 2 roll putinterval 4 add } def /pdfImClip { gsave 0 2 4 index length 1 sub { dup 4 index exch 2 copy get 5 index div put 1 add 3 index exch 2 copy get 3 index div put } for pop pop rectclip } def /pdfImClipEnd { grestore } def % shading operators /colordelta { false 0 1 3 index length 1 sub { dup 4 index exch get 3 index 3 2 roll get sub abs 0.004 gt { pop true } if } for exch pop exch pop } def /funcCol { func n array astore } def /funcSH { dup 0 eq { true } { dup 6 eq { false } { 4 index 4 index funcCol dup 6 index 4 index funcCol dup 3 1 roll colordelta 3 1 roll 5 index 5 index funcCol dup 3 1 roll colordelta 3 1 roll 6 index 8 index funcCol dup 3 1 roll colordelta 3 1 roll colordelta or or or } ifelse } ifelse { 1 add 4 index 3 index add 0.5 mul exch 4 index 3 index add 0.5 mul exch 6 index 6 index 4 index 4 index 4 index funcSH 2 index 6 index 6 index 4 index 4 index funcSH 6 index 2 index 4 index 6 index 4 index funcSH 5 3 roll 3 2 roll funcSH pop pop } { pop 3 index 2 index add 0.5 mul 3 index 2 index add 0.5 mul funcCol sc dup 4 index exch mat transform m 3 index 3 index mat transform l 1 index 3 index mat transform l mat transform l pop pop h f* } ifelse } def /axialCol { dup 0 lt { pop t0 } { dup 1 gt { pop t1 } { dt mul t0 add } ifelse } ifelse func n array astore } def /axialSH { dup 2 lt { true } { dup 8 eq { false } { 2 index axialCol 2 index axialCol colordelta } ifelse } ifelse { 1 add 3 1 roll 2 copy add 0.5 mul dup 4 3 roll exch 4 index axialSH exch 3 2 roll axialSH } { pop 2 copy add 0.5 mul axialCol sc exch dup dx mul x0 add exch dy mul y0 add 3 2 roll dup dx mul x0 add exch dy mul y0 add dx abs dy abs ge { 2 copy yMin sub dy mul dx div add yMin m yMax sub dy mul dx div add yMax l 2 copy yMax sub dy mul dx div add yMax l yMin sub dy mul dx div add yMin l h f* } { exch 2 copy xMin sub dx mul dy div add xMin exch m xMax sub dx mul dy div add xMax exch l exch 2 copy xMax sub dx mul dy div add xMax exch l xMin sub dx mul dy div add xMin exch l h f* } ifelse } ifelse } def /radialCol { dup t0 lt { pop t0 } { dup t1 gt { pop t1 } if } ifelse func n array astore } def /radialSH { dup 0 eq { true } { dup 8 eq { false } { 2 index dt mul t0 add radialCol 2 index dt mul t0 add radialCol colordelta } ifelse } ifelse { 1 add 3 1 roll 2 copy add 0.5 mul dup 4 3 roll exch 4 index radialSH exch 3 2 roll radialSH } { pop 2 copy add 0.5 mul dt mul t0 add radialCol sc encl { exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add 0 360 arc h dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add 360 0 arcn h f } { 2 copy dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add a1 a2 arcn dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add a2 a1 arcn h dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add a1 a2 arc dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add a2 a1 arc h f } ifelse } ifelse } def end %%EndResource /CIDInit /ProcSet findresource begin 10 dict begin begincmap /CMapType 1 def /CMapName /Identity-H def /CIDSystemInfo 3 dict dup begin /Registry (Adobe) def /Ordering (Identity) def /Supplement 0 def end def 1 begincodespacerange <0000> endcodespacerange 0 usefont 1 begincidrange <0000> 0 endcidrange endcmap currentdict CMapName exch /CMap defineresource pop end 10 dict begin begincmap /CMapType 1 def /CMapName /Identity-V def /CIDSystemInfo 3 dict dup begin /Registry (Adobe) def /Ordering (Identity) def /Supplement 0 def end def /WMode 1 def 1 begincodespacerange <0000> endcodespacerange 0 usefont 1 begincidrange <0000> 0 endcidrange endcmap currentdict CMapName exch /CMap defineresource pop end end %%EndProlog %%BeginSetup xpdf begin %%BeginResource: font T3_31_0 8 dict begin /FontType 3 def /FontMatrix [0.001 0 0 0.001 0 0] def /FontBBox [15 -210 824 728] def /Encoding 256 array def 0 1 255 { Encoding exch /.notdef put } for /BuildGlyph { exch /CharProcs get exch 2 copy known not { pop /.notdef } if get exec } bind def /BuildChar { 1 index /Encoding get exch get 1 index /BuildGlyph get exec } bind def /CharProcs 19 dict def CharProcs begin /D { 672 0 72 0 672 716 setcachedevice q 72.26562 715.82812 m 72.26562 715.82812 336.42188 715.82812 336.42188 715.82812 c 336.42188 715.82812 425.78125 715.82812 472.65625 702.15625 c 472.65625 702.15625 535.64062 683.59375 580.5625 636.23438 c 580.5625 636.23438 625.48438 588.875 648.92188 520.26562 c 648.92188 520.26562 672.35938 451.65625 672.35938 351.07812 c 672.35938 351.07812 672.35938 262.70312 650.39062 198.73438 c 650.39062 198.73438 623.53125 120.60938 573.73438 72.26562 c 573.73438 72.26562 536.14062 35.64062 472.17188 15.14063 c 472.17188 15.14063 424.3125 0 344.23438 0 c 344.23438 0 72.26562 0 72.26562 0 c 72.26562 0 72.26562 715.82812 72.26562 715.82812 c 72.26562 715.82812 72.26562 715.82812 72.26562 715.82812 c h 216.79688 594.73438 m 216.79688 594.73438 216.79688 120.60938 216.79688 120.60938 c 216.79688 120.60938 324.70312 120.60938 324.70312 120.60938 c 324.70312 120.60938 385.25 120.60938 412.10938 127.4375 c 412.10938 127.4375 447.26562 136.23438 470.45313 157.21875 c 470.45313 157.21875 493.65625 178.21875 508.29688 226.3125 c 508.29688 226.3125 522.95312 274.42188 522.95312 357.42188 c 522.95312 357.42188 522.95312 440.4375 508.29688 484.85938 c 508.29688 484.85938 493.65625 529.29688 467.28125 554.20312 c 467.28125 554.20312 440.92188 579.10938 400.39062 587.89062 c 400.39062 587.89062 370.125 594.73438 281.73438 594.73438 c 281.73438 594.73438 216.79688 594.73438 216.79688 594.73438 c h f* Q } def /L { 581 0 77 0 581 710 setcachedevice q 76.65625 0 m 76.65625 0 76.65625 709.96875 76.65625 709.96875 c 76.65625 709.96875 221.1875 709.96875 221.1875 709.96875 c 221.1875 709.96875 221.1875 120.60938 221.1875 120.60938 c 221.1875 120.60938 580.5625 120.60938 580.5625 120.60938 c 580.5625 120.60938 580.5625 0 580.5625 0 c 580.5625 0 76.65625 0 76.65625 0 c h f* Q } def /P { 621 0 73 0 621 716 setcachedevice q 72.75 0 m 72.75 0 72.75 715.82812 72.75 715.82812 c 72.75 715.82812 304.6875 715.82812 304.6875 715.82812 c 304.6875 715.82812 436.53125 715.82812 476.5625 705.07812 c 476.5625 705.07812 538.09375 688.96875 579.59375 635.01562 c 579.59375 635.01562 621.09375 581.0625 621.09375 495.60938 c 621.09375 495.60938 621.09375 429.6875 597.17188 384.76562 c 597.17188 384.76562 573.25 339.84375 536.375 314.20312 c 536.375 314.20312 499.51562 288.57812 461.42188 280.28125 c 461.42188 280.28125 409.67188 270.01562 311.53125 270.01562 c 311.53125 270.01562 217.28125 270.01562 217.28125 270.01562 c 217.28125 270.01562 217.28125 0 217.28125 0 c 217.28125 0 72.75 0 72.75 0 c 72.75 0 72.75 0 72.75 0 c h 217.28125 594.73438 m 217.28125 594.73438 217.28125 391.60938 217.28125 391.60938 c 217.28125 391.60938 296.39062 391.60938 296.39062 391.60938 c 296.39062 391.60938 381.84375 391.60938 410.64062 402.82812 c 410.64062 402.82812 439.45312 414.0625 455.8125 437.98438 c 455.8125 437.98438 472.17188 461.92188 472.17188 493.65625 c 472.17188 493.65625 472.17188 532.71875 449.21875 558.10938 c 449.21875 558.10938 426.26562 583.5 391.10938 589.84375 c 391.10938 589.84375 365.23438 594.73438 287.10938 594.73438 c 287.10938 594.73438 217.28125 594.73438 217.28125 594.73438 c h f* Q } def /S { 618 0 36 -13 618 728 setcachedevice q 36.14062 232.90625 m 36.14062 232.90625 176.76562 246.57812 176.76562 246.57812 c 176.76562 246.57812 189.45312 175.78125 228.26562 142.57812 c 228.26562 142.57812 267.09375 109.375 333.01562 109.375 c 333.01562 109.375 402.82812 109.375 438.23438 138.90625 c 438.23438 138.90625 473.64062 168.45312 473.64062 208.01562 c 473.64062 208.01562 473.64062 233.40625 458.73438 251.21875 c 458.73438 251.21875 443.84375 269.04688 406.73438 282.23438 c 406.73438 282.23438 381.34375 291.01562 291.01562 313.48438 c 291.01562 313.48438 174.8125 342.28125 127.9375 384.28125 c 127.9375 384.28125 62.01562 443.35938 62.01562 528.32812 c 62.01562 528.32812 62.01562 583.01562 93.01562 630.60938 c 93.01562 630.60938 124.03125 678.21875 182.375 703.125 c 182.375 703.125 240.71875 728.03125 323.25 728.03125 c 323.25 728.03125 458.01562 728.03125 526.125 668.9375 c 526.125 668.9375 594.23438 609.85938 597.65625 511.23438 c 597.65625 511.23438 453.125 504.89062 453.125 504.89062 c 453.125 504.89062 443.84375 560.0625 413.32813 584.23438 c 413.32813 584.23438 382.8125 608.40625 321.78125 608.40625 c 321.78125 608.40625 258.79688 608.40625 223.14062 582.51562 c 223.14062 582.51562 200.20312 565.92188 200.20312 538.09375 c 200.20312 538.09375 200.20312 512.70312 221.6875 494.625 c 221.6875 494.625 249.03125 471.6875 354.5 446.78125 c 354.5 446.78125 459.96875 421.875 510.5 395.26562 c 510.5 395.26562 561.03125 368.65625 589.59375 322.51562 c 589.59375 322.51562 618.17188 276.375 618.17188 208.5 c 618.17188 208.5 618.17188 146.96875 583.98438 93.25 c 583.98438 93.25 549.8125 39.54687 487.3125 13.42188 c 487.3125 13.42188 424.8125 -12.70312 331.54688 -12.70312 c 331.54688 -12.70312 195.79688 -12.70312 123.04688 50.04688 c 123.04688 50.04688 50.29688 112.79688 36.14062 232.90625 c h f* Q } def /T { 590 0 21 0 590 716 setcachedevice q 233.89062 0 m 233.89062 0 233.89062 594.73438 233.89062 594.73438 c 233.89062 594.73438 21.48438 594.73438 21.48438 594.73438 c 21.48438 594.73438 21.48438 715.82812 21.48438 715.82812 c 21.48438 715.82812 590.32812 715.82812 590.32812 715.82812 c 590.32812 715.82812 590.32812 594.73438 590.32812 594.73438 c 590.32812 594.73438 378.42188 594.73438 378.42188 594.73438 c 378.42188 594.73438 378.42188 0 378.42188 0 c 378.42188 0 233.89062 0 233.89062 0 c h f* Q } def /U { 643 0 72 -12 643 716 setcachedevice q 71.78125 715.82812 m 71.78125 715.82812 216.3125 715.82812 216.3125 715.82812 c 216.3125 715.82812 216.3125 328.125 216.3125 328.125 c 216.3125 328.125 216.3125 235.84375 221.6875 208.5 c 221.6875 208.5 230.95312 164.54687 265.85938 137.9375 c 265.85938 137.9375 300.78125 111.32812 361.32812 111.32812 c 361.32812 111.32812 422.85938 111.32812 454.10938 136.46875 c 454.10938 136.46875 485.35938 161.625 491.70312 198.23438 c 491.70312 198.23438 498.04688 234.85938 498.04688 319.82812 c 498.04688 319.82812 498.04688 715.82812 498.04688 715.82812 c 498.04688 715.82812 642.57812 715.82812 642.57812 715.82812 c 642.57812 715.82812 642.57812 339.84375 642.57812 339.84375 c 642.57812 339.84375 642.57812 210.9375 630.85938 157.71875 c 630.85938 157.71875 619.14062 104.5 587.64062 67.875 c 587.64062 67.875 556.15625 31.25 503.42188 9.51562 c 503.42188 9.51562 450.6875 -12.20312 365.71875 -12.20312 c 365.71875 -12.20312 263.1875 -12.20312 210.20312 11.46875 c 210.20312 11.46875 157.23438 35.15625 126.46875 73 c 126.46875 73 95.70312 110.84375 85.9375 152.34375 c 85.9375 152.34375 71.78125 213.875 71.78125 333.98438 c 71.78125 333.98438 71.78125 715.82812 71.78125 715.82812 c h f* Q } def /a { 522 0 36 -12 522 530 setcachedevice q 174.3125 360.35938 m 174.3125 360.35938 49.8125 382.8125 49.8125 382.8125 c 49.8125 382.8125 70.79688 458.01562 122.0625 494.14062 c 122.0625 494.14062 173.34375 530.28125 274.42188 530.28125 c 274.42188 530.28125 366.21875 530.28125 411.14062 508.54688 c 411.14062 508.54688 456.0625 486.8125 474.35938 453.35938 c 474.35938 453.35938 492.67188 419.92188 492.67188 330.5625 c 492.67188 330.5625 491.21875 170.40625 491.21875 170.40625 c 491.21875 170.40625 491.21875 102.04687 497.79688 69.57812 c 497.79688 69.57812 504.39062 37.10938 522.46875 0 c 522.46875 0 386.71875 0 386.71875 0 c 386.71875 0 381.34375 13.67188 373.53125 40.53125 c 373.53125 40.53125 370.125 52.73438 368.65625 56.64062 c 368.65625 56.64062 333.5 22.46875 293.45312 5.375 c 293.45312 5.375 253.42188 -11.71875 208.01562 -11.71875 c 208.01562 -11.71875 127.9375 -11.71875 81.78125 31.73437 c 81.78125 31.73437 35.64062 75.20312 35.64062 141.60938 c 35.64062 141.60938 35.64062 185.54688 56.64062 219.96875 c 56.64062 219.96875 77.64062 254.39062 115.48438 272.70312 c 115.48438 272.70312 153.32812 291.01562 224.60938 304.6875 c 224.60938 304.6875 320.79688 322.75 357.90625 338.375 c 357.90625 338.375 357.90625 352.04688 357.90625 352.04688 c 357.90625 352.04688 357.90625 391.60938 338.375 408.45312 c 338.375 408.45312 318.84375 425.29688 264.65625 425.29688 c 264.65625 425.29688 228.03125 425.29688 207.51562 410.89062 c 207.51562 410.89062 187.01562 396.48438 174.3125 360.35938 c 174.3125 360.35938 174.3125 360.35938 174.3125 360.35938 c h 357.90625 249.03125 m 357.90625 249.03125 331.54688 240.23438 274.40625 228.03125 c 274.40625 228.03125 217.28125 215.82812 199.70312 204.10938 c 199.70312 204.10938 172.85938 185.0625 172.85938 155.76563 c 172.85938 155.76563 172.85938 126.95312 194.34375 105.95312 c 194.34375 105.95312 215.82812 84.96875 249.03125 84.96875 c 249.03125 84.96875 286.14062 84.96875 319.82812 109.375 c 319.82812 109.375 344.73438 127.9375 352.54688 154.78125 c 352.54688 154.78125 357.90625 172.35937 357.90625 221.6875 c 357.90625 221.6875 357.90625 249.03125 357.90625 249.03125 c h f* Q } def /c { 531 0 42 -12 531 530 setcachedevice q 523.92188 365.23438 m 523.92188 365.23438 388.67188 340.82812 388.67188 340.82812 c 388.67188 340.82812 381.84375 381.34375 357.67188 401.84375 c 357.67188 401.84375 333.5 422.35938 294.92188 422.35938 c 294.92188 422.35938 243.65625 422.35938 213.14062 386.95312 c 213.14062 386.95312 182.625 351.5625 182.625 268.5625 c 182.625 268.5625 182.625 176.26562 213.625 138.17188 c 213.625 138.17188 244.625 100.09375 296.875 100.09375 c 296.875 100.09375 335.9375 100.09375 360.84375 122.3125 c 360.84375 122.3125 385.75 144.53125 396 198.73438 c 396 198.73438 530.76562 175.78125 530.76562 175.78125 c 530.76562 175.78125 509.76562 83.01562 450.1875 35.64062 c 450.1875 35.64062 390.625 -11.71875 290.53125 -11.71875 c 290.53125 -11.71875 176.76562 -11.71875 109.125 60.0625 c 109.125 60.0625 41.5 131.84375 41.5 258.79688 c 41.5 258.79688 41.5 387.20312 109.375 458.73438 c 109.375 458.73438 177.25 530.28125 292.96875 530.28125 c 292.96875 530.28125 387.70312 530.28125 443.60938 489.5 c 443.60938 489.5 499.51562 448.73438 523.92188 365.23438 c h f* Q } def /e { 519 0 32 -12 519 530 setcachedevice q 372.07812 165.04688 m 372.07812 165.04688 508.79688 142.09375 508.79688 142.09375 c 508.79688 142.09375 482.42188 66.89062 425.53125 27.57812 c 425.53125 27.57812 368.65625 -11.71875 283.20312 -11.71875 c 283.20312 -11.71875 147.95312 -11.71875 83.01562 76.65625 c 83.01562 76.65625 31.73437 147.46875 31.73437 255.375 c 31.73437 255.375 31.73437 384.28125 99.10938 457.28125 c 99.10938 457.28125 166.5 530.28125 269.53125 530.28125 c 269.53125 530.28125 385.25 530.28125 452.14062 453.85938 c 452.14062 453.85938 519.04688 377.4375 516.10938 219.73438 c 516.10938 219.73438 172.35938 219.73438 172.35938 219.73438 c 172.35938 219.73438 173.82812 158.6875 205.5625 124.75 c 205.5625 124.75 237.3125 90.82812 284.67188 90.82812 c 284.67188 90.82812 316.89062 90.82812 338.85938 108.40625 c 338.85938 108.40625 360.84375 125.98438 372.07812 165.04688 c 372.07812 165.04688 372.07812 165.04688 372.07812 165.04688 c h 379.89062 303.71875 m 379.89062 303.71875 378.42188 363.28125 349.125 394.28125 c 349.125 394.28125 319.82812 425.29688 277.82812 425.29688 c 277.82812 425.29688 232.90625 425.29688 203.60938 392.57812 c 203.60938 392.57812 174.3125 359.85938 174.8125 303.71875 c 174.8125 303.71875 379.89062 303.71875 379.89062 303.71875 c h f* Q } def /g { 547 0 41 -210 547 530 setcachedevice q 59.07812 -34.1875 m 59.07812 -34.1875 215.82812 -53.21875 215.82812 -53.21875 c 215.82812 -53.21875 219.73438 -80.5625 233.89062 -90.82812 c 233.89062 -90.82812 253.42188 -105.46875 295.40625 -105.46875 c 295.40625 -105.46875 349.125 -105.46875 375.98438 -89.35938 c 375.98438 -89.35938 394.04688 -78.60938 403.32812 -54.6875 c 403.32812 -54.6875 409.67188 -37.59375 409.67188 8.29687 c 409.67188 8.29687 409.67188 83.98438 409.67188 83.98438 c 409.67188 83.98438 348.14062 0 254.39062 0 c 254.39062 0 149.90625 0 88.875 88.375 c 88.875 88.375 41.01562 158.20312 41.01562 262.20312 c 41.01562 262.20312 41.01562 392.57812 103.75 461.42188 c 103.75 461.42188 166.5 530.28125 259.76562 530.28125 c 259.76562 530.28125 355.95312 530.28125 418.45312 445.79688 c 418.45312 445.79688 418.45312 518.5625 418.45312 518.5625 c 418.45312 518.5625 546.875 518.5625 546.875 518.5625 c 546.875 518.5625 546.875 53.21875 546.875 53.21875 c 546.875 53.21875 546.875 -38.57812 531.73438 -83.98438 c 531.73438 -83.98438 516.60938 -129.39062 489.26562 -155.26562 c 489.26562 -155.26562 461.92188 -181.15625 416.26563 -195.79688 c 416.26563 -195.79688 370.60938 -210.45312 300.78125 -210.45312 c 300.78125 -210.45312 168.95312 -210.45312 113.76562 -165.28125 c 113.76562 -165.28125 58.59375 -120.125 58.59375 -50.78125 c 58.59375 -50.78125 58.59375 -43.95312 59.07812 -34.1875 c 59.07812 -34.1875 59.07812 -34.1875 59.07812 -34.1875 c h 181.64062 270.01562 m 181.64062 270.01562 181.64062 187.5 213.625 149.17188 c 213.625 149.17188 245.60938 110.84375 292.48438 110.84375 c 292.48438 110.84375 342.78125 110.84375 377.4375 150.14062 c 377.4375 150.14062 412.10938 189.45312 412.10938 266.60938 c 412.10938 266.60938 412.10938 347.17188 378.90625 386.23438 c 378.90625 386.23438 345.70312 425.29688 294.92188 425.29688 c 294.92188 425.29688 245.60938 425.29688 213.625 386.96875 c 213.625 386.96875 181.64062 348.64062 181.64062 270.01562 c h f* Q } def /i { 209 0 72 0 209 716 setcachedevice q 71.78125 588.875 m 71.78125 588.875 71.78125 715.82812 71.78125 715.82812 c 71.78125 715.82812 208.98438 715.82812 208.98438 715.82812 c 208.98438 715.82812 208.98438 588.875 208.98438 588.875 c 208.98438 588.875 71.78125 588.875 71.78125 588.875 c 71.78125 588.875 71.78125 588.875 71.78125 588.875 c h 71.78125 0 m 71.78125 0 71.78125 518.5625 71.78125 518.5625 c 71.78125 518.5625 208.98438 518.5625 208.98438 518.5625 c 208.98438 518.5625 208.98438 0 208.98438 0 c 208.98438 0 71.78125 0 71.78125 0 c h f* Q } def /l { 209 0 72 0 209 716 setcachedevice q 71.78125 0 m 71.78125 0 71.78125 715.82812 71.78125 715.82812 c 71.78125 715.82812 208.98438 715.82812 208.98438 715.82812 c 208.98438 715.82812 208.98438 0 208.98438 0 c 208.98438 0 71.78125 0 71.78125 0 c h f* Q } def /m { 824 0 62 0 824 530 setcachedevice q 61.53125 518.5625 m 61.53125 518.5625 187.98438 518.5625 187.98438 518.5625 c 187.98438 518.5625 187.98438 447.75 187.98438 447.75 c 187.98438 447.75 255.85938 530.28125 349.60938 530.28125 c 349.60938 530.28125 399.42188 530.28125 436.03125 509.76562 c 436.03125 509.76562 472.65625 489.26562 496.09375 447.75 c 496.09375 447.75 530.28125 489.26562 569.82812 509.76562 c 569.82812 509.76562 609.375 530.28125 654.29688 530.28125 c 654.29688 530.28125 711.42188 530.28125 750.96875 507.07813 c 750.96875 507.07813 790.53125 483.89062 810.0625 438.96875 c 810.0625 438.96875 824.21875 405.76562 824.21875 331.54688 c 824.21875 331.54688 824.21875 0 824.21875 0 c 824.21875 0 687.01562 0 687.01562 0 c 687.01562 0 687.01562 296.39062 687.01562 296.39062 c 687.01562 296.39062 687.01562 373.53125 672.85938 396 c 672.85938 396 653.8125 425.29688 614.26562 425.29688 c 614.26562 425.29688 585.45312 425.29688 560.0625 407.71875 c 560.0625 407.71875 534.67188 390.14062 523.4375 356.20312 c 523.4375 356.20312 512.20312 322.26562 512.20312 249.03125 c 512.20312 249.03125 512.20312 0 512.20312 0 c 512.20312 0 375 0 375 0 c 375 0 375 284.1875 375 284.1875 c 375 284.1875 375 359.85938 367.67188 381.82812 c 367.67188 381.82812 360.35938 403.8125 344.96875 414.54688 c 344.96875 414.54688 329.59375 425.29688 303.21875 425.29688 c 303.21875 425.29688 271.48438 425.29688 246.09375 408.20312 c 246.09375 408.20312 220.70312 391.10938 209.71875 358.875 c 209.71875 358.875 198.73438 326.65625 198.73438 251.95312 c 198.73438 251.95312 198.73438 0 198.73438 0 c 198.73438 0 61.53125 0 61.53125 0 c 61.53125 0 61.53125 518.5625 61.53125 518.5625 c h f* Q } def /n { 543 0 71 0 543 530 setcachedevice q 543.45312 0 m 543.45312 0 406.25 0 406.25 0 c 406.25 0 406.25 264.65625 406.25 264.65625 c 406.25 264.65625 406.25 348.64062 397.45312 373.29688 c 397.45312 373.29688 388.67188 397.95312 368.89062 411.625 c 368.89062 411.625 349.125 425.29688 321.29688 425.29688 c 321.29688 425.29688 285.64062 425.29688 257.3125 405.76562 c 257.3125 405.76562 229 386.23438 218.5 354 c 218.5 354 208.01562 321.78125 208.01562 234.85938 c 208.01562 234.85938 208.01562 0 208.01562 0 c 208.01562 0 70.79688 0 70.79688 0 c 70.79688 0 70.79688 518.5625 70.79688 518.5625 c 70.79688 518.5625 198.25 518.5625 198.25 518.5625 c 198.25 518.5625 198.25 442.39062 198.25 442.39062 c 198.25 442.39062 266.10938 530.28125 369.14062 530.28125 c 369.14062 530.28125 414.54688 530.28125 452.14062 513.92188 c 452.14062 513.92188 489.75 497.5625 509.03125 472.17188 c 509.03125 472.17188 528.32812 446.78125 535.89062 414.54688 c 535.89062 414.54688 543.45312 382.32812 543.45312 322.26562 c 543.45312 322.26562 543.45312 0 543.45312 0 c h f* Q } def /o { 575 0 40 -12 575 530 setcachedevice q 40.04688 266.60938 m 40.04688 266.60938 40.04688 334.96875 73.73438 398.92188 c 73.73438 398.92188 107.42188 462.89062 169.1875 496.57812 c 169.1875 496.57812 230.95312 530.28125 307.125 530.28125 c 307.125 530.28125 424.8125 530.28125 500 453.85938 c 500 453.85938 575.20312 377.4375 575.20312 260.75 c 575.20312 260.75 575.20312 143.0625 499.26563 65.67188 c 499.26563 65.67188 423.34375 -11.71875 308.10938 -11.71875 c 308.10938 -11.71875 236.8125 -11.71875 172.10938 20.5 c 172.10938 20.5 107.42188 52.73438 73.73438 114.98438 c 73.73438 114.98438 40.04688 177.25 40.04688 266.60938 c 40.04688 266.60938 40.04688 266.60938 40.04688 266.60938 c h 180.67188 259.28125 m 180.67188 259.28125 180.67188 182.125 217.28125 141.10937 c 217.28125 141.10937 253.90625 100.09375 307.625 100.09375 c 307.625 100.09375 361.32812 100.09375 397.70312 141.10937 c 397.70312 141.10937 434.07812 182.125 434.07812 260.25 c 434.07812 260.25 434.07812 336.42188 397.70312 377.4375 c 397.70312 377.4375 361.32812 418.45312 307.625 418.45312 c 307.625 418.45312 253.90625 418.45312 217.28125 377.4375 c 217.28125 377.4375 180.67188 336.42188 180.67188 259.28125 c h f* Q } def /r { 402 0 66 0 402 530 setcachedevice q 203.125 0 m 203.125 0 65.92188 0 65.92188 0 c 65.92188 0 65.92188 518.5625 65.92188 518.5625 c 65.92188 518.5625 193.35938 518.5625 193.35938 518.5625 c 193.35938 518.5625 193.35938 444.82812 193.35938 444.82812 c 193.35938 444.82812 226.07812 497.07812 252.20312 513.67188 c 252.20312 513.67188 278.32812 530.28125 311.53125 530.28125 c 311.53125 530.28125 358.40625 530.28125 401.85938 504.39062 c 401.85938 504.39062 359.375 384.76562 359.375 384.76562 c 359.375 384.76562 324.70312 407.23438 294.92188 407.23438 c 294.92188 407.23438 266.10938 407.23438 246.09375 391.35938 c 246.09375 391.35938 226.07812 375.48438 214.59375 333.98438 c 214.59375 333.98438 203.125 292.48438 203.125 160.15625 c 203.125 160.15625 203.125 0 203.125 0 c h f* Q } def /s { 508 0 23 -12 508 530 setcachedevice q 23.4375 147.95313 m 23.4375 147.95313 161.14062 168.95312 161.14062 168.95312 c 161.14062 168.95312 169.92188 128.90625 196.78125 108.15625 c 196.78125 108.15625 223.64062 87.40625 271.96875 87.40625 c 271.96875 87.40625 325.20312 87.40625 352.04688 106.9375 c 352.04688 106.9375 370.125 120.60938 370.125 143.5625 c 370.125 143.5625 370.125 159.1875 360.35938 169.4375 c 360.35938 169.4375 350.09375 179.20313 314.45312 187.5 c 314.45312 187.5 148.4375 224.125 104 254.39062 c 104 254.39062 42.48438 296.39062 42.48438 371.09375 c 42.48438 371.09375 42.48438 438.48438 95.70312 484.375 c 95.70312 484.375 148.92188 530.28125 260.75 530.28125 c 260.75 530.28125 367.1875 530.28125 418.9375 495.60938 c 418.9375 495.60938 470.70312 460.9375 490.23438 393.0625 c 490.23438 393.0625 360.84375 369.14062 360.84375 369.14062 c 360.84375 369.14062 352.54688 399.42188 329.34375 415.53125 c 329.34375 415.53125 306.15625 431.64062 263.1875 431.64062 c 263.1875 431.64062 208.98438 431.64062 185.54688 416.5 c 185.54688 416.5 169.92188 405.76562 169.92188 388.67188 c 169.92188 388.67188 169.92188 374.03125 183.59375 363.76562 c 183.59375 363.76562 202.15625 350.09375 311.76562 325.1875 c 311.76562 325.1875 421.39062 300.29688 464.84375 264.15625 c 464.84375 264.15625 507.8125 227.54688 507.8125 162.10938 c 507.8125 162.10938 507.8125 90.82812 448.23438 39.54687 c 448.23438 39.54687 388.67188 -11.71875 271.96875 -11.71875 c 271.96875 -11.71875 166.01562 -11.71875 104.25 31.25 c 104.25 31.25 42.48438 74.21875 23.4375 147.95313 c h f* Q } def /t { 321 0 15 -12 321 702 setcachedevice q 309.57812 518.5625 m 309.57812 518.5625 309.57812 409.1875 309.57812 409.1875 c 309.57812 409.1875 215.82812 409.1875 215.82812 409.1875 c 215.82812 409.1875 215.82812 200.20312 215.82812 200.20312 c 215.82812 200.20312 215.82812 136.71875 218.5 126.21875 c 218.5 126.21875 221.1875 115.71875 230.70312 108.875 c 230.70312 108.875 240.23438 102.04687 253.90625 102.04687 c 253.90625 102.04687 272.95312 102.04687 309.07812 115.23438 c 309.07812 115.23438 320.79688 8.79688 320.79688 8.79688 c 320.79688 8.79688 272.95312 -11.71875 212.40625 -11.71875 c 212.40625 -11.71875 175.29688 -11.71875 145.5 0.73438 c 145.5 0.73438 115.71875 13.1875 101.79688 32.95312 c 101.79688 32.95312 87.89062 52.73438 82.51562 86.42187 c 82.51562 86.42187 78.125 110.35938 78.125 183.10938 c 78.125 183.10938 78.125 409.1875 78.125 409.1875 c 78.125 409.1875 15.14062 409.1875 15.14062 409.1875 c 15.14062 409.1875 15.14062 518.5625 15.14062 518.5625 c 15.14062 518.5625 78.125 518.5625 78.125 518.5625 c 78.125 518.5625 78.125 621.57812 78.125 621.57812 c 78.125 621.57812 215.82812 701.65625 215.82812 701.65625 c 215.82812 701.65625 215.82812 518.5625 215.82812 518.5625 c 215.82812 518.5625 309.57812 518.5625 309.57812 518.5625 c h f* Q } def /u { 541 0 69 -12 541 519 setcachedevice q 413.09375 0 m 413.09375 0 413.09375 77.64063 413.09375 77.64063 c 413.09375 77.64063 384.76562 36.14062 338.625 12.20312 c 338.625 12.20312 292.48438 -11.71875 241.21875 -11.71875 c 241.21875 -11.71875 188.96875 -11.71875 147.45312 11.23438 c 147.45312 11.23438 105.95312 34.1875 87.39062 75.6875 c 87.39062 75.6875 68.84375 117.1875 68.84375 190.4375 c 68.84375 190.4375 68.84375 518.5625 68.84375 518.5625 c 68.84375 518.5625 206.0625 518.5625 206.0625 518.5625 c 206.0625 518.5625 206.0625 280.28125 206.0625 280.28125 c 206.0625 280.28125 206.0625 170.90625 213.625 146.23438 c 213.625 146.23438 221.1875 121.57812 241.20312 107.17188 c 241.20312 107.17188 261.23438 92.78125 292 92.78125 c 292 92.78125 327.15625 92.78125 354.98438 112.0625 c 354.98438 112.0625 382.8125 131.34375 393.0625 159.90625 c 393.0625 159.90625 403.32812 188.48438 403.32812 299.8125 c 403.32812 299.8125 403.32812 518.5625 403.32812 518.5625 c 403.32812 518.5625 540.53125 518.5625 540.53125 518.5625 c 540.53125 518.5625 540.53125 0 540.53125 0 c 540.53125 0 413.09375 0 413.09375 0 c h f* Q } def end currentdict end /T3_31_0 exch definefont pop %%EndResource /F31_0 /T3_31_0 1 1 [ /D/L/P/S/T/U/a/c /e/g/i/l/m/n/o/r /s/t/u/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright /parenleft/parenright/asterisk/plus/comma/hyphen/period/slash /zero/one/two/three/four/five/six/seven /eight/nine/colon/semicolon/less/equal/greater/question /at/A/B/C/D/E/F/G /H/I/J/K/L/M/N/O /P/Q/R/S/T/U/V/W /X/Y/Z/bracketleft/backslash/bracketright/asciicircum/underscore /quoteleft/a/b/c/d/e/f/g /h/i/j/k/l/m/n/o /p/q/r/s/t/u/v/w /x/y/z/braceleft/bar/braceright/asciitilde/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/exclamdown/cent/sterling/fraction/yen/florin/section /currency/quotesingle/quotedblleft/guillemotleft/guilsinglleft/guilsinglright/fi/fl /.notdef/endash/dagger/daggerdbl/periodcentered/.notdef/paragraph/bullet /quotesinglbase/quotedblbase/quotedblright/guillemotright/ellipsis/perthousand/.notdef/questiondown /.notdef/grave/acute/circumflex/tilde/macron/breve/dotaccent /dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut/ogonek/caron /emdash/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/AE/.notdef/ordfeminine/.notdef/.notdef/.notdef/.notdef /Lslash/Oslash/OE/ordmasculine/.notdef/.notdef/.notdef/.notdef /.notdef/ae/.notdef/.notdef/.notdef/dotlessi/.notdef/.notdef /lslash/oslash/oe/germandbls/.notdef/.notdef/.notdef/.notdef] pdfMakeFont %%BeginResource: font T3_72_0 8 dict begin /FontType 3 def /FontMatrix [0.001 0 0 0.001 0 0] def /FontBBox [-46 -210 769 729] def /Encoding 256 array def 0 1 255 { Encoding exch /.notdef put } for /BuildGlyph { exch /CharProcs get exch 2 copy known not { pop /.notdef } if get exec } bind def /BuildChar { 1 index /Encoding get exch get 1 index /BuildGlyph get exec } bind def /CharProcs 37 dict def CharProcs begin /comma { 189 0 83 -142 189 100 setcachedevice q 88.875 0 m 88.875 0 88.875 100.09375 88.875 100.09375 c 88.875 100.09375 188.96875 100.09375 188.96875 100.09375 c 188.96875 100.09375 188.96875 0 188.96875 0 c 188.96875 0 188.96875 -55.17188 169.4375 -89.10938 c 169.4375 -89.10938 149.90625 -123.04688 107.42188 -141.60938 c 107.42188 -141.60938 83.01562 -104 83.01562 -104 c 83.01562 -104 110.84375 -91.79688 124.01562 -68.10938 c 124.01562 -68.10938 137.20312 -44.4375 138.67188 0 c 138.67188 0 88.875 0 88.875 0 c h f* Q } def /period { 191 0 91 0 191 100 setcachedevice q 90.82812 0 m 90.82812 0 90.82812 100.09375 90.82812 100.09375 c 90.82812 100.09375 190.92188 100.09375 190.92188 100.09375 c 190.92188 100.09375 190.92188 0 190.92188 0 c 190.92188 0 90.82812 0 90.82812 0 c h f* Q } def /semicolon { 189 0 83 -142 189 519 setcachedevice q 88.875 418.45312 m 88.875 418.45312 88.875 518.5625 88.875 518.5625 c 88.875 518.5625 188.96875 518.5625 188.96875 518.5625 c 188.96875 518.5625 188.96875 418.45312 188.96875 418.45312 c 188.96875 418.45312 88.875 418.45312 88.875 418.45312 c 88.875 418.45312 88.875 418.45312 88.875 418.45312 c h 88.875 0 m 88.875 0 88.875 100.09375 88.875 100.09375 c 88.875 100.09375 188.96875 100.09375 188.96875 100.09375 c 188.96875 100.09375 188.96875 0 188.96875 0 c 188.96875 0 188.96875 -55.17188 169.4375 -89.10938 c 169.4375 -89.10938 149.90625 -123.04688 107.42188 -141.60938 c 107.42188 -141.60938 83.01562 -104 83.01562 -104 c 83.01562 -104 110.84375 -91.79688 124.01562 -68.10938 c 124.01562 -68.10938 137.20312 -44.4375 138.67188 0 c 138.67188 0 88.875 0 88.875 0 c h f* Q } def /A { 668 0 -1 0 668 716 setcachedevice q -1.46875 0 m -1.46875 0 273.4375 715.82812 273.4375 715.82812 c 273.4375 715.82812 375.48438 715.82812 375.48438 715.82812 c 375.48438 715.82812 668.45312 0 668.45312 0 c 668.45312 0 560.54688 0 560.54688 0 c 560.54688 0 477.04688 216.79688 477.04688 216.79688 c 477.04688 216.79688 177.73438 216.79688 177.73438 216.79688 c 177.73438 216.79688 99.125 0 99.125 0 c 99.125 0 -1.46875 0 -1.46875 0 c -1.46875 0 -1.46875 0 -1.46875 0 c h 205.07812 293.95312 m 205.07812 293.95312 447.75 293.95312 447.75 293.95312 c 447.75 293.95312 373.04688 492.1875 373.04688 492.1875 c 373.04688 492.1875 338.875 582.51562 322.26562 640.625 c 322.26562 640.625 308.59375 571.78125 283.6875 503.90625 c 283.6875 503.90625 205.07812 293.95312 205.07812 293.95312 c h f* Q } def /C { 683 0 50 -12 683 728 setcachedevice q 587.89062 250.98438 m 587.89062 250.98438 682.625 227.04688 682.625 227.04688 c 682.625 227.04688 652.82812 110.35938 575.4375 49.07812 c 575.4375 49.07812 498.04688 -12.20312 386.23438 -12.20312 c 386.23438 -12.20312 270.51562 -12.20312 198 34.90625 c 198 34.90625 125.48438 82.03125 87.64062 171.39063 c 87.64062 171.39063 49.8125 260.75 49.8125 363.28125 c 49.8125 363.28125 49.8125 475.09375 92.53125 558.34375 c 92.53125 558.34375 135.25 641.60938 214.10938 684.8125 c 214.10938 684.8125 292.96875 728.03125 387.70312 728.03125 c 387.70312 728.03125 495.125 728.03125 568.35938 673.34375 c 568.35938 673.34375 641.60938 618.65625 670.40625 519.53125 c 670.40625 519.53125 577.15625 497.5625 577.15625 497.5625 c 577.15625 497.5625 552.25 575.6875 504.875 611.32812 c 504.875 611.32812 457.51562 646.96875 385.75 646.96875 c 385.75 646.96875 303.21875 646.96875 247.79688 607.42188 c 247.79688 607.42188 192.39063 567.875 169.92188 501.21875 c 169.92188 501.21875 147.46875 434.57812 147.46875 363.76562 c 147.46875 363.76562 147.46875 272.46875 174.07812 204.34375 c 174.07812 204.34375 200.6875 136.23438 256.82812 102.53125 c 256.82812 102.53125 312.98438 68.84375 378.42188 68.84375 c 378.42188 68.84375 458.01562 68.84375 513.1875 114.73438 c 513.1875 114.73438 568.35938 160.64062 587.89062 250.98438 c h f* Q } def /D { 669 0 77 0 669 716 setcachedevice q 77.15625 0 m 77.15625 0 77.15625 715.82812 77.15625 715.82812 c 77.15625 715.82812 323.73438 715.82812 323.73438 715.82812 c 323.73438 715.82812 407.23438 715.82812 451.17188 705.5625 c 451.17188 705.5625 512.70312 691.40625 556.15625 654.29688 c 556.15625 654.29688 612.79688 606.45312 640.875 531.98438 c 640.875 531.98438 668.95312 457.51562 668.95312 361.8125 c 668.95312 361.8125 668.95312 280.28125 649.90625 217.28125 c 649.90625 217.28125 630.85938 154.29688 601.07812 113.03125 c 601.07812 113.03125 571.29688 71.78125 535.89062 48.09375 c 535.89062 48.09375 500.48438 24.42188 450.4375 12.20312 c 450.4375 12.20312 400.39062 0 335.45312 0 c 335.45312 0 77.15625 0 77.15625 0 c 77.15625 0 77.15625 0 77.15625 0 c h 171.875 84.46875 m 171.875 84.46875 324.70312 84.46875 324.70312 84.46875 c 324.70312 84.46875 395.51562 84.46875 435.79688 97.65625 c 435.79688 97.65625 476.07812 110.84375 500 134.76562 c 500 134.76562 533.6875 168.45312 552.48438 225.34375 c 552.48438 225.34375 571.29688 282.23438 571.29688 363.28125 c 571.29688 363.28125 571.29688 475.59375 534.42188 535.89062 c 534.42188 535.89062 497.5625 596.1875 444.82812 616.70312 c 444.82812 616.70312 406.73438 631.34375 322.26562 631.34375 c 322.26562 631.34375 171.875 631.34375 171.875 631.34375 c 171.875 631.34375 171.875 84.46875 171.875 84.46875 c h f* Q } def /E { 613 0 79 0 613 716 setcachedevice q 79.10938 0 m 79.10938 0 79.10938 715.82812 79.10938 715.82812 c 79.10938 715.82812 596.6875 715.82812 596.6875 715.82812 c 596.6875 715.82812 596.6875 631.34375 596.6875 631.34375 c 596.6875 631.34375 173.82812 631.34375 173.82812 631.34375 c 173.82812 631.34375 173.82812 412.10938 173.82812 412.10938 c 173.82812 412.10938 569.82812 412.10938 569.82812 412.10938 c 569.82812 412.10938 569.82812 328.125 569.82812 328.125 c 569.82812 328.125 173.82812 328.125 173.82812 328.125 c 173.82812 328.125 173.82812 84.46875 173.82812 84.46875 c 173.82812 84.46875 613.28125 84.46875 613.28125 84.46875 c 613.28125 84.46875 613.28125 0 613.28125 0 c 613.28125 0 79.10938 0 79.10938 0 c h f* Q } def /F { 565 0 82 0 565 716 setcachedevice q 82.03125 0 m 82.03125 0 82.03125 715.82812 82.03125 715.82812 c 82.03125 715.82812 564.9375 715.82812 564.9375 715.82812 c 564.9375 715.82812 564.9375 631.34375 564.9375 631.34375 c 564.9375 631.34375 176.76562 631.34375 176.76562 631.34375 c 176.76562 631.34375 176.76562 409.67188 176.76562 409.67188 c 176.76562 409.67188 512.70312 409.67188 512.70312 409.67188 c 512.70312 409.67188 512.70312 325.20312 512.70312 325.20312 c 512.70312 325.20312 176.76562 325.20312 176.76562 325.20312 c 176.76562 325.20312 176.76562 0 176.76562 0 c 176.76562 0 82.03125 0 82.03125 0 c h f* Q } def /I { 188 0 93 0 188 716 setcachedevice q 93.26562 0 m 93.26562 0 93.26562 715.82812 93.26562 715.82812 c 93.26562 715.82812 187.98438 715.82812 187.98438 715.82812 c 187.98438 715.82812 187.98438 0 187.98438 0 c 187.98438 0 93.26562 0 93.26562 0 c h f* Q } def /L { 521 0 73 0 521 716 setcachedevice q 73.25 0 m 73.25 0 73.25 715.82812 73.25 715.82812 c 73.25 715.82812 167.96875 715.82812 167.96875 715.82812 c 167.96875 715.82812 167.96875 84.46875 167.96875 84.46875 c 167.96875 84.46875 520.51562 84.46875 520.51562 84.46875 c 520.51562 84.46875 520.51562 0 520.51562 0 c 520.51562 0 73.25 0 73.25 0 c h f* Q } def /M { 757 0 74 0 757 716 setcachedevice q 74.21875 0 m 74.21875 0 74.21875 715.82812 74.21875 715.82812 c 74.21875 715.82812 216.79688 715.82812 216.79688 715.82812 c 216.79688 715.82812 386.23438 208.98438 386.23438 208.98438 c 386.23438 208.98438 409.67188 138.1875 420.40625 103.03125 c 420.40625 103.03125 432.625 142.09375 458.5 217.78125 c 458.5 217.78125 629.89062 715.82812 629.89062 715.82812 c 629.89062 715.82812 757.32812 715.82812 757.32812 715.82812 c 757.32812 715.82812 757.32812 0 757.32812 0 c 757.32812 0 666.01562 0 666.01562 0 c 666.01562 0 666.01562 599.125 666.01562 599.125 c 666.01562 599.125 458.01562 0 458.01562 0 c 458.01562 0 372.5625 0 372.5625 0 c 372.5625 0 165.53125 609.375 165.53125 609.375 c 165.53125 609.375 165.53125 0 165.53125 0 c 165.53125 0 74.21875 0 74.21875 0 c h f* Q } def /N { 640 0 76 0 640 716 setcachedevice q 76.17188 0 m 76.17188 0 76.17188 715.82812 76.17188 715.82812 c 76.17188 715.82812 173.34375 715.82812 173.34375 715.82812 c 173.34375 715.82812 549.3125 153.8125 549.3125 153.8125 c 549.3125 153.8125 549.3125 715.82812 549.3125 715.82812 c 549.3125 715.82812 640.14062 715.82812 640.14062 715.82812 c 640.14062 715.82812 640.14062 0 640.14062 0 c 640.14062 0 542.96875 0 542.96875 0 c 542.96875 0 167 562.5 167 562.5 c 167 562.5 167 0 167 0 c 167 0 76.17188 0 76.17188 0 c h f* Q } def /P { 624 0 77 0 624 716 setcachedevice q 77.15625 0 m 77.15625 0 77.15625 715.82812 77.15625 715.82812 c 77.15625 715.82812 347.17188 715.82812 347.17188 715.82812 c 347.17188 715.82812 418.45312 715.82812 456.0625 708.98438 c 456.0625 708.98438 508.79688 700.20312 544.4375 675.53125 c 544.4375 675.53125 580.07812 650.875 601.79688 606.4375 c 601.79688 606.4375 623.53125 562.01562 623.53125 508.79688 c 623.53125 508.79688 623.53125 417.48438 565.42188 354.25 c 565.42188 354.25 507.32812 291.01562 355.46875 291.01562 c 355.46875 291.01562 171.875 291.01562 171.875 291.01562 c 171.875 291.01562 171.875 0 171.875 0 c 171.875 0 77.15625 0 77.15625 0 c 77.15625 0 77.15625 0 77.15625 0 c h 171.875 375.48438 m 171.875 375.48438 356.9375 375.48438 356.9375 375.48438 c 356.9375 375.48438 448.73438 375.48438 487.29688 409.65625 c 487.29688 409.65625 525.875 443.84375 525.875 505.85938 c 525.875 505.85938 525.875 550.78125 503.17188 582.76562 c 503.17188 582.76562 480.46875 614.75 443.35938 625 c 443.35938 625 419.4375 631.34375 354.98438 631.34375 c 354.98438 631.34375 171.875 631.34375 171.875 631.34375 c 171.875 631.34375 171.875 375.48438 171.875 375.48438 c h f* Q } def /Q { 741 0 43 -56 741 729 setcachedevice q 619.625 76.65625 m 619.625 76.65625 685.54688 31.25 741.21875 10.25 c 741.21875 10.25 713.375 -55.67188 713.375 -55.67188 c 713.375 -55.67188 636.23438 -27.82812 559.57812 32.23438 c 559.57812 32.23438 479.98438 -12.20312 383.79688 -12.20312 c 383.79688 -12.20312 286.625 -12.20312 207.51562 34.67188 c 207.51562 34.67188 128.42188 81.54688 85.6875 166.5 c 85.6875 166.5 42.96875 251.46875 42.96875 357.90625 c 42.96875 357.90625 42.96875 463.875 85.9375 550.78125 c 85.9375 550.78125 128.90625 637.70312 208.25 683.10938 c 208.25 683.10938 287.59375 728.51562 385.75 728.51562 c 385.75 728.51562 484.85938 728.51562 564.45312 681.39062 c 564.45312 681.39062 644.04688 634.28125 685.79688 549.5625 c 685.79688 549.5625 727.54688 464.84375 727.54688 358.40625 c 727.54688 358.40625 727.54688 270.01562 700.6875 199.45312 c 700.6875 199.45312 673.82812 128.90625 619.625 76.65625 c 619.625 76.65625 619.625 76.65625 619.625 76.65625 c h 411.14062 197.75 m 411.14062 197.75 493.17188 174.8125 546.39062 129.39062 c 546.39062 129.39062 629.89062 205.5625 629.89062 358.40625 c 629.89062 358.40625 629.89062 445.3125 600.34375 510.25 c 600.34375 510.25 570.79688 575.20312 513.90625 611.07812 c 513.90625 611.07812 457.03125 646.96875 386.23438 646.96875 c 386.23438 646.96875 280.28125 646.96875 210.45312 574.45312 c 210.45312 574.45312 140.625 501.95312 140.625 357.90625 c 140.625 357.90625 140.625 218.26562 209.71875 143.54688 c 209.71875 143.54688 278.8125 68.84375 386.23438 68.84375 c 386.23438 68.84375 437.01562 68.84375 481.9375 87.89062 c 481.9375 87.89062 437.5 116.70313 388.1875 128.90625 c 388.1875 128.90625 411.14062 197.75 411.14062 197.75 c h f* Q } def /S { 615 0 45 -12 615 728 setcachedevice q 44.92188 229.98438 m 44.92188 229.98438 134.28125 237.79688 134.28125 237.79688 c 134.28125 237.79688 140.625 184.07812 163.8125 149.65625 c 163.8125 149.65625 187.01562 115.23438 235.84375 93.98438 c 235.84375 93.98438 284.67188 72.75 345.70312 72.75 c 345.70312 72.75 399.90625 72.75 441.40625 88.85938 c 441.40625 88.85938 482.90625 104.98438 503.17188 133.0625 c 503.17188 133.0625 523.4375 161.14062 523.4375 194.34375 c 523.4375 194.34375 523.4375 228.03125 503.90625 253.17188 c 503.90625 253.17188 484.375 278.32812 439.45312 295.40625 c 439.45312 295.40625 410.64062 306.64062 312 330.3125 c 312 330.3125 213.375 354 173.82812 375 c 173.82812 375 122.5625 401.85938 97.40625 441.65625 c 97.40625 441.65625 72.26562 481.45312 72.26562 530.76562 c 72.26562 530.76562 72.26562 584.96875 103.03125 632.07812 c 103.03125 632.07812 133.79688 679.20312 192.875 703.60938 c 192.875 703.60938 251.95312 728.03125 324.21875 728.03125 c 324.21875 728.03125 403.8125 728.03125 464.59375 702.39062 c 464.59375 702.39062 525.39062 676.76562 558.10938 626.95312 c 558.10938 626.95312 590.82812 577.15625 593.26562 514.15625 c 593.26562 514.15625 502.4375 507.32812 502.4375 507.32812 c 502.4375 507.32812 495.125 575.20312 452.875 609.85938 c 452.875 609.85938 410.64062 644.53125 328.125 644.53125 c 328.125 644.53125 242.1875 644.53125 202.875 613.03125 c 202.875 613.03125 163.57812 581.54688 163.57812 537.10938 c 163.57812 537.10938 163.57812 498.53125 191.40625 473.64062 c 191.40625 473.64062 218.75 448.73438 334.21875 422.60938 c 334.21875 422.60938 449.70312 396.48438 492.67188 376.95312 c 492.67188 376.95312 555.17188 348.14062 584.95312 303.95312 c 584.95312 303.95312 614.75 259.76562 614.75 202.15625 c 614.75 202.15625 614.75 145.01562 582.03125 94.48438 c 582.03125 94.48438 549.3125 43.95312 488.03125 15.875 c 488.03125 15.875 426.76562 -12.20312 350.09375 -12.20312 c 350.09375 -12.20312 252.9375 -12.20312 187.25 16.10937 c 187.25 16.10937 121.57812 44.4375 84.21875 101.3125 c 84.21875 101.3125 46.875 158.20312 44.92188 229.98438 c h f* Q } def /V { 659 0 4 0 659 716 setcachedevice q 281.73438 0 m 281.73438 0 4.39062 715.82812 4.39062 715.82812 c 4.39062 715.82812 106.9375 715.82812 106.9375 715.82812 c 106.9375 715.82812 292.96875 195.79687 292.96875 195.79687 c 292.96875 195.79687 315.4375 133.29687 330.5625 78.60937 c 330.5625 78.60937 347.17188 137.20312 369.14062 195.79687 c 369.14062 195.79687 562.5 715.82812 562.5 715.82812 c 562.5 715.82812 659.1875 715.82812 659.1875 715.82812 c 659.1875 715.82812 378.90625 0 378.90625 0 c 378.90625 0 281.73438 0 281.73438 0 c h f* Q } def /a { 514 0 36 -12 514 530 setcachedevice q 404.29688 63.96875 m 404.29688 63.96875 355.46875 22.46875 310.29688 5.375 c 310.29688 5.375 265.14062 -11.71875 213.375 -11.71875 c 213.375 -11.71875 127.9375 -11.71875 82.03125 30.03125 c 82.03125 30.03125 36.14062 71.78125 36.14062 136.71875 c 36.14062 136.71875 36.14062 174.8125 53.46875 206.29688 c 53.46875 206.29688 70.79688 237.79688 98.875 256.82812 c 98.875 256.82812 126.95312 275.875 162.10938 285.64062 c 162.10938 285.64062 187.98438 292.48438 240.23438 298.82812 c 240.23438 298.82812 346.6875 311.53125 396.96875 329.10938 c 396.96875 329.10938 397.46875 347.17188 397.46875 352.04688 c 397.46875 352.04688 397.46875 405.76562 372.5625 427.73438 c 372.5625 427.73438 338.875 457.51562 272.46875 457.51562 c 272.46875 457.51562 210.45312 457.51562 180.90625 435.78125 c 180.90625 435.78125 151.375 414.0625 137.20312 358.89062 c 137.20312 358.89062 51.26562 370.60938 51.26562 370.60938 c 51.26562 370.60938 62.98438 425.78125 89.84375 459.71875 c 89.84375 459.71875 116.70312 493.65625 167.48438 511.96875 c 167.48438 511.96875 218.26562 530.28125 285.15625 530.28125 c 285.15625 530.28125 351.5625 530.28125 393.0625 514.65625 c 393.0625 514.65625 434.57812 499.03125 454.10938 475.34375 c 454.10938 475.34375 473.64062 451.65625 481.45312 415.53125 c 481.45312 415.53125 485.84375 393.0625 485.84375 334.46875 c 485.84375 334.46875 485.84375 217.28125 485.84375 217.28125 c 485.84375 217.28125 485.84375 94.73438 491.45313 62.25 c 491.45313 62.25 497.07812 29.78125 513.67188 0 c 513.67188 0 421.875 0 421.875 0 c 421.875 0 408.20312 27.34375 404.29688 63.96875 c 404.29688 63.96875 404.29688 63.96875 404.29688 63.96875 c h 396.96875 260.25 m 396.96875 260.25 349.125 240.71875 253.42188 227.04688 c 253.42188 227.04688 199.21875 219.23438 176.75 209.46875 c 176.75 209.46875 154.29688 199.70312 142.09375 180.90625 c 142.09375 180.90625 129.89062 162.10938 129.89062 139.15625 c 129.89062 139.15625 129.89062 104 156.5 80.5625 c 156.5 80.5625 183.10938 57.125 234.375 57.125 c 234.375 57.125 285.15625 57.125 324.70312 79.34375 c 324.70312 79.34375 364.26562 101.5625 382.8125 140.14063 c 382.8125 140.14063 396.96875 169.92188 396.96875 228.03125 c 396.96875 228.03125 396.96875 260.25 396.96875 260.25 c h f* Q } def /b { 515 0 65 -12 515 716 setcachedevice q 146.96875 0 m 146.96875 0 65.4375 0 65.4375 0 c 65.4375 0 65.4375 715.82812 65.4375 715.82812 c 65.4375 715.82812 153.32812 715.82812 153.32812 715.82812 c 153.32812 715.82812 153.32812 460.45312 153.32812 460.45312 c 153.32812 460.45312 208.98438 530.28125 295.40625 530.28125 c 295.40625 530.28125 343.26562 530.28125 385.98438 510.98438 c 385.98438 510.98438 428.71875 491.70312 456.29688 456.78125 c 456.29688 456.78125 483.89062 421.875 499.51562 372.5625 c 499.51562 372.5625 515.14062 323.25 515.14062 267.09375 c 515.14062 267.09375 515.14062 133.79688 449.21875 61.03125 c 449.21875 61.03125 383.29688 -11.71875 291.01562 -11.71875 c 291.01562 -11.71875 199.21875 -11.71875 146.96875 64.9375 c 146.96875 64.9375 146.96875 0 146.96875 0 c 146.96875 0 146.96875 0 146.96875 0 c h 146 263.1875 m 146 263.1875 146 169.92188 171.39062 128.42188 c 171.39062 128.42188 212.89062 60.54688 283.6875 60.54688 c 283.6875 60.54688 341.3125 60.54688 383.29688 110.59375 c 383.29688 110.59375 425.29688 160.64062 425.29688 259.76562 c 425.29688 259.76562 425.29688 361.32812 385.01562 409.67188 c 385.01562 409.67188 344.73438 458.01562 287.59375 458.01562 c 287.59375 458.01562 229.98438 458.01562 187.98438 407.95312 c 187.98438 407.95312 146 357.90625 146 263.1875 c h f* Q } def /c { 491 0 39 -12 491 530 setcachedevice q 404.29688 189.9375 m 404.29688 189.9375 490.71875 178.71875 490.71875 178.71875 c 490.71875 178.71875 476.5625 89.35938 418.20312 38.8125 c 418.20312 38.8125 359.85938 -11.71875 274.90625 -11.71875 c 274.90625 -11.71875 168.45312 -11.71875 103.75 57.85938 c 103.75 57.85938 39.0625 127.4375 39.0625 257.32812 c 39.0625 257.32812 39.0625 341.3125 66.89062 404.29688 c 66.89062 404.29688 94.73438 467.28125 151.60938 498.78125 c 151.60938 498.78125 208.5 530.28125 275.39062 530.28125 c 275.39062 530.28125 359.85938 530.28125 413.5625 487.54688 c 413.5625 487.54688 467.28125 444.82812 482.42188 366.21875 c 482.42188 366.21875 396.96875 353.03125 396.96875 353.03125 c 396.96875 353.03125 384.76562 405.28125 353.75 431.64062 c 353.75 431.64062 322.75 458.01562 278.8125 458.01562 c 278.8125 458.01562 212.40625 458.01562 170.89062 410.40625 c 170.89062 410.40625 129.39062 362.79688 129.39062 259.76562 c 129.39062 259.76562 129.39062 155.28125 169.42188 107.90625 c 169.42188 107.90625 209.46875 60.54688 273.92188 60.54688 c 273.92188 60.54688 325.6875 60.54688 360.34375 92.28125 c 360.34375 92.28125 395.01562 124.03125 404.29688 189.9375 c h f* Q } def /d { 484 0 34 -12 484 716 setcachedevice q 402.34375 0 m 402.34375 0 402.34375 65.4375 402.34375 65.4375 c 402.34375 65.4375 353.03125 -11.71875 257.32812 -11.71875 c 257.32812 -11.71875 195.3125 -11.71875 143.3125 22.45312 c 143.3125 22.45312 91.3125 56.64062 62.75 117.92188 c 62.75 117.92188 34.1875 179.20313 34.1875 258.79688 c 34.1875 258.79688 34.1875 336.42188 60.0625 399.65625 c 60.0625 399.65625 85.9375 462.89062 137.6875 496.57812 c 137.6875 496.57812 189.45312 530.28125 253.42188 530.28125 c 253.42188 530.28125 300.29688 530.28125 336.90625 510.5 c 336.90625 510.5 373.53125 490.71875 396.48438 458.98438 c 396.48438 458.98438 396.48438 715.82812 396.48438 715.82812 c 396.48438 715.82812 483.89062 715.82812 483.89062 715.82812 c 483.89062 715.82812 483.89062 0 483.89062 0 c 483.89062 0 402.34375 0 402.34375 0 c 402.34375 0 402.34375 0 402.34375 0 c h 124.51562 258.79688 m 124.51562 258.79688 124.51562 159.1875 166.5 109.85937 c 166.5 109.85937 208.5 60.54688 265.625 60.54688 c 265.625 60.54688 323.25 60.54688 363.53125 107.65625 c 363.53125 107.65625 403.8125 154.78125 403.8125 251.46875 c 403.8125 251.46875 403.8125 357.90625 362.79688 407.70312 c 362.79688 407.70312 321.78125 457.51562 261.71875 457.51562 c 261.71875 457.51562 203.125 457.51562 163.8125 409.65625 c 163.8125 409.65625 124.51562 361.8125 124.51562 258.79688 c h f* Q } def /e { 515 0 37 -12 515 530 setcachedevice q 420.90625 167 m 420.90625 167 511.71875 155.76563 511.71875 155.76563 c 511.71875 155.76563 490.23438 76.17188 432.125 32.21875 c 432.125 32.21875 374.03125 -11.71875 283.6875 -11.71875 c 283.6875 -11.71875 169.92188 -11.71875 103.26562 58.34375 c 103.26562 58.34375 36.625 128.42188 36.625 254.89062 c 36.625 254.89062 36.625 385.75 104 458.01562 c 104 458.01562 171.39062 530.28125 278.8125 530.28125 c 278.8125 530.28125 382.8125 530.28125 448.73438 459.46875 c 448.73438 459.46875 514.65625 388.67188 514.65625 260.25 c 514.65625 260.25 514.65625 252.4375 514.15625 236.8125 c 514.15625 236.8125 127.4375 236.8125 127.4375 236.8125 c 127.4375 236.8125 132.32812 151.375 175.78125 105.95312 c 175.78125 105.95312 219.23438 60.54688 284.1875 60.54688 c 284.1875 60.54688 332.51562 60.54688 366.6875 85.9375 c 366.6875 85.9375 400.875 111.32812 420.90625 167 c 420.90625 167 420.90625 167 420.90625 167 c h 132.32812 309.07812 m 132.32812 309.07812 421.875 309.07812 421.875 309.07812 c 421.875 309.07812 416.01562 374.51562 388.67188 407.23438 c 388.67188 407.23438 346.6875 458.01562 279.78125 458.01562 c 279.78125 458.01562 219.23438 458.01562 177.96875 417.48438 c 177.96875 417.48438 136.71875 376.95312 132.32812 309.07812 c h f* Q } def /f { 313 0 9 0 313 728 setcachedevice q 86.92188 0 m 86.92188 0 86.92188 450.20312 86.92188 450.20312 c 86.92188 450.20312 9.28125 450.20312 9.28125 450.20312 c 9.28125 450.20312 9.28125 518.5625 9.28125 518.5625 c 9.28125 518.5625 86.92188 518.5625 86.92188 518.5625 c 86.92188 518.5625 86.92188 573.73438 86.92188 573.73438 c 86.92188 573.73438 86.92188 625.98438 96.1875 651.375 c 96.1875 651.375 108.89062 685.54688 140.875 706.78125 c 140.875 706.78125 172.85938 728.03125 230.46875 728.03125 c 230.46875 728.03125 267.57812 728.03125 312.5 719.23438 c 312.5 719.23438 299.3125 642.57812 299.3125 642.57812 c 299.3125 642.57812 271.96875 647.46875 247.5625 647.46875 c 247.5625 647.46875 207.51562 647.46875 190.90625 630.375 c 190.90625 630.375 174.3125 613.28125 174.3125 566.40625 c 174.3125 566.40625 174.3125 518.5625 174.3125 518.5625 c 174.3125 518.5625 275.39062 518.5625 275.39062 518.5625 c 275.39062 518.5625 275.39062 450.20312 275.39062 450.20312 c 275.39062 450.20312 174.3125 450.20312 174.3125 450.20312 c 174.3125 450.20312 174.3125 0 174.3125 0 c 174.3125 0 86.92188 0 86.92188 0 c h f* Q } def /g { 489 0 32 -210 489 530 setcachedevice q 49.8125 -42.96875 m 49.8125 -42.96875 135.25 -55.67188 135.25 -55.67188 c 135.25 -55.67188 140.625 -95.21875 165.04688 -113.28125 c 165.04688 -113.28125 197.75 -137.70312 254.39062 -137.70312 c 254.39062 -137.70312 315.4375 -137.70312 348.64062 -113.28125 c 348.64062 -113.28125 381.84375 -88.875 393.5625 -44.92188 c 393.5625 -44.92188 400.39062 -18.0625 399.90625 67.875 c 399.90625 67.875 342.28125 0 256.34375 0 c 256.34375 0 149.42188 0 90.82812 77.14062 c 90.82812 77.14062 32.23438 154.29688 32.23438 262.20312 c 32.23438 262.20312 32.23438 336.42188 59.07812 399.17188 c 59.07812 399.17188 85.9375 461.92188 136.95312 496.09375 c 136.95312 496.09375 187.98438 530.28125 256.84375 530.28125 c 256.84375 530.28125 348.64062 530.28125 408.20312 456.0625 c 408.20312 456.0625 408.20312 518.5625 408.20312 518.5625 c 408.20312 518.5625 489.26562 518.5625 489.26562 518.5625 c 489.26562 518.5625 489.26562 70.3125 489.26562 70.3125 c 489.26562 70.3125 489.26562 -50.78125 464.59375 -101.3125 c 464.59375 -101.3125 439.9375 -151.85938 386.46875 -181.15625 c 386.46875 -181.15625 333.01562 -210.45312 254.89062 -210.45312 c 254.89062 -210.45312 162.10938 -210.45312 104.98438 -168.70312 c 104.98438 -168.70312 47.85938 -126.95312 49.8125 -42.96875 c 49.8125 -42.96875 49.8125 -42.96875 49.8125 -42.96875 c h 122.5625 268.5625 m 122.5625 268.5625 122.5625 166.5 163.07812 119.625 c 163.07812 119.625 203.60938 72.75 264.65625 72.75 c 264.65625 72.75 325.20312 72.75 366.21875 119.375 c 366.21875 119.375 407.23438 166.01562 407.23438 265.625 c 407.23438 265.625 407.23438 360.84375 364.98438 409.17188 c 364.98438 409.17188 322.75 457.51562 263.1875 457.51562 c 263.1875 457.51562 204.59375 457.51562 163.57812 409.90625 c 163.57812 409.90625 122.5625 362.3125 122.5625 268.5625 c h f* Q } def /h { 488 0 66 0 488 716 setcachedevice q 65.92188 0 m 65.92188 0 65.92188 715.82812 65.92188 715.82812 c 65.92188 715.82812 153.8125 715.82812 153.8125 715.82812 c 153.8125 715.82812 153.8125 458.98438 153.8125 458.98438 c 153.8125 458.98438 215.32812 530.28125 309.07812 530.28125 c 309.07812 530.28125 366.70312 530.28125 409.17188 507.5625 c 409.17188 507.5625 451.65625 484.85938 469.96875 444.8125 c 469.96875 444.8125 488.28125 404.78125 488.28125 328.60938 c 488.28125 328.60938 488.28125 0 488.28125 0 c 488.28125 0 400.39062 0 400.39062 0 c 400.39062 0 400.39062 328.60938 400.39062 328.60938 c 400.39062 328.60938 400.39062 394.53125 371.82812 424.5625 c 371.82812 424.5625 343.26562 454.59375 291.01562 454.59375 c 291.01562 454.59375 251.95312 454.59375 217.53125 434.32812 c 217.53125 434.32812 183.10938 414.0625 168.45312 379.39062 c 168.45312 379.39062 153.8125 344.73438 153.8125 283.6875 c 153.8125 283.6875 153.8125 0 153.8125 0 c 153.8125 0 65.92188 0 65.92188 0 c h f* Q } def /i { 154 0 66 0 154 716 setcachedevice q 66.40625 614.75 m 66.40625 614.75 66.40625 715.82812 66.40625 715.82812 c 66.40625 715.82812 154.29688 715.82812 154.29688 715.82812 c 154.29688 715.82812 154.29688 614.75 154.29688 614.75 c 154.29688 614.75 66.40625 614.75 66.40625 614.75 c 66.40625 614.75 66.40625 614.75 66.40625 614.75 c h 66.40625 0 m 66.40625 0 66.40625 518.5625 66.40625 518.5625 c 66.40625 518.5625 154.29688 518.5625 154.29688 518.5625 c 154.29688 518.5625 154.29688 0 154.29688 0 c 154.29688 0 66.40625 0 66.40625 0 c h f* Q } def /j { 153 0 -46 -210 153 716 setcachedevice q 65.4375 613.76562 m 65.4375 613.76562 65.4375 715.82812 65.4375 715.82812 c 65.4375 715.82812 153.32812 715.82812 153.32812 715.82812 c 153.32812 715.82812 153.32812 613.76562 153.32812 613.76562 c 153.32812 613.76562 65.4375 613.76562 65.4375 613.76562 c 65.4375 613.76562 65.4375 613.76562 65.4375 613.76562 c h -45.90625 -201.17188 m -45.90625 -201.17188 -29.29688 -126.46875 -29.29688 -126.46875 c -29.29688 -126.46875 -2.9375 -133.29688 12.20312 -133.29688 c 12.20312 -133.29688 39.0625 -133.29688 52.25 -115.46875 c 52.25 -115.46875 65.4375 -97.65625 65.4375 -26.375 c 65.4375 -26.375 65.4375 518.5625 65.4375 518.5625 c 65.4375 518.5625 153.32812 518.5625 153.32812 518.5625 c 153.32812 518.5625 153.32812 -28.32812 153.32812 -28.32812 c 153.32812 -28.32812 153.32812 -124.03125 128.42188 -161.625 c 128.42188 -161.625 96.6875 -210.45312 22.95312 -210.45312 c 22.95312 -210.45312 -12.70313 -210.45312 -45.90625 -201.17188 c h f* Q } def /l { 152 0 64 0 152 716 setcachedevice q 63.96875 0 m 63.96875 0 63.96875 715.82812 63.96875 715.82812 c 63.96875 715.82812 151.85938 715.82812 151.85938 715.82812 c 151.85938 715.82812 151.85938 0 151.85938 0 c 151.85938 0 63.96875 0 63.96875 0 c h f* Q } def /m { 769 0 66 0 769 530 setcachedevice q 65.92188 0 m 65.92188 0 65.92188 518.5625 65.92188 518.5625 c 65.92188 518.5625 144.53125 518.5625 144.53125 518.5625 c 144.53125 518.5625 144.53125 445.79688 144.53125 445.79688 c 144.53125 445.79688 168.95312 483.89062 209.46875 507.07813 c 209.46875 507.07813 250 530.28125 301.76562 530.28125 c 301.76562 530.28125 359.375 530.28125 396.23438 506.34375 c 396.23438 506.34375 433.10938 482.42188 448.25 439.45312 c 448.25 439.45312 509.76562 530.28125 608.40625 530.28125 c 608.40625 530.28125 685.54688 530.28125 727.04688 487.54688 c 727.04688 487.54688 768.5625 444.82812 768.5625 355.95312 c 768.5625 355.95312 768.5625 0 768.5625 0 c 768.5625 0 681.15625 0 681.15625 0 c 681.15625 0 681.15625 326.65625 681.15625 326.65625 c 681.15625 326.65625 681.15625 379.39062 672.60938 402.57812 c 672.60938 402.57812 664.0625 425.78125 641.59375 439.9375 c 641.59375 439.9375 619.14062 454.10938 588.875 454.10938 c 588.875 454.10938 534.1875 454.10938 498.04688 417.71875 c 498.04688 417.71875 461.92188 381.34375 461.92188 301.26562 c 461.92188 301.26562 461.92188 0 461.92188 0 c 461.92188 0 374.03125 0 374.03125 0 c 374.03125 0 374.03125 336.92188 374.03125 336.92188 c 374.03125 336.92188 374.03125 395.51562 352.54688 424.8125 c 352.54688 424.8125 331.0625 454.10938 282.23438 454.10938 c 282.23438 454.10938 245.125 454.10938 213.625 434.57812 c 213.625 434.57812 182.125 415.04688 167.96875 377.4375 c 167.96875 377.4375 153.8125 339.84375 153.8125 269.04688 c 153.8125 269.04688 153.8125 0 153.8125 0 c 153.8125 0 65.92188 0 65.92188 0 c h f* Q } def /n { 487 0 66 0 487 530 setcachedevice q 65.92188 0 m 65.92188 0 65.92188 518.5625 65.92188 518.5625 c 65.92188 518.5625 145.01562 518.5625 145.01562 518.5625 c 145.01562 518.5625 145.01562 444.82812 145.01562 444.82812 c 145.01562 444.82812 202.15625 530.28125 310.0625 530.28125 c 310.0625 530.28125 356.9375 530.28125 396.23438 513.42188 c 396.23438 513.42188 435.54688 496.57812 455.07812 469.23438 c 455.07812 469.23438 474.60938 441.89062 482.42188 404.29688 c 482.42188 404.29688 487.3125 379.89062 487.3125 318.84375 c 487.3125 318.84375 487.3125 0 487.3125 0 c 487.3125 0 399.42188 0 399.42188 0 c 399.42188 0 399.42188 315.4375 399.42188 315.4375 c 399.42188 315.4375 399.42188 369.14062 389.15625 395.75 c 389.15625 395.75 378.90625 422.35938 352.78125 438.23438 c 352.78125 438.23438 326.65625 454.10938 291.5 454.10938 c 291.5 454.10938 235.35938 454.10938 194.57812 418.45312 c 194.57812 418.45312 153.8125 382.8125 153.8125 283.20312 c 153.8125 283.20312 153.8125 0 153.8125 0 c 153.8125 0 65.92188 0 65.92188 0 c h f* Q } def /o { 519 0 33 -12 519 530 setcachedevice q 33.20312 259.28125 m 33.20312 259.28125 33.20312 403.32812 113.28125 472.65625 c 113.28125 472.65625 180.17188 530.28125 276.375 530.28125 c 276.375 530.28125 383.29688 530.28125 451.17188 460.20312 c 451.17188 460.20312 519.04688 390.14062 519.04688 266.60938 c 519.04688 266.60938 519.04688 166.5 489.01563 109.125 c 489.01563 109.125 458.98438 51.76562 401.60938 20.01562 c 401.60938 20.01562 344.23438 -11.71875 276.375 -11.71875 c 276.375 -11.71875 167.48438 -11.71875 100.34375 58.10938 c 100.34375 58.10938 33.20312 127.9375 33.20312 259.28125 c 33.20312 259.28125 33.20312 259.28125 33.20312 259.28125 c h 123.53125 259.28125 m 123.53125 259.28125 123.53125 159.67188 166.98438 110.10938 c 166.98438 110.10938 210.45312 60.54688 276.375 60.54688 c 276.375 60.54688 341.79688 60.54688 385.25 110.34375 c 385.25 110.34375 428.71875 160.15625 428.71875 262.20312 c 428.71875 262.20312 428.71875 358.40625 385.01562 407.95312 c 385.01562 407.95312 341.3125 457.51562 276.375 457.51562 c 276.375 457.51562 210.45312 457.51562 166.98438 408.20312 c 166.98438 408.20312 123.53125 358.89062 123.53125 259.28125 c h f* Q } def /p { 516 0 66 -199 516 530 setcachedevice q 65.92188 -198.73438 m 65.92188 -198.73438 65.92188 518.5625 65.92188 518.5625 c 65.92188 518.5625 146 518.5625 146 518.5625 c 146 518.5625 146 451.17188 146 451.17188 c 146 451.17188 174.3125 490.71875 209.95312 510.5 c 209.95312 510.5 245.60938 530.28125 296.39062 530.28125 c 296.39062 530.28125 362.79688 530.28125 413.57812 496.09375 c 413.57812 496.09375 464.35938 461.92188 490.23438 399.65625 c 490.23438 399.65625 516.10938 337.40625 516.10938 263.1875 c 516.10938 263.1875 516.10938 183.59375 487.54688 119.875 c 487.54688 119.875 458.98438 56.15625 404.53125 22.21875 c 404.53125 22.21875 350.09375 -11.71875 290.04688 -11.71875 c 290.04688 -11.71875 246.09375 -11.71875 211.17188 6.82812 c 211.17188 6.82812 176.26562 25.39062 153.8125 53.71875 c 153.8125 53.71875 153.8125 -198.73438 153.8125 -198.73438 c 153.8125 -198.73438 65.92188 -198.73438 65.92188 -198.73438 c 65.92188 -198.73438 65.92188 -198.73438 65.92188 -198.73438 c h 145.51562 256.34375 m 145.51562 256.34375 145.51562 156.25 186.03125 108.39062 c 186.03125 108.39062 226.5625 60.54688 284.1875 60.54688 c 284.1875 60.54688 342.78125 60.54688 384.51562 110.10938 c 384.51562 110.10938 426.26562 159.67188 426.26562 263.67188 c 426.26562 263.67188 426.26562 362.79688 385.5 412.10938 c 385.5 412.10938 344.73438 461.42188 288.09375 461.42188 c 288.09375 461.42188 231.9375 461.42188 188.71875 408.9375 c 188.71875 408.9375 145.51562 356.45312 145.51562 256.34375 c h f* Q } def /q { 484 0 35 -199 484 530 setcachedevice q 396.48438 -198.73438 m 396.48438 -198.73438 396.48438 55.17187 396.48438 55.17187 c 396.48438 55.17187 375.98438 26.375 339.10938 7.32813 c 339.10938 7.32813 302.25 -11.71875 260.75 -11.71875 c 260.75 -11.71875 168.45312 -11.71875 101.79688 62.01563 c 101.79688 62.01563 35.15625 135.75 35.15625 264.15625 c 35.15625 264.15625 35.15625 342.28125 62.25 404.29688 c 62.25 404.29688 89.35938 466.3125 140.875 498.29688 c 140.875 498.29688 192.39063 530.28125 253.90625 530.28125 c 253.90625 530.28125 350.09375 530.28125 405.28125 449.21875 c 405.28125 449.21875 405.28125 518.5625 405.28125 518.5625 c 405.28125 518.5625 484.375 518.5625 484.375 518.5625 c 484.375 518.5625 484.375 -198.73438 484.375 -198.73438 c 484.375 -198.73438 396.48438 -198.73438 396.48438 -198.73438 c 396.48438 -198.73438 396.48438 -198.73438 396.48438 -198.73438 c h 125.48438 260.75 m 125.48438 260.75 125.48438 160.64062 167.46875 110.59375 c 167.46875 110.59375 209.46875 60.54688 268.0625 60.54688 c 268.0625 60.54688 324.21875 60.54688 364.75 108.15625 c 364.75 108.15625 405.28125 155.76563 405.28125 252.9375 c 405.28125 252.9375 405.28125 356.45312 362.54688 408.6875 c 362.54688 408.6875 319.82812 460.9375 262.20312 460.9375 c 262.20312 460.9375 205.07812 460.9375 165.28125 412.34375 c 165.28125 412.34375 125.48438 363.76562 125.48438 260.75 c h f* Q } def /r { 347 0 65 0 347 530 setcachedevice q 64.9375 0 m 64.9375 0 64.9375 518.5625 64.9375 518.5625 c 64.9375 518.5625 144.04688 518.5625 144.04688 518.5625 c 144.04688 518.5625 144.04688 439.9375 144.04688 439.9375 c 144.04688 439.9375 174.3125 495.125 199.95312 512.70312 c 199.95312 512.70312 225.59375 530.28125 256.34375 530.28125 c 256.34375 530.28125 300.78125 530.28125 346.6875 501.95312 c 346.6875 501.95312 316.40625 420.40625 316.40625 420.40625 c 316.40625 420.40625 284.1875 439.45312 251.95312 439.45312 c 251.95312 439.45312 223.14062 439.45312 200.1875 422.10938 c 200.1875 422.10938 177.25 404.78125 167.48438 374.03125 c 167.48438 374.03125 152.82812 327.15625 152.82812 271.48438 c 152.82812 271.48438 152.82812 0 152.82812 0 c 152.82812 0 64.9375 0 64.9375 0 c h f* Q } def /s { 461 0 31 -12 461 530 setcachedevice q 30.76563 154.78125 m 30.76563 154.78125 117.67188 168.45312 117.67188 168.45312 c 117.67188 168.45312 125 116.21875 158.4375 88.375 c 158.4375 88.375 191.89062 60.54688 251.95312 60.54688 c 251.95312 60.54688 312.5 60.54688 341.79688 85.20312 c 341.79688 85.20312 371.09375 109.85937 371.09375 143.0625 c 371.09375 143.0625 371.09375 172.85938 345.21875 189.9375 c 345.21875 189.9375 327.15625 201.65625 255.375 219.73438 c 255.375 219.73438 158.6875 244.14062 121.32813 261.95312 c 121.32813 261.95312 83.98438 279.78125 64.6875 311.28125 c 64.6875 311.28125 45.40625 342.78125 45.40625 380.85938 c 45.40625 380.85938 45.40625 415.53125 61.28125 445.0625 c 61.28125 445.0625 77.15625 474.60938 104.5 494.14062 c 104.5 494.14062 125 509.28125 160.39062 519.78125 c 160.39062 519.78125 195.79688 530.28125 236.32812 530.28125 c 236.32812 530.28125 297.35938 530.28125 343.5 512.70312 c 343.5 512.70312 389.65625 495.125 411.625 465.09375 c 411.625 465.09375 433.59375 435.0625 441.89062 384.76562 c 441.89062 384.76562 355.95312 373.04688 355.95312 373.04688 c 355.95312 373.04688 350.09375 413.09375 322.01562 435.54688 c 322.01562 435.54688 293.95312 458.01562 242.67188 458.01562 c 242.67188 458.01562 182.125 458.01562 156.25 437.98438 c 156.25 437.98438 130.375 417.96875 130.375 391.10938 c 130.375 391.10938 130.375 374.03125 141.10938 360.35938 c 141.10938 360.35938 151.85938 346.1875 174.8125 336.92188 c 174.8125 336.92188 187.98438 332.03125 252.4375 314.45312 c 252.4375 314.45312 345.70312 289.54688 382.5625 273.67188 c 382.5625 273.67188 419.4375 257.8125 440.42188 227.53125 c 440.42188 227.53125 461.42188 197.26562 461.42188 152.34375 c 461.42188 152.34375 461.42188 108.40625 435.78125 69.57812 c 435.78125 69.57812 410.15625 30.76563 361.8125 9.51562 c 361.8125 9.51562 313.48438 -11.71875 252.4375 -11.71875 c 252.4375 -11.71875 151.375 -11.71875 98.39062 30.26562 c 98.39062 30.26562 45.40625 72.26562 30.76563 154.78125 c h f* Q } def /t { 271 0 18 -7 271 700 setcachedevice q 257.8125 78.60937 m 257.8125 78.60937 270.51562 0.98438 270.51562 0.98438 c 270.51562 0.98438 233.40625 -6.84375 204.10938 -6.84375 c 204.10938 -6.84375 156.25 -6.84375 129.875 8.29687 c 129.875 8.29687 103.51562 23.4375 92.76562 48.09375 c 92.76562 48.09375 82.03125 72.75 82.03125 151.85938 c 82.03125 151.85938 82.03125 450.20312 82.03125 450.20312 c 82.03125 450.20312 17.57812 450.20312 17.57812 450.20312 c 17.57812 450.20312 17.57812 518.5625 17.57812 518.5625 c 17.57812 518.5625 82.03125 518.5625 82.03125 518.5625 c 82.03125 518.5625 82.03125 646.96875 82.03125 646.96875 c 82.03125 646.96875 169.4375 699.70312 169.4375 699.70312 c 169.4375 699.70312 169.4375 518.5625 169.4375 518.5625 c 169.4375 518.5625 257.8125 518.5625 257.8125 518.5625 c 257.8125 518.5625 257.8125 450.20312 257.8125 450.20312 c 257.8125 450.20312 169.4375 450.20312 169.4375 450.20312 c 169.4375 450.20312 169.4375 146.96875 169.4375 146.96875 c 169.4375 146.96875 169.4375 109.375 174.07812 98.625 c 174.07812 98.625 178.71875 87.89062 189.20312 81.54688 c 189.20312 81.54688 199.70312 75.20312 219.23438 75.20312 c 219.23438 75.20312 233.89062 75.20312 257.8125 78.60937 c h f* Q } def /u { 484 0 64 -12 484 519 setcachedevice q 405.76562 0 m 405.76562 0 405.76562 76.17188 405.76562 76.17188 c 405.76562 76.17188 345.21875 -11.71875 241.21875 -11.71875 c 241.21875 -11.71875 195.3125 -11.71875 155.51562 5.85938 c 155.51562 5.85938 115.71875 23.4375 96.4375 50.04688 c 96.4375 50.04688 77.15625 76.65625 69.34375 115.23438 c 69.34375 115.23438 63.96875 141.10937 63.96875 197.26562 c 63.96875 197.26562 63.96875 518.5625 63.96875 518.5625 c 63.96875 518.5625 151.85938 518.5625 151.85938 518.5625 c 151.85938 518.5625 151.85938 230.95312 151.85938 230.95312 c 151.85938 230.95312 151.85938 162.10938 157.23438 138.1875 c 157.23438 138.1875 165.53125 103.51562 192.375 83.73438 c 192.375 83.73438 219.23438 63.96875 258.79688 63.96875 c 258.79688 63.96875 298.34375 63.96875 333 84.23438 c 333 84.23438 367.67188 104.5 382.07812 139.40625 c 382.07812 139.40625 396.48438 174.3125 396.48438 240.71875 c 396.48438 240.71875 396.48438 518.5625 396.48438 518.5625 c 396.48438 518.5625 484.375 518.5625 484.375 518.5625 c 484.375 518.5625 484.375 0 484.375 0 c 484.375 0 405.76562 0 405.76562 0 c h f* Q } def /v { 488 0 13 0 488 519 setcachedevice q 209.96875 0 m 209.96875 0 12.70313 518.5625 12.70313 518.5625 c 12.70313 518.5625 105.46875 518.5625 105.46875 518.5625 c 105.46875 518.5625 216.79688 208.01562 216.79688 208.01562 c 216.79688 208.01562 234.85938 157.71875 250 103.51562 c 250 103.51562 261.71875 144.53125 282.71875 202.15625 c 282.71875 202.15625 397.95312 518.5625 397.95312 518.5625 c 397.95312 518.5625 488.28125 518.5625 488.28125 518.5625 c 488.28125 518.5625 292 0 292 0 c 292 0 209.96875 0 209.96875 0 c h f* Q } def end currentdict end /T3_72_0 exch definefont pop %%EndResource /F72_0 /T3_72_0 1 1 [ /comma/period/semicolon/A/C/D/E/F /I/L/M/N/P/Q/S/V /a/b/c/d/e/f/g/h /i/j/l/m/n/o/p/q /r/s/t/u/v/percent/ampersand/quoteright /parenleft/parenright/asterisk/plus/comma/hyphen/period/slash /zero/one/two/three/four/five/six/seven /eight/nine/colon/semicolon/less/equal/greater/question /at/A/B/C/D/E/F/G /H/I/J/K/L/M/N/O /P/Q/R/S/T/U/V/W /X/Y/Z/bracketleft/backslash/bracketright/asciicircum/underscore /quoteleft/a/b/c/d/e/f/g /h/i/j/k/l/m/n/o /p/q/r/s/t/u/v/w /x/y/z/braceleft/bar/braceright/asciitilde/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/exclamdown/cent/sterling/fraction/yen/florin/section /currency/quotesingle/quotedblleft/guillemotleft/guilsinglleft/guilsinglright/fi/fl /.notdef/endash/dagger/daggerdbl/periodcentered/.notdef/paragraph/bullet /quotesinglbase/quotedblbase/quotedblright/guillemotright/ellipsis/perthousand/.notdef/questiondown /.notdef/grave/acute/circumflex/tilde/macron/breve/dotaccent /dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut/ogonek/caron /emdash/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/AE/.notdef/ordfeminine/.notdef/.notdef/.notdef/.notdef /Lslash/Oslash/OE/ordmasculine/.notdef/.notdef/.notdef/.notdef /.notdef/ae/.notdef/.notdef/.notdef/dotlessi/.notdef/.notdef /lslash/oslash/oe/germandbls/.notdef/.notdef/.notdef/.notdef] pdfMakeFont false pdfSetup 612 792 pdfSetupPaper %%EndSetup %%Page: 1 1 %%BeginPageSetup %%PageOrientation: Portrait pdfStartPage 0 0 612 792 re W %%EndPageSetup [] 0 d 1 i 0 j 0 J 10 M 1 w /DeviceGray {} cs [0] sc /DeviceGray {} CS [0] SC false op false OP {} settransfer 0 0 612 792 re W q q [1 0 0 1 0 0] cm q 1 w [] 0 d 0 J 0 j [1 0 0 1 36 718] cm q [1 0 0 1 0 0] Tm 0 0 Td /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\011) [6.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 13.34766 -9.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 17.34375 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 24.01758 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 37.34766 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 40.01367 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 46.6875 -9.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 52.6875 -9.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 59.36133 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 72.69141 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 79.36523 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 86.03906 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 88.70508 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 95.37891 -9.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 102.70898 -9.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 108.70898 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 111.375 -9.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 118.04297 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 124.7168 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 134.71289 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 141.38672 -9.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 144.7207 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 151.38867 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 157.38867 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 164.0625 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 170.73633 -9.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 176.73633 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 183.41016 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 189.41016 -9.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 192.74414 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 199.41797 -9.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 202.75195 -9.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 209.42578 -9.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 216.75586 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 223.42969 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 230.10352 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 232.76953 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 239.44336 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 242.10938 -9.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 248.10938 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 254.10938 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 256.77539 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 263.44922 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 273.45703 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 280.13086 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 282.79688 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 285.46289 -9.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 288.79688 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 295.46484 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\013) [7.68 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 304.13086 -9.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 310.80469 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 317.47852 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 326.8125 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 333.48633 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 340.16016 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 346.83398 -9.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 350.83008 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 357.50391 -9.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 360.83789 -9.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 364.83398 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 374.8418 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 381.51562 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 384.18164 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 390.85547 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 397.5293 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 404.20312 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 406.86914 -9.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 413.53711 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 420.21094 -9.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 424.20703 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 430.88086 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 437.55469 -9.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 441.55078 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 448.22461 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 454.89258 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\017) [7.908 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 462.23438 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 468.9082 -9.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 474.9082 -9.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 478.24219 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 480.9082 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 487.58203 -9.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 494.25586 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 496.92188 -9.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 503.5957 -9.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 13.34766 -24.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 16.68164 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 26.68945 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 29.35547 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 36.0293 -24.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 42.0293 -24.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 48.70312 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 62.0332 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 68.70703 -24.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 72.70312 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 75.36914 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 85.36523 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 88.03125 -24.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 97.36523 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 100.03125 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 110.03906 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\025) [3.756 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 113.37305 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 120.04688 -24.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 126.7207 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 132.7207 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 135.38672 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 142.06055 -24.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 148.73438 -24.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 158.06836 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 164.74219 -24.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 168.73828 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 174.73828 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 180.73828 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 183.4043 -24.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 190.07812 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 196.07812 -24.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 199.41211 -24.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 206.08594 -24.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 215.41992 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 222.09375 -24.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 228.76172 -24.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 235.43555 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 238.10156 -24.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 241.43555 -24.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 245.43164 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 248.09766 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 254.09766 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 260.77148 -24.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 270.10547 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 276.7793 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 283.45312 -24.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 289.45312 -24.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 296.12695 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 302.80078 -24.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 306.79688 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 316.80469 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 322.80469 -24.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 329.47852 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 336.15234 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 338.81836 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 341.48438 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 344.15039 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 354.1582 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\004) [8.196 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 362.82422 -24.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 369.49805 -24.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 373.49414 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 380.16797 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 386.8418 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\002) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 393.50977 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\006) [7.356 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 401.51367 -24.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 404.84766 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 407.51367 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 414.1875 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 427.51758 -24.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 433.51758 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 436.18359 -24.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 442.85156 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 449.52539 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 459.52148 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 466.19531 -24.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 472.86328 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 482.85938 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 489.5332 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 492.19922 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 494.86523 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 497.53125 -24.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 506.86523 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 513.53906 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 520.21289 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 522.87891 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 529.55273 -24.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\006) [7.356 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 8.00391 -39.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 11.33789 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 14.00391 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 20.67773 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 34.00781 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 44.00391 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 50.67773 -39.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 54.01172 -39.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 60.68555 -39.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 70.01953 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 76.69336 -39.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 80.68945 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 87.36328 -39.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 90.69727 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 97.36523 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 100.03125 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 110.02734 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 116.70117 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 123.375 -39.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 127.37109 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 134.04492 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 136.71094 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 143.38477 -39.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 150.05273 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 156.72656 -39.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 163.39453 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 166.06055 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 176.05664 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 182.73047 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 189.4043 -39.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 193.40039 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 200.07422 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 202.74023 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 209.41406 -39.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 216.08203 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 218.74805 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 225.42188 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 232.08984 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 234.75586 -39.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 241.42969 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 247.42969 -39.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 250.76367 -39.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 257.4375 -39.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 266.77148 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 273.44531 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 282.7793 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 289.45312 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 292.11914 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 298.79297 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 305.4668 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 312.13477 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\011) [6.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 318.80859 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 325.48242 -39.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 329.47852 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 336.15234 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 349.48242 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 352.14844 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 358.82227 -39.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 364.82227 -39.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 371.49609 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 384.82617 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 391.5 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 398.17383 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 400.83984 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 407.51367 -39.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 414.84375 -39.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 420.84375 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 423.50977 -39.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 430.17773 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 436.85156 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 446.84766 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 453.52148 -39.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 456.85547 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 463.52344 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 469.52344 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 476.19727 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 482.87109 -39.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 488.87109 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 495.54492 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 501.54492 -39.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 504.87891 -39.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 511.55273 -39.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 514.88672 -39.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 521.56055 -39.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 13.34766 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 16.01367 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 22.6875 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 25.35352 -54.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 31.35352 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 37.35352 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 40.01953 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 46.69336 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 56.70117 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 63.375 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 66.04102 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 68.70703 -54.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 72.04102 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 78.70898 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\017) [7.908 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 86.05078 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 92.72461 -54.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 98.72461 -54.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 102.05859 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 104.72461 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 111.39844 -54.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 118.07227 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 120.73828 -54.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 127.41211 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 140.74219 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 147.41602 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 154.08984 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 156.75586 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 159.42188 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 166.0957 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 172.76953 -54.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 176.10352 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 182.77734 -54.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 188.77734 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 195.45117 -54.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 202.125 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 212.13281 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 222.12891 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 228.80273 -54.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 234.80273 -54.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 240.80273 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 250.81055 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 257.48438 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 264.1582 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 270.83203 -54.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 277.5 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\031) [1.836 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 280.16602 -54.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 286.83984 -54.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 292.83984 -54.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 296.17383 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 306.18164 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 312.85547 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 315.52148 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 321.52148 -54.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 324.85547 -54.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 331.5293 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 344.85938 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 351.5332 -54.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 358.20703 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 360.87305 -54.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 366.87305 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 376.86914 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 383.54297 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 390.2168 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 396.88477 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\006) [7.356 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 404.88867 -54.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 408.22266 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 410.88867 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 417.5625 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 430.89258 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 433.55859 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 440.23242 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 446.23242 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 448.89844 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 455.57227 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 458.23828 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 468.24609 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 474.91992 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 481.59375 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 484.25977 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 497.58984 -54.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 501.58594 -54.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 508.25977 -54.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 511.59375 -54.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 515.58984 -54.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 522.26367 -54.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -69.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 13.34766 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 19.34766 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 26.02148 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 28.6875 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 35.36133 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 42.03516 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 44.70117 -69.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 50.70117 -69.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 56.70117 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 59.36719 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 72.69727 -69.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 79.37109 -69.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 86.03906 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 88.70508 -69.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 95.37891 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 101.37891 -69.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 104.71289 -69.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 111.38672 -69.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 120.7207 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 127.39453 -69.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 134.06836 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 140.74219 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 154.07227 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 160.74609 -69.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 167.41992 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 173.41992 -69.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 176.75391 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 183.42773 -69.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 186.76172 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 193.42969 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\005) [8.028 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 202.0957 -69.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 208.76953 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 211.43555 -69.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 220.76953 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 227.44336 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 236.77734 -69.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 242.77734 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 249.45117 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 262.78125 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 269.45508 -69.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 275.45508 -69.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 278.78906 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 285.45703 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\013) [7.68 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 294.12305 -69.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 300.79688 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 303.46289 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 306.12891 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 312.80273 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 326.13281 -69.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 332.13281 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 338.80664 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 352.13672 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 354.80273 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 361.47656 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 367.47656 -69.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 370.81055 -69.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 377.48438 -69.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 383.48438 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 390.15234 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 396.82617 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 399.49219 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 402.1582 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 408.83203 -69.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 415.50586 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 422.17969 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 435.50977 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 442.18359 -69.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 448.85742 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 451.52344 -69.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 460.85742 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\025) [3.756 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 464.19141 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 470.86523 -69.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 477.53906 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 484.21289 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 486.87891 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 493.55273 -69.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 500.2207 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 502.88672 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 509.56055 -69.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 9.33984 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 16.01367 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 22.6875 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 25.35352 -84.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 31.35352 -84.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 37.35352 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 40.01953 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 53.34961 -84.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 59.34961 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 66.02344 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 76.03125 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 78.69727 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 85.37109 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 91.37109 -84.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 98.04492 -84.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 104.04492 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 110.71289 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\014) [7.488 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 118.7168 -84.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 122.71289 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 129.38672 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 132.05273 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 142.06055 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 148.73438 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 155.4082 -84.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 159.4043 -84.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 162.73828 -84.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 166.07227 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 168.73828 -84.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 172.07227 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 178.74609 -84.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 182.08008 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 188.74805 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 195.42188 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 202.0957 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 204.76172 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 211.43555 -84.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 218.76562 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 225.43945 -84.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 232.10742 -84.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 238.78125 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 241.44727 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 244.11328 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 250.78711 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 260.7832 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 266.7832 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 273.45703 -84.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 277.45312 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 284.12695 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 290.80078 -84.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 298.13086 -84.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 301.46484 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 304.13086 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 310.80469 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 316.80469 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 319.4707 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 326.14453 -84.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 332.81836 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 339.49219 -84.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 342.82617 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 349.49414 -84.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 355.49414 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 362.16797 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 368.8418 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 371.50781 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 378.18164 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 388.18945 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 398.18555 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 404.85938 -84.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 411.5332 -84.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 415.5293 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 418.19531 -84.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 427.5293 -84.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 430.86328 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 437.53711 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 447.5332 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 454.20703 -84.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 460.88086 -84.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 470.21484 -84.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 473.54883 -84.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 480.22266 -84.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 484.21875 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 490.89258 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 493.55859 -84.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 499.55859 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 506.22656 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 512.90039 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 519.57422 -84.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -99.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 3.99609 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 10.66992 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 17.34375 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 24.01758 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 30.01758 -99.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 36.69141 -99.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 46.02539 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 52.69922 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 55.36523 -99.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 61.36523 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 67.36523 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 70.03125 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 76.70508 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 82.70508 -99.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 89.37891 -99.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 98.71289 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 105.38672 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 112.06055 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 118.73438 -99.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 125.40234 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 128.06836 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 134.74219 -99.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 140.74219 -99.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 147.41602 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 157.41211 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 163.41797 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\003) [8.016 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 171.42188 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 174.08789 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 176.75391 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 183.42773 -99.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 190.10156 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 196.77539 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 210.10547 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 212.77148 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 222.7793 -99.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 228.7793 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 235.45312 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 248.7832 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 255.45703 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 262.13086 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 264.79688 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 271.4707 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 278.13867 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 284.8125 -99.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 291.48047 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 297.48047 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 304.1543 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 310.82812 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 317.50195 -99.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 324.17578 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 334.18359 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 336.84961 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 343.52344 -99.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 349.52344 -99.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 356.19727 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 366.19336 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 372.86133 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\013) [7.68 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 381.52734 -99.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 388.20117 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 394.875 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 404.20898 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 410.88281 -99.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 420.89062 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\025) [3.756 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 424.22461 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 430.89844 -99.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 437.57227 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 443.57227 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 446.23828 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 452.91211 -99.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 459.58594 -99.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 468.91992 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 475.59375 -99.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 479.58984 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 486.26367 -99.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 489.59766 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 496.26562 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\012) [9.084 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 506.26172 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 512.93555 -99.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 516.93164 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 523.60547 -99.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -114.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 12.67383 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 15.33984 -114.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 22.01367 -114.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 25.34766 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 32.02148 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 38.69531 -114.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 45.36328 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 52.03711 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 54.70312 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 61.37695 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 71.38477 -114.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 77.38477 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 80.05078 -114.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 83.38477 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 90.05859 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 100.06641 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 106.74023 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 109.40625 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 116.08008 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 126.08789 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 128.75391 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 135.42773 -114.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 138.76172 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 145.43555 -114.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 149.43164 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 156.10547 -114.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 162.7793 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 176.10938 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 182.7832 -114.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 189.45117 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 195.45117 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 202.125 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 212.12109 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 222.11719 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 228.79102 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 235.46484 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 245.47266 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 255.46875 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 262.14258 -114.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 268.14258 -114.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 274.14258 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 284.15039 -114.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 290.15039 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 296.82422 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 303.49805 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 306.16406 -114.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 309.49805 -114.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 312.83203 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 315.49805 -114.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 321.49805 -114.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\003) [8.016 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 8.00391 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 14.67773 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 21.35156 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 28.02539 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 34.69922 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 44.70703 -144.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 50.70703 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 57.38086 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 67.37695 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 74.05078 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 80.72461 -144.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 88.05469 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 94.72852 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 101.40234 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 108.07617 -144.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 114.07617 -144.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 117.41016 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 124.08398 -144.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 133.41797 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 140.0918 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 146.76562 -144.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 150.09961 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 156.77344 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 163.44141 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 166.10742 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 176.11523 -144.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 182.11523 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 188.78906 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 191.45508 -144.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 198.12891 -144.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 201.46289 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 208.13672 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 214.81055 -144.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 221.47852 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 224.14453 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 230.81836 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 236.81836 -144.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 240.15234 -144.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 246.82617 -144.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 256.16016 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\025) [3.756 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 259.49414 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 266.16797 -144.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 272.8418 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 279.51562 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 282.18164 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 288.85547 -144.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 295.52344 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 302.19727 -144.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 308.87109 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 311.53711 -144.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 317.53711 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 324.20508 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\016) [7.38 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 332.20898 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 338.88281 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 348.89062 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 355.56445 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 358.23047 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 364.23047 -144.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 367.56445 -144.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 374.23828 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 387.56836 -144.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 393.56836 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 400.24219 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 402.9082 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 405.57422 -144.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 412.24219 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 418.91602 -144.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 425.58398 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 432.25781 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 434.92383 -144.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 440.92383 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 446.92383 -144.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 452.92383 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 459.59766 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 466.27148 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 468.9375 -144.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 472.27148 -144.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 475.60547 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 478.27148 -144.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 487.60547 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 494.2793 -144.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 500.95312 -144.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 503.61914 -144.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\025) [3.756 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 3.33398 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 10.00781 -159.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 14.00391 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 24 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 30.67383 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 37.34766 -159.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 40.68164 -159.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 47.35547 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 60.68555 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 70.68164 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 77.35547 -159.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 83.35547 -159.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 89.35547 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 99.36328 -159.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 105.36328 -159.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 112.03711 -159.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 118.03711 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 124.03711 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 126.70312 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 133.37695 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 136.04297 -159.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 139.37695 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 146.04492 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\013) [7.68 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 154.71094 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 161.38477 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 174.71484 -159.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 178.04883 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 184.72266 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 194.71875 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 201.39258 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 208.06641 -159.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 215.39648 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 222.07031 -159.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 228.74414 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 235.41797 -159.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 242.0918 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 252.09961 -159.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 258.77344 -159.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 265.44141 -159.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 272.11523 -159.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 276.11133 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 282.78516 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 292.79297 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 295.45898 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 302.13281 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 308.13281 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 310.79883 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 317.47266 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 320.13867 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 330.14648 -159.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 333.48047 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 336.14648 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 342.82031 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 348.82031 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 351.48633 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 358.16016 -159.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 364.83398 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 371.50781 -159.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 378.17578 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 384.84961 -159.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 391.52344 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 394.18945 -159.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 400.18945 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 410.18555 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 416.85938 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 426.86719 -159.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 430.20117 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 436.875 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 439.54102 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 442.20703 -159.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 448.88086 -159.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 458.21484 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 464.88867 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 467.55469 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 474.22852 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 480.90234 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 487.57617 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 490.24219 -159.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 493.57617 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 500.24414 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\012) [9.084 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 510.24023 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 516.91406 -159.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 523.58789 -159.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 527.58398 -159.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 530.25 -159.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 13.34766 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 22.68164 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 25.34766 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 32.02148 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 42.0293 -174.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 48.70312 -174.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 55.37109 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 65.36719 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 71.36719 -174.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 77.36719 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 84.04102 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 94.03711 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 100.71094 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 107.38477 -174.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 114.71484 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 121.38867 -174.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 128.0625 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 130.72852 -174.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 136.72852 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 139.39453 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 146.06836 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 152.74219 -174.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 160.07227 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 162.73828 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 172.74609 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 179.41992 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 188.75391 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 191.41992 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 198.09375 -174.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 204.09375 -174.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 210.76758 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 220.76367 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 226.76953 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\003) [8.016 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 234.77344 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 241.44727 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 248.12109 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 254.79492 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 261.46875 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 271.47656 -174.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 277.47656 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 284.15039 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 290.82422 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 297.49805 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 300.16406 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 306.83789 -174.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 316.17188 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 322.8457 -174.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 329.51953 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 335.51953 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 342.19336 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 351.52734 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 361.52344 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 368.19727 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 374.87109 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 381.54492 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 391.55273 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 398.22656 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 404.90039 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 411.57422 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 418.24805 -174.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 422.24414 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 428.91797 -174.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 432.91406 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 435.58008 -174.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 442.24805 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 448.92188 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 455.5957 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 462.26953 -174.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 468.9375 -174.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 474.9375 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 481.61133 -174.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 487.61133 -174.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 490.94531 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 493.61133 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 500.28516 -174.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 506.95898 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 509.625 -174.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 516.29883 -174.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -189.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 12.67383 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 19.34766 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 22.01367 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 28.6875 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 38.69531 -189.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 44.69531 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 51.36914 -189.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 55.36523 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 58.03125 -189.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 64.70508 -189.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 70.70508 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 77.37305 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\015) [8.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 86.70703 -189.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 93.38086 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 96.04688 -189.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 102.04688 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 108.7207 -189.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 115.39453 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 125.40234 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 132.07617 -189.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 138.75 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 141.41602 -189.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 147.41602 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 157.41211 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 164.08594 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 174.09375 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 180.76758 -189.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 187.44141 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 194.11523 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 207.44531 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 214.11914 -189.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 224.12695 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 226.79297 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 229.45898 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 236.13281 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 242.80664 -189.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 246.80273 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 256.81055 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 262.81055 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 269.48438 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 276.1582 -189.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 282.1582 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 288.83203 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 294.83203 -189.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 298.16602 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 304.83984 -189.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 308.17383 -189.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 314.84766 -189.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 322.17773 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 328.17773 -189.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 334.85156 -189.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 338.84766 -189.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 344.84766 -189.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 351.52148 -189.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 357.52148 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 363.52734 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\003) [8.016 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 371.53125 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 374.19727 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 376.86328 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 383.53711 -189.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 390.21094 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 396.88477 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 410.21484 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 416.88867 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 423.5625 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 426.22852 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 428.89453 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 435.56836 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 442.24219 -189.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 445.57617 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 452.25 -189.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 458.25 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 464.92383 -189.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 471.59766 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 481.60547 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 488.2793 -189.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 494.95312 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 497.61914 -189.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 503.61914 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 513.61523 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 520.28906 -189.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -204.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 13.34766 -204.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 17.34375 -204.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 24.01758 -204.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 30.01758 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 36.68555 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 43.35938 -204.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 50.02734 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 56.70117 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 62.70117 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 68.70117 -204.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 75.375 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 85.37109 -204.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 91.37109 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 98.04492 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 108.05273 -204.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 114.72656 -204.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 118.72266 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 125.39648 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 135.4043 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 142.07812 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 148.07812 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 154.07812 -204.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 160.75195 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 170.74805 -204.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 176.74805 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 183.42188 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 193.42969 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 200.10352 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 206.77734 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 212.77734 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 219.44531 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\004) [8.196 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 228.11133 -204.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 234.78516 -204.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 238.78125 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 245.45508 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 252.12891 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 254.79492 -204.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 258.12891 -204.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 264.80273 -204.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 272.13281 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\025) [3.756 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 275.4668 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 282.14062 -204.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 288.81445 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 294.81445 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 297.48047 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 304.1543 -204.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 310.82812 -204.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 320.16211 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 322.82812 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 329.50195 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 335.50195 -204.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 342.17578 -204.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 351.50977 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 358.18359 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 364.85742 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 371.53125 -204.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 378.19922 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 384.87305 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 387.53906 -204.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 393.53906 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 399.53906 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 406.21289 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 408.87891 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 414.87891 -204.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 418.21289 -204.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 424.88672 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 438.2168 -204.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 444.2168 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 450.89062 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 457.56445 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 460.23047 -204.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 463.56445 -204.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 466.89844 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 469.56445 -204.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 475.56445 -204.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\016) [7.38 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 8.00391 -219.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 14.67773 -219.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 20.67773 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 27.35156 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 34.02539 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 40.69922 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 47.37305 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 50.03906 -219.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 56.03906 -219.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 62.03906 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 72.04688 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 78.7207 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 85.39453 -219.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 88.72852 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 95.40234 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 102.07617 -219.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 105.41016 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 108.07617 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 114.74414 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\013) [7.68 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 123.41016 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 130.08398 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 143.41406 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 146.08008 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 156.07617 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 162.75 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 169.42383 -219.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 173.41992 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 180.09375 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 182.75977 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 189.43359 -219.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 196.10156 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 206.09766 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 212.77148 -219.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 218.77148 -219.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 224.77148 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 234.7793 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 241.45312 -219.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 248.12695 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 250.79297 -219.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 260.12695 -219.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 266.80078 -219.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 270.79688 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 277.4707 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 287.47852 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 290.14453 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 296.81836 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 303.49219 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 310.16602 -219.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 314.16211 -219.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 317.49609 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 320.16211 -219.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 329.49609 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 336.16992 -219.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 342.83789 -219.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 346.17188 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 348.83789 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 355.51172 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 361.51172 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 364.17773 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 370.85156 -219.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 377.52539 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 384.19922 -219.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 390.86719 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 393.5332 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 400.20703 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 410.21484 -219.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 413.54883 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 416.21484 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 422.88867 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 428.88867 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 431.55469 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 438.22852 -219.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 444.90234 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 451.57617 -219.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 454.91016 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 461.57812 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\016) [7.38 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 469.58203 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 476.25586 -219.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 13.34766 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 16.01367 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 22.6875 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 25.35352 -234.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 31.35352 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 37.35352 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 40.01953 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 46.69336 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 56.70117 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 63.375 -234.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 67.37109 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 73.37109 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 79.37109 -234.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 85.37109 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 92.04492 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 102.05273 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 108.72656 -234.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 115.40039 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 122.07422 -234.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 128.74805 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 138.75586 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 141.42188 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 148.0957 -234.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 151.42969 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 158.10352 -234.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 162.09961 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 168.77344 -234.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 175.44727 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 188.77734 -234.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 194.77734 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 201.45117 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 211.44727 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 218.12109 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 224.79492 -234.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 228.12891 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 234.79688 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\013) [7.68 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 243.46289 -234.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 250.13672 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 252.80273 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 255.46875 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 265.47656 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 272.15039 -234.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 278.82422 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 281.49023 -234.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 290.82422 -234.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 294.1582 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 300.83203 -234.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 304.82812 -234.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 308.16211 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 314.83594 -234.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 322.16602 -234.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 328.16602 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 334.83984 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 340.83984 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 347.51367 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 350.17969 -234.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 356.17969 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 362.17969 -234.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 368.17969 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 374.85352 -234.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 378.84961 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 381.51562 -234.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 388.18945 -234.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 397.52344 -234.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 403.52344 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 410.19727 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 420.19336 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 426.86719 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 433.54102 -234.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 436.875 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 443.54297 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\010) [2.256 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 446.87695 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 453.55078 -234.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 456.88477 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 463.55859 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 470.23242 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 476.90625 -234.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 484.23633 -234.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 490.23633 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 496.91016 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 506.91797 -234.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 510.91406 -234.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 513.58008 -234.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 519.58008 -234.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 526.25391 -234.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 13.34766 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 20.02148 -249.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 26.69531 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 33.36914 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 40.03711 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\007) [6.78 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 47.36719 -249.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 54.04102 -249.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 60.04102 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 66.04102 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 76.04883 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 82.72266 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 85.38867 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 92.0625 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 98.73633 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 101.40234 -249.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 107.40234 -249.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 113.40234 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 116.06836 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 126.06445 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 132.73242 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 139.40625 -249.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 146.08008 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 152.75391 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 166.08398 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 172.75781 -249.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 179.42578 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 186.09961 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 192.77344 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 199.44727 -249.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 203.44336 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 210.11719 -249.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 213.45117 -249.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 217.44727 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 227.45508 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 234.12891 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 236.79492 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 243.46875 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 250.14258 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 256.81641 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 263.49023 -249.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 270.16406 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 280.16016 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 286.82812 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 289.49414 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 292.16016 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 298.83398 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 305.50781 -249.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 309.50391 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 319.51172 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 326.18555 -249.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 332.85938 -249.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 336.85547 -249.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 343.5293 -249.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 352.86328 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 359.53711 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 366.21094 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 368.87695 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 371.54297 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 378.2168 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 384.89062 -249.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 388.22461 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 394.89844 -249.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 400.89844 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 407.57227 -249.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 414.24609 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 424.25391 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 434.25 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 436.91602 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 443.58398 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 450.25781 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 456.93164 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 463.60547 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 470.2793 -249.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 474.27539 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 480.94922 -249.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 484.94531 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 487.61133 -249.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 494.2793 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 500.95312 -249.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 507.62695 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 510.29297 -249.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 516.29297 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 518.95898 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 525.63281 -249.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 532.30664 -249.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -264.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 3.33398 -264.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 10.00781 -264.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 12.67383 -264.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 15.33984 -264.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 22.01367 -264.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 31.34766 -264.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 37.34766 -264.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 44.02148 -264.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 50.69531 -264.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 53.36133 -264.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 60.03516 -264.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 70.04297 -264.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 76.04297 -264.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 82.7168 -264.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 88.7168 -264.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 95.39062 -264.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 99.38672 -264.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 106.06055 -264.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 112.73438 -264.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\013) [7.68 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 8.66602 -294.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 15.33984 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 18.00586 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 20.67188 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 30.67969 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 40.6875 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 47.36133 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 50.02734 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 56.70117 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 66.69727 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 73.37109 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 80.04492 -294.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 83.37891 -294.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 90.05273 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 103.38281 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 110.05664 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 116.73047 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 119.39648 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 129.39258 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 136.06055 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\014) [7.488 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 144.06445 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 150.73828 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 157.41211 -294.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 163.41211 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 170.08594 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 172.75195 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 175.41797 -294.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 182.0918 -294.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 191.42578 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 198.09961 -294.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 204.77344 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 207.43945 -294.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 216.77344 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 223.44727 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 230.12109 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 232.78711 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 239.46094 -294.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 246.79102 -294.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 252.79102 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 255.45703 -294.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 258.79102 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 265.46484 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 275.47266 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 278.13867 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 284.8125 -294.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 290.8125 -294.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 297.48633 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 310.81641 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 316.81641 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 323.49023 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 330.16406 -294.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 336.16406 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 342.83789 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 348.83789 -294.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 352.17188 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 358.8457 -294.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 362.17969 -294.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 368.85352 -294.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 376.18359 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 378.84961 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 385.52344 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 392.19727 -294.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 396.19336 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 402.86719 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 409.54102 -294.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 412.875 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 419.54297 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\014) [7.488 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 427.54688 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 434.2207 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 436.88672 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 439.55273 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 446.22656 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 452.90039 -294.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 456.23438 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 462.9082 -294.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 468.9082 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 475.58203 -294.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 482.25586 -294.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 12.67383 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 19.34766 -309.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 25.34766 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 32.02148 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 38.02148 -309.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 41.35547 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 48.0293 -309.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 51.36328 -309.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 58.03711 -309.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 65.36719 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 68.0332 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 74.70703 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 80.70703 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 83.37305 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 90.04688 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 92.71289 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 102.7207 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 109.39453 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 112.06055 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 118.73438 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 125.4082 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 132.07617 -309.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 138.07617 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 140.74219 -309.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 144.07617 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 150.75 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 160.75781 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 167.43164 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 174.10547 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 180.7793 -309.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 186.7793 -309.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 190.11328 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 196.78711 -309.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 206.12109 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 212.79492 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 215.46094 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 218.12695 -309.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 224.79492 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 231.46875 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 238.14258 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 240.80859 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 247.48242 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 250.14844 -309.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 256.14844 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 262.14844 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 264.81445 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 271.48828 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 281.49609 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 288.16992 -309.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 294.84375 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 297.50977 -309.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 303.50977 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 310.17773 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\004) [8.196 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 318.84375 -309.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 322.83984 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 329.51367 -309.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 338.84766 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 345.52148 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 352.19531 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 361.5293 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 371.52539 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 378.19922 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 380.86523 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 383.53125 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 386.19727 -309.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 395.53125 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 398.19727 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 404.87109 -309.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 410.87109 -309.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 417.54492 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 427.54102 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 434.20898 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\014) [7.488 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 442.21289 -309.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 446.20898 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 452.88281 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 459.55664 -309.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 465.55664 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 472.23047 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 478.9043 -309.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 485.57227 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 488.23828 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 494.91211 -309.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 500.91211 -309.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 507.58594 -309.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 9.33984 -324.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 15.33984 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 18.00586 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 24.67383 -324.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 28.00781 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 34.68164 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 44.67773 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 51.35156 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 58.02539 -324.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 65.35547 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 72.0293 -324.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 82.03711 -324.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 85.37109 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 88.03711 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 94.71094 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 100.71094 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 103.37695 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 110.05078 -324.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 116.72461 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 123.39844 -324.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 130.06641 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 136.74023 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 142.74023 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 149.4082 -324.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 156.08203 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 158.74805 -324.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 162.08203 -324.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 166.07812 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 168.74414 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 174.74414 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 181.41797 -324.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 190.75195 -324.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 196.75195 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 199.41797 -324.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 206.08594 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 212.75977 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 222.75586 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 229.42969 -324.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 236.09766 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 246.09375 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 252.76758 -324.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 256.10156 -324.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 262.77539 -324.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 268.77539 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 275.44336 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\007) [6.78 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 282.77344 -324.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 289.44727 -324.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 295.44727 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 301.44727 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 311.45508 -324.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 317.45508 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 324.12891 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 334.13672 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 340.81055 -324.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 347.48438 -324.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 351.48047 -324.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 358.1543 -324.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 367.48828 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 377.48438 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 384.1582 -324.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 390.1582 -324.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 396.1582 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 402.83203 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 409.5 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\013) [7.68 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 418.16602 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 424.83984 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 438.16992 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 444.84375 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 451.51758 -324.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 454.85156 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 464.85938 -324.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 470.85938 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 477.5332 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 480.19922 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 482.86523 -324.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 486.19922 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 492.86719 -324.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 498.86719 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 505.54102 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 508.20703 -324.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 514.88086 -324.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 518.21484 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 524.88867 -324.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 531.5625 -324.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -339.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 13.3418 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 16.00781 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 22.68164 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 29.35547 -339.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 33.35156 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 40.02539 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 46.69922 -339.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 53.36719 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 60.04102 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 66.70898 -339.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 70.04297 -339.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 74.03906 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 76.70508 -339.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 82.70508 -339.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 86.03906 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 88.70508 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 95.37891 -339.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 102.05273 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 112.06055 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 114.72656 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 121.40039 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 127.40039 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 130.06641 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 136.74023 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 139.40625 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 149.41406 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 152.08008 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 154.74609 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 161.41992 -339.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 168.09375 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 170.75977 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 177.43359 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 184.10156 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\014) [7.488 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 192.10547 -339.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 196.10156 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 202.77539 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 205.44141 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 215.44922 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 222.12305 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 224.78906 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 231.46289 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 241.4707 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 248.14453 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 254.81836 -339.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 258.15234 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 264.82617 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 271.49414 -339.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 277.49414 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 283.49414 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 290.16797 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 292.83398 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 299.50781 -339.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 303.50391 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 306.16992 -339.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 312.16992 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 318.84375 -339.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 325.51758 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 335.52539 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 345.5332 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 348.19922 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 358.19531 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 364.86914 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 371.54297 -339.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 375.53906 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 382.21289 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 384.87891 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 391.55273 -339.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 398.2207 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 400.88672 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 407.56055 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 414.22852 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 420.90234 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 423.56836 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 430.24219 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 436.24219 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 442.91602 -339.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 446.91211 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 453.58594 -339.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 460.25391 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 466.92773 -339.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 473.60156 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 476.26758 -339.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 485.60156 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 488.26758 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 494.94141 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 501.61523 -339.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\010) [2.256 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 3.33398 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 10.00781 -354.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 13.3418 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 20.01562 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 26.68945 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 33.36328 -354.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 40.69336 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 47.36719 -354.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 54.03516 -354.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 60.03516 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 66.70898 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 69.375 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 72.04102 -354.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 78.70898 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 85.38281 -354.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 92.05664 -354.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 96.05273 -354.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 102.72656 -354.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 108.72656 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 115.39453 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\010) [2.256 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 118.72852 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 128.73633 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 131.40234 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 141.41016 -354.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 147.41016 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 154.08398 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 156.75 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 159.41602 -354.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 166.08398 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 172.75781 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 175.42383 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 182.09766 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 188.77148 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 195.43945 -354.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 201.43945 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 204.10547 -354.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 210.77344 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 217.44727 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 227.44336 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 234.11719 -354.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 240.78516 -354.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 244.11914 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 246.78516 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 253.45898 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 259.45898 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 262.125 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 268.79883 -354.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 275.47266 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 282.14648 -354.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 288.81445 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 291.48047 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 298.1543 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 304.1543 -354.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 310.82812 -354.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 316.82812 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 323.49609 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\012) [9.084 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 333.49219 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 340.16602 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 346.83984 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 352.83984 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 359.51367 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 366.1875 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 372.86133 -354.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 382.19531 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 388.86914 -354.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 395.54297 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 398.20898 -354.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 407.54297 -354.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 410.87695 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 417.55078 -354.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 421.54688 -354.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 424.88086 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 431.55469 -354.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 438.88477 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 448.88086 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 455.55469 -354.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 461.55469 -354.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 467.55469 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 474.22852 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 480.89648 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\004) [8.196 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 489.5625 -354.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 493.55859 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 500.23242 -354.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 509.56641 -354.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 515.56641 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 518.23242 -354.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 521.56641 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 528.24023 -354.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 9.99609 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 15.99609 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 18.66211 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 28.66992 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 35.34375 -369.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 42.01758 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 48.69141 -369.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 55.36523 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 65.37305 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 68.03906 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 74.71289 -369.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 78.04688 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 84.7207 -369.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 88.7168 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 95.39062 -369.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 102.06445 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 115.39453 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 122.06836 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 128.74219 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 135.41602 -369.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 141.41602 -369.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 144.75 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 151.42383 -369.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 157.42383 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 164.0918 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\010) [2.256 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 167.42578 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 174.09961 -369.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 177.43359 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 184.10742 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 190.78125 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 197.45508 -369.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 204.78516 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 214.78125 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 221.45508 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 228.12891 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 234.80273 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 244.81055 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 251.48438 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 254.15039 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 256.81641 -369.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 260.15039 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 266.81836 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 276.81445 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 283.48828 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 286.1543 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 292.82812 -369.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 298.82812 -369.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 305.50195 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 312.17578 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 318.84961 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 328.85742 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 335.53125 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 342.20508 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 348.87891 -369.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 354.87891 -369.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 358.21289 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 364.88672 -369.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 374.2207 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 376.88672 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 383.56055 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 389.56055 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 392.22656 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 398.90039 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 401.56641 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 411.57422 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 414.24023 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 420.91406 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 427.58203 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 433.58203 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 440.25586 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 446.92969 -369.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 452.92969 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 459.60352 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 466.27734 -369.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 472.95117 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 479.625 -369.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 486.29297 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 492.9668 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 495.63281 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 498.29883 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 504.97266 -369.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 511.64648 -369.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 518.32031 -369.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -384.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -384.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 13.34766 -384.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 20.02148 -384.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 26.02148 -384.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\005) [8.028 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 8.66602 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 15.33984 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 22.01367 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 28.6875 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 38.02148 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 44.69531 -414.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 51.36914 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 54.03516 -414.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 63.36914 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 66.03516 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 72.70898 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 78.70898 -414.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 82.04297 -414.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 88.7168 -414.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 98.05078 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\025) [3.756 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 101.38477 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 108.05859 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 110.72461 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 113.39062 -414.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 119.39062 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 126.05859 -414.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 132.05859 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 138.73242 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 148.74023 -414.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 152.07422 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 154.74023 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 161.41406 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 167.41406 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 170.08008 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 176.75391 -414.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 183.42773 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 190.10156 -414.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 196.76953 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\025) [3.756 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 200.10352 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 206.77734 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 209.44336 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 212.10938 -414.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 218.10938 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 224.77734 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\013) [7.68 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 233.44336 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 240.11719 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 253.44727 -414.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 259.44727 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 262.11328 -414.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 265.44727 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 272.12109 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 282.12891 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 284.79492 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 291.46875 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 297.46875 -414.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 304.14258 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 306.80859 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 309.47461 -414.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 318.80859 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 321.47461 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 324.14062 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 330.81445 -414.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 337.48828 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 340.1543 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 346.82812 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 353.49609 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\015) [8.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 362.83008 -414.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 369.50391 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 372.16992 -414.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 378.16992 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 384.84375 -414.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 391.51758 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 401.52539 -414.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 407.52539 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 414.19922 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 424.20703 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 426.87305 -414.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 433.54688 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 439.54688 -414.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 442.88086 -414.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 449.55469 -414.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 458.88867 -414.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 464.88867 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 471.5625 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 481.55859 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 488.22656 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\012) [9.084 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 498.22266 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 504.89648 -414.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 508.89258 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 515.56641 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 521.56641 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 524.23242 -414.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -429.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 3.33398 -429.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 10.00781 -429.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 14.00391 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 20.67773 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 23.34375 -429.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 32.67773 -429.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 38.67773 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 45.35156 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 51.35156 -429.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 57.35156 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 64.02539 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 77.35547 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 83.35547 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 90.0293 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 96.70312 -429.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 102.70312 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 109.37695 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 115.37695 -429.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 118.71094 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 125.38477 -429.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 128.71875 -429.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 135.39258 -429.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 142.72266 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 148.72266 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 155.39648 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 162.07031 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 168.74414 -429.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 175.41797 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 185.42578 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 192.09961 -429.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 198.76758 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 201.43359 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 211.44141 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 214.10742 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 220.78125 -429.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 226.78125 -429.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 233.45508 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 243.45117 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 250.11914 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\010) [2.256 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 253.45312 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 263.46094 -429.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 269.46094 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 272.12695 -429.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 278.12695 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 284.80078 -429.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 288.79688 -429.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 292.79297 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 302.80078 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 305.4668 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 312.14062 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 322.14844 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 328.82227 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 335.49609 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 342.16992 -429.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 348.83789 -429.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 354.83789 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 361.51172 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 364.17773 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 366.84375 -429.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 373.51172 -429.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 380.18555 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 382.85156 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 385.51758 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 392.19141 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 402.1875 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 408.1875 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 414.86133 -429.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 418.85742 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 425.53125 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 432.20508 -429.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 439.53516 -429.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 442.86914 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 449.54297 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 459.53906 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 466.21289 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 472.88672 -429.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 476.2207 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 482.22656 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\003) [8.016 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 490.23047 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 496.9043 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 503.57812 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 510.25195 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 516.92578 -429.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 16.00781 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 26.00391 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 32.67773 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 39.35156 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 46.02539 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 56.0332 -444.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 62.0332 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 64.69922 -444.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 71.36719 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 78.04102 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 88.03711 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 94.71094 -444.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 101.37891 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 108.05273 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 114.72656 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 121.40039 -444.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 128.07422 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 138.08203 -444.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 144.08203 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 146.74805 -444.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 152.74805 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 159.42188 -444.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 163.41797 -444.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 167.41406 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 177.42188 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 184.0957 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 186.76172 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 193.43555 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 199.43555 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 206.10938 -444.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 210.10547 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 216.7793 -444.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 220.11328 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 226.78125 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\014) [7.488 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 234.78516 -444.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 238.78125 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 245.45508 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 248.12109 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 258.12891 -444.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 261.46289 -444.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 268.13672 -444.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 272.13281 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 278.80664 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 281.47266 -444.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 290.80664 -444.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 296.80664 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 303.48047 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 310.1543 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 312.82031 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 319.49414 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 326.16797 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 332.83594 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 335.50195 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 345.49805 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 352.17188 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 358.8457 -444.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 362.8418 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 369.51562 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 372.18164 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 378.85547 -444.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 385.52344 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 392.19727 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 398.87109 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 405.54492 -444.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 412.21289 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 418.21289 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 424.88672 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 431.56055 -444.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 437.56055 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 444.23438 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 450.23438 -444.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 453.56836 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 460.24219 -444.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 463.57617 -444.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 470.25 -444.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 477.58008 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 480.24609 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 486.91992 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 493.58789 -444.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 500.26172 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 502.92773 -444.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 506.26172 -444.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 510.25781 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 512.92383 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 518.92383 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 521.58984 -444.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 528.26367 -444.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -459.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 13.3418 -459.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 19.3418 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 26.01562 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 32.68945 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 35.35547 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 42.0293 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 48.70312 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 55.37109 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\005) [8.028 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 64.03711 -459.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 70.71094 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 73.37695 -459.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 82.71094 -459.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 89.38477 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 92.05078 -459.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 95.38477 -459.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 99.38086 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 102.04688 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 108.04688 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 114.7207 -459.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 124.05469 -459.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 130.05469 -459.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 136.72852 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 139.39453 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 146.06836 -459.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 152.74219 -459.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 156.07617 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 162.75 -459.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 166.08398 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 176.0918 -459.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 182.0918 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 188.76562 -459.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 194.76562 -459.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 198.09961 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 200.76562 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 207.43945 -459.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 214.11328 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 216.7793 -459.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 223.45312 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 233.44922 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 240.11719 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\014) [7.488 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 248.12109 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 254.79492 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 261.46875 -459.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 267.46875 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 274.14258 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 276.80859 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 279.47461 -459.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 286.14844 -459.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 295.48242 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 302.15625 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 308.83008 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 318.16406 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 324.83789 -459.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 328.83398 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 335.50781 -459.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 344.8418 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 351.51562 -459.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 358.18359 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 364.85742 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 371.53125 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 374.19727 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 387.52734 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 390.19336 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 396.86719 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 402.86719 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 405.5332 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 412.20703 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 414.87305 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 424.88086 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 431.55469 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 434.2207 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 440.89453 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 447.56836 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 454.24219 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 460.91602 -459.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 467.58984 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 480.91992 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 487.59375 -459.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 494.26758 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 496.93359 -459.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 506.26758 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 512.94141 -459.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -474.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 10.66992 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 17.34375 -474.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 23.34375 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 30.01172 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\014) [7.488 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 38.01562 -474.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 42.01172 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 48.68555 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 55.35938 -474.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 61.35938 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 68.0332 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 74.70703 -474.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 81.375 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 88.04883 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 94.72266 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 97.38867 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 104.0625 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 106.72852 -474.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 112.72852 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 118.72852 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 121.39453 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 128.06836 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 138.07617 -474.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 141.41016 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 148.08398 -474.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 152.08008 -474.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 155.41406 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 162.08789 -474.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 169.41797 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 176.0918 -474.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 186.09961 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 192.77344 -474.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 196.76953 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 203.44336 -474.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 210.11133 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 216.78516 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 222.78516 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 228.78516 -474.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 235.45898 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 245.45508 -474.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 251.45508 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 258.12891 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 268.13672 -474.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 271.4707 -474.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 275.4668 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 278.13281 -474.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 284.13281 -474.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 287.4668 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 290.13281 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 296.80664 -474.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 303.48047 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 310.1543 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 316.82227 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\006) [7.356 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 324.82617 -474.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 328.16016 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 330.82617 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 337.5 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 350.83008 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 357.50391 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 364.17773 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 366.84375 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 373.51758 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 376.18359 -474.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 382.18359 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 388.18359 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 390.84961 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 397.52344 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 407.53125 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 410.19727 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 420.19336 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 426.86719 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 433.54102 -474.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 437.53711 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 444.21094 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 446.87695 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 453.55078 -474.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 460.21875 -474.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 466.89258 -474.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 470.88867 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 477.5625 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 484.23633 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 490.9043 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 497.57812 -474.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 504.25195 -474.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 506.91797 -474.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -489.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6 -489.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 12.67383 -489.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 22.66992 -489.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 29.34375 -489.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 36.01758 -489.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 43.34766 -489.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 46.01367 -489.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 52.6875 -489.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 58.6875 -489.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 62.02148 -489.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 68.69531 -489.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 78.0293 -489.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 84.70312 -489.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 87.36914 -489.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 90.70312 -489.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 94.69922 -489.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 97.36523 -489.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 103.36523 -489.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 106.03125 -489.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 112.70508 -489.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 122.03906 -489.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 128.03906 -489.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 134.71289 -489.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 141.38672 -489.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\010) [2.256 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 3.33398 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 13.3418 -519.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 19.3418 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 22.00781 -519.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 28.67578 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 35.34961 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 45.3457 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 52.01953 -519.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 58.6875 -519.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 64.6875 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 71.36133 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 78.03516 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 80.70117 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 87.375 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 97.38281 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 100.04883 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 110.05664 -519.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 113.39062 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 120.06445 -519.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 124.06055 -519.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 127.39453 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 134.06836 -519.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 141.39844 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 148.07227 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 154.74609 -519.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 160.74609 -519.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 167.41992 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 174.09375 -519.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 178.08984 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 188.09766 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\025) [3.756 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 191.43164 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 198.10547 -519.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 204.7793 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 210.7793 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 213.44531 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 220.11914 -519.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 226.79297 -519.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 236.12695 -519.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 242.12695 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 248.80078 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 254.80078 -519.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 260.80078 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 263.4668 -519.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 266.80078 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 273.47461 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 283.48242 -519.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 286.81641 -519.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 293.49023 -519.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 297.48633 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 304.16016 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 306.82617 -519.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 312.82617 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 319.49414 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\014) [7.488 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 327.49805 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 334.17188 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 340.8457 -519.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 346.8457 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 353.51953 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 356.18555 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 358.85156 -519.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 365.52539 -519.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 374.85938 -519.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 381.5332 -519.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 385.5293 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 392.20312 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 402.21094 -519.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 405.54492 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 412.21875 -519.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 416.21484 -519.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 419.54883 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 426.22266 -519.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 429.55664 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 436.22461 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 438.89062 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 445.56445 -519.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 448.89844 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 455.57227 -519.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 459.56836 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 466.24219 -519.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 472.91602 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 486.24609 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 488.91211 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 498.91992 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 505.59375 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 508.25977 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 514.25977 -519.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 517.59375 -519.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 524.26758 -519.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 13.3418 -534.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 16.67578 -534.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 20.67188 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 23.33789 -534.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 29.33789 -534.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 32.67188 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 35.33789 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 42.01172 -534.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 48.68555 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 58.69336 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 65.36719 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 72.04102 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 82.04883 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 88.72266 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 91.38867 -534.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 97.38867 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 100.05469 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 106.72266 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\005) [8.028 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 115.38867 -534.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 122.0625 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 124.72852 -534.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 134.0625 -534.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 140.0625 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 146.73633 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 149.40234 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 152.06836 -534.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 158.73633 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 165.41016 -534.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 169.40625 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 176.08008 -534.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 179.41406 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 186.08203 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 192.75586 -534.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 196.75195 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 203.42578 -534.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 206.75977 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 209.42578 -534.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 216.09961 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 229.42969 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 236.10352 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 245.4375 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 252.11133 -534.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 256.10742 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 262.78125 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 269.45508 -534.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 273.45117 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 283.45898 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 290.13281 -534.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 293.4668 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 300.13477 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 306.13477 -534.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 312.80859 -534.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 316.80469 -534.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 322.80469 -534.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 329.47852 -534.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 338.8125 -534.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 345.48633 -534.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 352.1543 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 354.82031 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 361.49414 -534.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 367.49414 -534.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 374.16797 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 384.16406 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 390.83203 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\014) [7.488 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 398.83594 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 405.50977 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 412.18359 -534.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 418.18359 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 424.85742 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 427.52344 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 430.18945 -534.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 436.86328 -534.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 446.19727 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 452.87109 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 459.54492 -534.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 463.54102 -534.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 466.875 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 476.88281 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 486.87891 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 493.55273 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\026) [5.868 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 500.22656 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 506.90039 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 516.9082 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 523.58203 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 530.25586 -534.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -549.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 10.66992 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 17.34375 -549.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 26.67773 -549.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 32.67773 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 39.35156 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 49.34766 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 56.02148 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 62.69531 -549.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 70.02539 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 76.69922 -549.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 86.70703 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 92.70703 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 99.38086 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 106.05469 -549.58984] Tm 0 0 Td /F72_0 12 Tf ($) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 112.05469 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 118.72852 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 121.39453 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 124.06055 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 126.72656 -549.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 136.06055 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 146.05664 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 152.73047 -549.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 159.4043 -549.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 163.40039 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 166.06641 -549.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 175.40039 -549.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 178.73438 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 185.4082 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 195.4043 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 202.07812 -549.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 208.75195 -549.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 214.75195 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 221.41992 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\004) [8.196 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 230.08594 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 232.75195 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 239.42578 -549.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 245.42578 -549.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 254.75977 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 261.43359 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 268.10742 -549.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 271.44141 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 278.11523 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 284.78906 -549.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 291.45703 -549.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 294.79102 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 301.46484 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 307.46484 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 310.13086 -549.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 313.46484 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 319.46484 -549.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 325.46484 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 332.13867 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 338.13867 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 340.80469 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 347.47852 -549.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 353.47852 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 360.15234 -549.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 370.16016 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 376.83398 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\023) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 386.8418 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\032) [1.824 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 389.50781 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 392.17383 -549.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 395.50781 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 402.18164 -549.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 406.17773 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 416.18555 -549.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 419.51953 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 426.19336 -549.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 430.18945 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\037) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 436.86328 -549.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 443.53711 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 450.21094 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 456.88477 -549.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 463.55273 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 470.22656 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 476.90039 -549.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 484.23047 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 490.23047 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 496.9043 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 503.57812 -549.58984] Tm 0 0 Td /F72_0 12 Tf (#) [5.808 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 510.25195 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\021) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 516.92578 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 519.5918 -549.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 0 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 6.67383 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 13.34766 -564.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 19.34766 -564.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 22.68164 -564.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 26.67773 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 33.35156 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\000) [2.268 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 40.01953 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 46.69336 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 53.36719 -564.58984] Tm 0 0 Td /F72_0 12 Tf ( ) [4.164 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 60.69727 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 63.36328 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 70.03711 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\022) [5.892 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 76.03711 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 82.71094 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\036) [6.192 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 89.38477 -564.58984] Tm 0 0 Td /F72_0 12 Tf (") [3.252 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 92.71875 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 99.39258 -564.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 108.72656 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\027) [5.856 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 115.40039 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\030) [1.848 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 118.06641 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\033) [9.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 128.0625 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 134.73633 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\034) [5.844 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 141.41016 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\020) [6.168 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 148.08398 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\024) [6.18 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 154.75781 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\035) [6.228 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 161.43164 -564.58984] Tm 0 0 Td /F72_0 12 Tf (!) [5.532 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 167.43164 -564.58984] Tm 0 0 Td /F72_0 12 Tf (\001) [2.292 0] Tj Q Q q 1 w [] 0 d 0 J 0 j [1 0 0 1 36 756] cm q [1 0 0 1 0 0] Tm 0 0 Td /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 109.19727 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\003) [11.124 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 121.20312 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\012) [3.762 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 126.2041 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\015) [9.774 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 137.19922 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\011) [9.846 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 148.19434 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\013) [3.762 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 153.19531 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\010) [9.342 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 168.20703 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\002) [11.178 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 180.21289 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\006) [9.396 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 190.22363 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\011) [9.846 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 201.21875 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\010) [9.342 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 216.23047 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\005) [11.574 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 229.22949 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\003) [11.124 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 246.23633 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\001) [10.458 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 257.23145 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\010) [9.342 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 267.24219 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\021) [5.778 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 273.23633 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\021) [5.778 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 279.23047 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\010) [9.342 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 289.24121 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\017) [7.236 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 301.24707 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\004) [10.62 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 310.90625 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\010) [9.342 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 320.91699 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\020) [9.144 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 330.92773 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\021) [5.778 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 341.92285 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\000) [12.096 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 354.92188 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\016) [10.35 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 365.91699 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\007) [9.558 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 375.92773 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\022) [9.738 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 386.92285 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\014) [14.832 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 402.92773 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\010) [9.342 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 412.93848 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\015) [9.774 0] Tj /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc 0 Tr [1 0 0 1 423.93359 -14.10449] Tm 0 0 Td /F31_0 18 Tf (\021) [5.778 0] Tj Q Q q /DeviceRGB {} cs [0 0.6196 0.8784] sc /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 36 136] cm 0 -100 100 100 re f* 0 -100 100 100 re S Q q /DeviceRGB {} cs [0.8863 0 0.4706] sc /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 183 136] cm 0 -100 100 100 re f* 0 -100 100 100 re S Q q /DeviceRGB {} cs [1 0.9255 0] sc /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 331 136] cm 0 -100 100 100 re f* 0 -100 100 100 re S Q q /DeviceRGB {} cs [0.0863 0.0784 0.0745] sc /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 477 136] cm 0 -100 100 100 re f* 0 -100 100 100 re S Q q 36 35.5 100 100 re W* q q [1 0 0 1 0 0] cm 0 0 612 792 re W q /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 36 86] cm 0 0 m 100 0 l S Q q /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 86 36] cm [0 1 -1 0 0 0] cm 0 0 m 100 0 l S Q q /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 53 119] cm 66 -33 m 66 -51.22606 51.22606 -66 33 -66 c 14.7746 -66 0 -51.22606 0 -33 c 0 -14.7746 14.7746 0 33 0 c 51.22606 0 66 -14.7746 66 -33 c h S Q Q Q Q q 183 35.5 100 100 re W* q q [1 0 0 1 0 0] cm 0 0 612 792 re W q /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 183 86] cm 0 0 m 100 0 l S Q q /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 233 36] cm [0 1 -1 0 0 0] cm 0 0 m 100 0 l S Q q /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 200 119] cm 66 -33 m 66 -51.2261 51.2261 -66 33 -66 c 14.7746 -66 0 -51.2261 0 -33 c 0 -14.7746 14.7746 0 33 0 c 51.2261 0 66 -14.7746 66 -33 c h S Q Q Q Q q 331 35.5 100 100 re W* q q [1 0 0 1 0 0] cm 0 0 612 792 re W q /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 331 86] cm 0 0 m 100 0 l S Q q /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 381 36] cm [0 1 -1 0 0 0] cm 0 0 m 100 0 l S Q q /DeviceRGB {} CS [0.0863 0.0784 0.0745] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 348 119] cm 66 -33 m 66 -51.2261 51.2261 -66 33 -66 c 14.7746 -66 0 -51.2261 0 -33 c 0 -14.7746 14.7746 0 33 0 c 51.2261 0 66 -14.7746 66 -33 c h S Q Q Q Q q /DeviceRGB {} CS [1 1 1] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 478 86] cm 0 0 m 100 0 l S Q q /DeviceRGB {} CS [1 1 1] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 528 36] cm [0 1 -1 0 0 0] cm 0 0 m 100 0 l S Q q /DeviceRGB {} CS [1 1 1] SC 1 w [] 0 d 0 J 0 j [1 0 0 1 495 119] cm 66 -33 m 66 -51.2261 51.2261 -66 33 -66 c 14.7746 -66 0 -51.2261 0 -33 c 0 -14.7746 14.7746 0 33 0 c 51.2261 0 66 -14.7746 66 -33 c h S Q Q Q showpage %%PageTrailer pdfEndPage %%Trailer end %%DocumentSuppliedResources: %%+ font T3_31_0 %%+ font T3_72_0 %%EOF ippsample/examples/testfile.jpg0000644000175000017500000061657413240604116015721 0ustar tilltillJFIFExifMM*C  !"$"$CC" h  !1"AQaq2#Bru$34567RTUVbstS Cv%&DWce'EFdG!1AQ"q23Ra4#BSr$TCUb“ ?(('Dq4llb44:;m>B澬~vC.qDm-6TXՑ]8UR"[ŐߌV\?+WV^/9mC$0:wNUoұ0]88q@fHL-Ŵ4I$y3!WE}3ެ6.z7ӅF0HJ=C"k>l0Ψ% D2j?pxd*ܷV][*oRpqY5I+OLQ I~NK.9կp['ݮ[i}b Z@Lx]vnwۭl6{';W yT"ntD'8=e qJLO1l8Nx [ćPRJ^归AHO@2(R i6H> 7Kѝ%]PJRƒ>:k+OMO"cd.,!'xV2APq(ȯvM%/5!Cjm!`6@Ύrb-5qqIO1Kkpp弨*[wB__ èʮq\+nSeDNOyQEEPQ@QEQEEPQ@QEQEEPQ@QEQEEPQ@QEQEEPQ@QEQEEPQ@QEQEEPQ@QEQEEPQ@QEQEEPQ@QEQEEPQ@QEQEEPQ@QEQE;ߦ| 7Ρ}B9o::t}"CMeL&WTp%=m[PP< PYmiJ$";u8;iq\w8fevgdh} =gbGiC9A-SY!io8{ή4v[t,02.BtE`kc0aEGM@''HI;J9%Q ߌ ZiaZ iϊz% čVUEQ#KtE q6,Y<(=G^ BrQpg5Tzkt5jM. Aq֮k3 1]E\meꂼqD\UUgM6ֶRTyJ<`i|K^3pLyTs'EŁqчqd&[f:bf)WyRGyyެZ8fb tFha)I'rI&:)tsd>Ü9g7_, %JPՠdd !WOClO C_RbqUMY$`' IgdIuw>g¬U ]QSug(}~h"\1\8u;sug(}~h"\(yz+C4n {F OJy$z+C4^ {EOaʀ+I1?(x+C` W|=NydO^38/AfCGS~h G}4c4(uY>o}~h!\XU<GO?/bWn P{VV'<=GO?Rq >b*+v, [c4ʀ'EQf5iULA|0y^#E(G֝H3W<[+rGw)'V>.yWWSԣSgb_[ʴMm8֍Ӄ/Oc+߮c*KՐx!p8 \CǤ>cKZL)5l;$oqUG-ts+WLK a)'V*#%1$AO1;j ?W'_EgEqTW;&)Σ2;4vQ?G>'?V*Kϊ W)w W|]het~7+҈~/Jr#lwTyt"ѺHy8Yxc,ϧSSZ|F~/F9X=JT6U˼CfkI'ן= m%SoXVh# U'62ԆXx~l}c~05f]nBJR`(0GF.;nU}tu1KOl(IqIZ9` N+ G*36!R  VɊu-d_xBfږT G`79[N"駕]Jչq֥%R'׀q"*JDzZ.I^>SÓ lu)[檣svq$4T*[8ˇV)k B CgvU[[ہ_5nROKtT{8flʎ(;qx8Bfq,#J|r;{I}R\zSUˈ驇:sl>u*|S5DۺE8:.H#;Cn_}vRӔ#񏀪JPZ%7c[q -)# ׊u ) P=\m"DVV m7@Ɯgm rVҐm)wu2q{8cZ%khMJ\'WXj(qqȐy-TwVs !Jd$@=uxE$bٸׅڃmǓ%ԕ6s2y *t!sKH(B˅ӓNqU5YU$QEh8QEQEEPQ@QEQEr\xQں/qp\^Z^ĻŪH < FkvQ'H4+8h([-dc5ܒhǕ(S%,B] ˮ?ψ];y\Kjv-e*:N"PUiaOj$m1^]K9ҕzZJIQJ^B}nj|H%G}!Hq-z6^.z͡imZc^l}ܭ2Xxd~ Y/>p{}FF[6eղPP#7c-㶎[!J rc ?)I?8ME5VLnV+[@V6j^&PR5$lO#3ݡM1PZUݠ1NcXIb[lUj~9 BZƃ+$d[oUcI) aeN%[[|60*l9jMUԍƄ!Ns&\C gOFİm(6\%JF[V?qM/)RAp$55 2Ypj;d75)qzJ8!'8UW*RQM:?!s$)娜L[.U~QW*klhr\l(>¤J;֌#;mQwv6Giՠ([ * N y-48'jq:ܣAYP܎^u8_NyfX}ZRwfl {+.l$o `=QqQV,ywJSF^a@XR!A@Uo]+(#Nqa%-2 oJ=ե J)ޤVz;|,Voc5 =4Ցd%u۝J-?kRN u7Bn;{vVNp7rmޅr5*7 wm.(sM7f֚W~9yJmn+sLӜ(j8vB'&NUH\Fk ع\ˣ|5\EpR$m+*єUc*6t'.գWL"^#ۗ;b7;A֝]s dImȼK`JcVYa3\PZlqޓqF[h vpmM <96SYEʫaՒ\ y)ANKٖ؊Tj(痈ޢ;2nI)8@;g4KAqup }%)#sJ8~^^ Zlzb) -Jb3l{1ʜNX8P;{/^42DuRARG,c(N J98U|oFzԓBSs>[sjD-A YYP `8B\Q 4 |_6p+;d'g!*pR\N ]ޤw\% Kh#Gj? Q'JElu}bG}&U eGkпSti"_ qL 9"gr?l/]enA[ٸ@HZAP5 H %jFV9z>t=߄賨*!ژ՞eXO,gykэeut ٖfX Fj5`B¢7Hm9Dmc$u7BIq #"8#3uZ|,*'~EJ[+Ci:!sm(?E  2^rp H<}SM {j K7tI8$xrTp;;Sխnu\O)ÙBuTRBV<*HX75D)YR@8#at}P=QJVT6)9K ģ5i=7\tc:eo)wq{E(T `nGQ;6b!'H$dM]HӵV2YAbd41)*15%%zP*^#vsnD-lht$'(Jw9sT^2͸gnӡE. +PH(φaP~# FRtr $cyW[n*˭'ecbnsTrp~e{L(-DH/eQZJ6G qZo_+'g3oYJEU2٢q;|x RtBMsДR(!#⚟t} ԵϸT *[wI#56N.2;0$bsI dj%uH}O",DV{S(j9vLb1[Z$¤)9RζzB kWPIF>$2VP EQtI5lMm;XQT\HS*tjR@+Rv״Ō91/fcʙ,3)PKTVjIP \MڒJyWv1/<gJOu%Xɧ)4wձ3,lwiv+0H!ÜT?WwxUKXK*^q\1ƝfD!hZ$[ZNޢ7ȒN zv8h 3ߩ;%[)\ɫ4,C{a e@gs!ې4C.: H C+A S&В.;Fm3},@ZUs[z6 c=a-%<ķ[mɿB K6A^O;g}r48 ' ߃XXŠ(DB( (((( (tѓvzBR?꒯77ۦ /i)5 o1a픗Re%D@ָ˜c]U!4P S``c8?UTU+FV kݽV>="1 m$R#!CʜCyD-7n֕M4r@wd\1-7ciJ5ĐP zZ]$y5j٠t"GxK$2rC>ִ|PϐVvs3-V+bKi.KԥYZU_b8m=<›lvudr쫣Y8J0DV~zc}s.FsC uP U).mKkAJux>';{+$G~ԩkh$#ˇiTQ(nkU>THHI$%2!ΡI;f8VFRGǕl{o)IQO:J!1'2fh(#jԷe0q$9"C yIy֗'P<wz4n_r^ìej ݃βpVTqfDVɦԴk3ʳV'@~@F\H4FR mIVR@\Rg\`a*:Gy4;m.-Wr8jԎVVN}Hqz_\2+y|Y,(EE\ԅ{һMkA Ɲ-< Tt<*,Ѻ=(a(㭿{dcyRDLx͡ A9$eMFJt$m5S+3FRx缇Lu͓ݹW ZH*RHX|kLg%+Q(OqRyQ;bPB iYe-[IAXBD6N;OjRxwlaSPҬ]D~Ǝ*q+\cou-ͼ9p멒J liRO^}%frkAYWK.Hpn9ۚNY#N@L) J}`qX,S޷*3-;}ci,܉󫐸IYH퓎z dx4O\m)m&j$cQDžD]ꟑ*P 6RdEXAQNt;z]dJp=G;{U, c%q:q[K4!wS5c^BO3J.q:eC<37uk:V7=ZZ:);d'[@:Yr+'fps\UXaY,wׇ$gT9\/E|KiZ]SaX+#36#˸p0PKodrJpBC$u5}B,NGC_vMyą%mJB\>:4o4L;im|Dco1RqpՁ2(]̧BBRVNdvE  W)mJc R0Jw05E:s͕(,_/fޔō+>cʤ!W+žӞܚzu|;lz4i'(BtI;ds'<ثA s̙ҒR5e+> 8zxbj:sߐpq⩪7 cݏ*qVIV1% 6F )P+\)=p9[ yRPqJ46@WpgñuT͕:Ą!##'ľ-7!X)6gQqD9YT9.jL)1!/-m9Ղ]⧢eȰQ|-$ot%$w (J I1GK[[SBw99<+[Q[E` Gg 偕{*Z{ޢo :' ţvlP=BR2212d6XgJi&F`}ƚX-? HyL鷹![Vo:xtǖ5ɖ)JZT]C$ ?h6ݢ]ʊP(́ݟuTgZOe/V1Zs:l6-\-CNFe[7>lDElAЮ-$yl<ڳbpԅ}M]7N#dn,t9P]2Z.8)w {Cwﱮxf41N< ( (((( (( ӓW'xime%p,~滗6ŢSɂr"D7q˝t&H>>ҵ*|93nRJ-\DN܋cNEg]#my7)MCZe8n^T6]{.mhm]K()WVtl`Ծ}Dh;n1)#S{Q Fߎ/v9wMi)JNAcf惕Eb괝dÈulrTtJPd@jmDq ~j=CBT*Q=^@.g$|c95q3vYR$-ЉNPj!DjSSk} 6 ;靖Tr{\;e5)nfX؁ui6im-#P%IY'ʫ[-Mj@i4GF_Hq(礆mEA)ʶ#qc'2 ^x U0+RH>9;uQ%拺qG?R3K}tIPzp ')ǞnJy JN1GX۴ -#*SyʰqNiJy>/g!dl2;d^܊tQ GөGzi+/f=s-)Tk*9% ]l.|=>i[)֙Mځ' ugo Ĭ)SJ%+yOf$B^_-2#u)9} P 4\^~2Gi@aJް$x#u2[^%ZXj :Bv)JyZT![J?jZZqz\ZРs6XD_!,6i I8V;>Ul=82؜,'f8 T *b}mBx綧buX[U9t0Ԝ(of+ewD>&vc #1ŒzVR2k=Xd vUQx?&#-0|u~1N͜0ZAljc!$IʒK[e#I88usS}}*GȚ)}* s5F&0W.Д°Ѐq,ʌyۣHHۑ<{=j@w8fxHIqo62j9˕bƺPr4yIuzm$is [[}{!,PhmjO2VጃxkTmHh)J96=Pu˧B*ĺЀ[i\mz%C^ygOiz̀VIarvNx84/B]2: -!ܑ("]v%]e{|dsmtnG]4y>Dhu'%-//r# oF1(wh* JܱcNȹ%jK%i@h+me@7߻];}iu (82SϽ@zGic) j'z\0" 0 ,FwdQ .u8!-ώW)+GS- uNIt˩} @J(a8ΰ!T| =T6BDyoN*2(XwᛣX}Ȁ<5P9_E=5w{-)e6@{}NEBR|cGK3IB;՜E-t+rFhRRڐ Ps4洹u$w9ׂlq!!8Rqk2hGxWjzH0S|ksy4:] I#N3΄5TffuaJ$]4KL=!„឴Q$ #{*ϙx`18劆]Y8mM d=UPyNjGMNFE1%L4%$$$IZHRT{Ip_L{$]!wPbcy!*mj SzGINq\iz:|T֖H'Q=Uq8ͱ2P뮧Qsb0wVѺ͹K4 Z2Ar+BdžH 'PP%9 z=.2%; lj9JIwž1tQ*)Q*ǎ sn6MRHOꯒ3,WxMiˑvìTzo|9:,8K+L7(FP Adr5Sn~7 %.amFA/)#+O^^͕7} 6q|sZݶ#cca;9Q{iL:HJ)R5bsQiT9xkN s*#R$>p~j1_iw57!KZT!G+P:8jp- ѡC)>xzqHbdL!JuyޟԦ.G[Sώ(8ӈ$䅤=5<0a=5K]Qev@<<{iobR }Gh 5k:Ϯ>8|RwHp SRHGw'zIi]YW>urҖqc5K9\9Pߟ/ zSdprUE/DDi|H}Tbe  Zg=k(+#=N}Ra$yi[2;%C VGY;OI(#{JQ#$|8F։ӡ@+H')$ *cjq l(,ual }TJt탎xԻk]XEu/!kK=jI*N~/dcl>4cK ^3sT}/tń |vr589^TFv2<}bJsݚJLezL6BOm8 :R`V14iikȀцFH{!I%(lsmJOZʆq|?띭“ }Wj HJG#2om!0HOXr}zXə+2^q JJJFs]¢ihPH;aOJS7I,$\jmh@gEBT}ӥBKxA:v'4We!XZit#>RdNhȪݥ)Ji"!Da dΣSWZٷ>) JHѧSzM6A`$d:T}bq2j8FIߝ K-zs,xwpPwwe>N{H匦89zo\|%yWlF cuQwK?kR[$34 )Ī"8Ri<|EE7yi zYmN*eZL-<3pmH @Wkϯ11RZKBͶQEL((( ((( z ?GoFN{ͱu9I忕w'HK)R6%4$5Ɇ5nZ޷5NPH۞fWo>Z\ȗ~-mfNAENb}2#ɘ9Y(sJ#u)*:N÷;VP;,$\SHYp5&fnWSNǎ -IQ9+dT&Y%fDbNlt- ^ 6#ڄyŜc'H#<+W:jhр+i(tA;a9w 9}SV׵*u'8$o*SRQh"ti(Ry!v[H\dih$0`vR%8yZxN҈NGbr ;rJ߼wny{\2_q8J8m8BcNvQ&^:z$! 2nD;7Hw8?[cZu#d"R;yJFH8Xe:AJ q/*Xv?)TT2T,ih6\%]bb>I; =-0CKkCr- 2vdGv&VTө8$aY`uw5-J & &Ep[R Q5b$KyV5g!u8H=>iFvLl)m$69ګI6m\58SKiħQBO ]ԵV9RkʠHs+K IIs0]!=1Gxf7ih2ְ(JäO~ *GEr#db,R҄䬸bTZԠ$vRm@w} >یCVڮ)M'a ,O:[)e.ő\Rp*A08;kƂJI-L9ֻ=.Ư փÄ76vhMYJ`5+mN& 0U*n 2S'c:R<@)Ϗ:@D\ҧ$yՌzu. Yҭ,_ yEJ 鑮<@GVdly7`PMlу,{Nn&UvŦfR +4nh2[j޽n t05 ޭ? Gvto@9%SV!S!*I9.&ib;<}GvT_pz{_T)]L{PTiNN{dvtlw"|(D-XryE(q*|4ښt8~4`0UGh7B4{Q`wƣ4ZZէ[D T2K$% TRxI;aR< ]1 -u[Yc2[&0/sBq[SHeo`L(e H^"!׺Uwָ UU `ԏ;)*匍cr+ d jL(JNN pS7p$|zfYFWPt o-L=ql/@‰h'Ni$aPFBpHpwj74CyRq鷙f-޹u<ybt)jnG\sG[qe)xJR.lJ/McJs̲|K`ۏU+DUJST9Vp̅ T-d,y^=Ƭ>3nILvRR o"xˈ CS)IQ }c¢sDl$7%*Qp!2$?l[o[U%9L0f8*%Mp9*芞4) վ#jB՜sj+RNH7/]'${jCW, "GJJXQXSuqc7iTd7胕)ƃ6ؤD jBKJV)-\Ysu ۙ#$F6F!1hG l}5"t(QNXΡH4Ԇ[j*ӊ$`jS8m閔hQγmaZڐSw۔lrxmZL-!M6) lwR;vKj@鯇%"IXl(Ύ~?9{~QveNɷQE2!EPQ@QEQEEPQ@T_U˗mm)cHunNvBb#5&"RFT㰔s+_$jYHV;\ZS3gԖ gʲWR4RI РT;\fBijtpr89s *JzH mIv8L}:pǗ"}U/{nܵe- 9'9ǨiMi̹FK?î귪q)el228;,˸yƥGWrt0Qi"IJ;J.:UWM~r'm `?T9*e ȎУ;JU;ss<):VzƣFoq([mYYֲ<|3ϗ 7fub]wpv32![p/ V~7~yZ.8c#BcNۑ5^ [Ikљ*8Μmqv7KBYJZ-%8u3sp;r%ɲJuz5R3F ޡ;7*!** Rh9es:2*V1Uݕ/x@F yr#M8⫑2:0B%Gc0)ŞRn[${MKsϖý0O\;C^춤>V2>LMwŴԦKi)*'C)<>iۍyE0ûg:7o0E.IX-:A;ž3&mm)*%#lIM-L&,\~ ʜi•ՁIn/ͳz#msIܨN7_}r>mp1s /Fc $a#ʛ!JBrrRBS8=܇}vR̼!;;ܩq,)O<5#%(s >Gš_luFJPדah%Cqk͛tu.2PRBBxߘ|ꤖK{[}9w$ gFP)9ԣdVFuO [9,or,rV*8PQ#ױp s]l\=%FHy 7Rnh # 3m8;e~e_f^eRԧKZV|H48]?apuB U؎ucqGqKRcLdZXu.549F+nCɻĊK)K@% $Wd!); m:#dt KO>cH vz:[+Rn+@Yqy!'8/ޝosٶ=yJBc' Zv]RSe\jrcSD =` ]ZV>rT(ߙez}xD ;mEjjhu*Ԗ?6}4qjw)yeF9#Q4j h4ʣR0FTAϺoAQR7܁IT'~uKFSKVA53ù6_ R) `㗻4`ղl;iZSHCxFu7hIpp)mN-޽-֢y;Ou'q*:V5ڕ#YC; ׶D74APSɴiB]냤IU&}ѥa`JG fHȎl#`yӡ(civԢ9q_2!G+!$B $xR i!* kiA%; I,p_X1q,kܐH ou`PPJ0 }la凨ˑ3Rd =bH[./+k |qV RfS:\ZԠ7V+Z95Ǘi%:V5)WwyMPBRH*3NVD`{T9+-J | Ğ*-"ql8JNOO3^::JW#B7Sg == <Y=nu#8N]% OPW6]]^mD[ޅJR\$<<\G,m٭ηDy+?b R|9ƣb-< He`oF+ZeI;k.Vlr>6; v\oѕ.Ci:ث8v~JOXV )Br"J#bAk1 bQ"U~*=P%9ޅm 6ߝHUM(PzRlUi<2 qlJeԮ8@g )%u߿µ:Zʂpy{Ra&2c@6 `~J-jWfг @ySunO!ކҕ~(z1Q.iȍ! !?IBRm)BVO?.om.oThRJ<>[ K2 >icXA\iԍ;9V ȎַP; 7sg9d2]KQ[F:Уs#o-M#坴4(M9/KO):GN=›k!IVr ӊEy O:"֝bV2Ĕ}jܥn@[k'c ?meyW. !u eGnP\C+m\6yΆƔ$TFuBHv82^>?* >θyO(a ZyRXҖ-ZT)8ǿ]ڒzGONVҮ{;~{Stuim̂}}vN;0*G( (((( ( E4]B&z5[ $QG(XP LJ[+#TUi-rpf4X:ΩZRRB}BIoeX10"B\qWBre;5'`9Ԯ3JIqDx':㵵G{E} NF#G[Y+]:a/X2UT!g)ݦֻm'9f]c͹$ LrTUXUqymwk# HqNN;/# k* `娧?O)M|A>G אJ@@`TTq-qp5AՒT-6Y䓚[n!fGlʊB.IB_QJ:pPm;r*ڔĉ9*HSJH#eK\ʝFdʋid3- <5ylq+:SRHKm?ϒ~)և L+AC? 'lF̈.{Ȩ󔯌r,=޿A=%Rɤ/ ZwRTBGҋs7Hm)g1Ev-ʐTvwu'Rsld~fg&d8ӎe'm'{{-6JgʬGMl)dso*|**hXޒWD+8F >1ZT.ĕ5 .gԵ=I{XR@@QRqP PC'wyIr:ckGH0 '⓼JG;d{8!ᧆ`V^j$}&J-Hi {MfJ 2Clyx׊T'-6RT OZ0yZ܆R+-j q:m䳤5 29RqqevN\jds6nDHҮ  TZN)Hҭ)ŲT ea Gm_֕%BsJ*!( JN[(%Z$~J5)տd˟"KwZ\)Գآ5 ㄵ%+%Iޣ\;8a48SmΖ[N-YoRqQPVl NqOH y #*i$-:yN-'bȦՅJB2܌CIyЭ* "r(뒄'GNN yྦ#=-9*nHqJKi<9Ҷ6sQsq+)ӑL8ۨJJ~6䕈s{&: zGŭLGf-"V &f}?9.>\Vn= { $\>ʝKZ0 VG,BG8Ns-#XZdv)=`IR5}ؚX\{ksNdV)@ߞƘx*-%, :*ut-n3B֜NsꨧqCP Byn,m9:rIIr}M8ӕ FeNi&,%+-:ms%O))*Ndck]g\ѹ$yniՎ(lmW+y_~Q?95!) uhjluO[z;-ͷpq^CͷpFG=䎊l _T``26'<ø> VOR.Tj J Sw v) րwR1:0 4aCtgO(.p-?cx/zES_օ 9>s) bD teIR:4ZdOq K2Q u7y% a\ƓQ>g ể/j GpHSg[p[L u +*82N7^(}eaFiy[L_ iLJ?]kőݸz`:GRAd6$׫uLNL;M.ՂKdr,TZrk1m6VO9-J‘i<ȥB]h̔,~pR⋍-$`{Vž-S$Orycbsq{Z.u _7=1&.ujNU\Ghj즜!iB܌IS~'ʡ^2sRZo)T4Ny\FhM7q#+†H Gʕ:)Vyc⁖ܞg ieHNH.JDU$j2r.P4F/ԕJeۮiN)I0q]G %<ʟ.Adp`r'VI$~\LHg)JAߖ{L44' 3c%tq `:C`x`.6vڧ#rK['ӎ` ω5Ekɤ|IܕNzTEi8mҕ6F!~Hں/ %ҝ^|u:`À'׍1ꮴ|u3˛QE^VQEQEEPQ@QEQEmH::3q%Q?m\ԹQ"l)|T#ĶvZ<={͂W07ʻs#RVGvGJLIiҒns=W^d:҆Iwf!f!'u$!~[䮩3F!$/ X: O^7W`MT<*zu({4 ŒÊZ<]Jd]~mF2 Ƣ@ Am}gaNS˥&W]BKNU)INI&8B @TqЋ6;JxV^: I< w=D1UHmκ3 a` μJ޹#᷁X5}[,ZZrDdeXH r66b˚SJ`83%`{qPwR? eDVVH#89ڣ]$b;lQc&@ ƹGxlBǸXmSBJOV- iČ|϶ccfz1^2 @e8|ҮAc#' I{#'5=C}IC'q rqGzJhi=-Hq翿辶$&dV*\|6ڜKH-PӜwʘٚ8$)vqiN|,Ӵ1BjPT0sjdbQKo20Y'a*<U<C ()% wI P+'[`!Qp:96g)KS: 9B[J[ 6R %);X]%.óC>T)( $i'RpTrGl*8TylMn;}M()^8c#ʜaW+v;|]!F:eL!Cs<Ǵfnz 814) $:P%e$χ#WuHͰ㩌t V(I U7@r%̡\@Nxi=ʏ*q\F^u*TOGIsNB?jU(M$+T+)]B%2eŗR1皼)K̕clpyp2 YP$(>H +}6=֌m>]G!b2Sn#';{iI4M( `u#=7 HB:qAEXNun@ʹ4uI9y\G}ȸcw!zR3M2q7-7R:L4qF0}#;ǰnлRk^ d|aԾs!Jc\eȷ#`6%$MUٸbCжF|6->P |zR f4!jCGCb-/ʞXgSW{gC`Wo<-ZP( qJ+V!ˈurR}q XWW@bQE,b+FPQ@Q@(( (((( ((ы8|o\nţ،\.#鮖2z'$^uͶ.i+|xUq+m1K\ zq8~ԓRmȥI=M+!b!@Q8,ia Y#TC.*ĉ}E<"MіL50y:j{jin7չaXΠ7]%Gˇ~z'bI6#h0i<<=T园„><)zp.7X801{AM%kTh)inВAIkR`.!˭ĥ ds|32UwjRAI(+;dwc7f2!@(r; qIǫy8`7jJْk.4%X.oa-Ϲ+ Cdq)E,yK zT}A :N4GcPlvPkr#͆X ԡ~C, ~ ǝmaL6T%%cJէ*'3>Z*Ez42[y8qG7qkP%YH'i4\PZz@HҮZo]I"݈R!YAVOwƣNycGTiNb%!Y=uA55s)Y*Z|ơ%.iWg*IҴ9AҠq[8UT|)*llEM2-֢΄aVyK0v Q$hq%%D  )m!+sLh#P!=6FNM[Qz2ZS8BN2I% rSʖ; qwTp(g|K>dR9Y;oL~A!^\7@P\I>4Jki@Xݑ_I f/8=^s+M HЫK))JHBv,Τ6PJt% uy+%^yI ul%c>;cYY!ϸ%r2 3jSQ##ncsݏ_:Dx%pMw`V&b8zF-E9ZylύI=l3rZ $9aݔry^U$k Ԭ/=ղʓ-P`F6 N|+&%QM8n.̀m2RQx,)HQ9*b-MeSҮHZzlGy<"Gnx|zte8 %*ߚP*W1I5ƳJ ZyI-;'(NwV8+;~[W jCdTThտ‰Ŭ~ F8:ukiCNQ)94drdȆD)ivp0A崕ÝNſ#rsUƟT{n5ROZt #␢v;[dn1M_SV [qxb.}߇x_Tc#*B[\&.$Ju;G*тrk،Kq%U˧L#} aXNvӸ J(v6#?=Tguv3h[H+'9Wq{k#YSh+Stݷ\"k [K NFw¥2!球%嗚qmDbت&'Cz=8n!ɺ@*e"C%HdJHwRXiF5TK3k_K!nDF+:IeNgd¶m>ޙ[2:R1 ;YTL֣wOe`ˎ,ҽAOHDa3$N@rbE:!#-=wcǺIZz=MTص8s3:3)%^pgdϬԄ䀱icC·uʋՀd)DӋn%Rw?WSW]+$J)Vq蓩UWlu3z8nz3yP$T5}V2mkYˏv'w-Nr~SJ^jkc`F(aN9fB9O-Ӂ O(3-%ŷޔ)dn)D\Gef)Gq'&\2Piip{NayV;-J2LBq~XƜePSt؈O7qNC}"ݵܮjA܎Ȧ{a!Uʶ{bZ,]ƴ+EY;v/s ڽw*z*Dv,~ùSk;T+Dd {½fO\+&aHqL* Np{Hy}奶IZԣI5̉*}P]gQ($6GaV3WL3E#9.7Zpm Mr*\Xԡ8T5p+ԩ$rMɶAkV)hyEw8yNXʊ4fh;Ac*3X漮:y5hAc*(;EW@QEEPQ@QEQEEP3Ѻ/ϬzwQp7>]!Fi!I2=K( }g\8!⨥R?%V|NgI>Y?כZ, /FS /I80ղ[u@ g٫XyHX=qQ[C ` xTi%NύAIRV̘_mR) ヷ>=nmEp=ygj}MZh#wpWޠ8sHܟ lxS+CRgs,Sԩh/)߸c=W]INBv=ǝ4ˊE1ȁTJ4#~F:F8 !g_~/jFYͲZZX+ Hϰc;cԈHqՎD1*^9!2kH ۊ>()qA/ve$$Vo6AoE[qhЁ>&j=-'E NQsjɥrMxj>綆2 $ĩ 6Sy֋Lc4˒sRs^HԥfI7 O\s͂iB*C ΎK6')XG/^ Hru0slp#v )ZW\֨=>',l#BO X[K +RpMCʴXSq9(FVB% O8jᖱ$C-n-'› WZGr {>U]jDz҇UA؏g-tjK-JIXG-i[coϝ4CQRpe\A%5KRFM?%eomFyoɎG_lJP8޺f3VJԻZ46ր9v$ns志ܔi"Vw*۳J+S#uPBH `%Zk֋y2IwDC{*pxvx\ሁD*ps V/vάItQyMliH_^A*${Zc(NFtuc)oځeŨ|ʩ6噞TiS!1-$+$Y 9J!+qJʀc3<9׳ ڕ@uxݍ$iqfRJB)Ds$l_B4[p #! HoJ[oVnNɐfe7+l_\w// <'SE PҝD 6Kh.!PU<@߶)N6Բ]TbN`\Xb[ ҖPRTp1$aJܝ$⛛ojv?qd~H|oMFy ,[n Ddg~ơ [pSh-J)Ӕw;V4Rԅ'QH9'av)Mqyc< ?=o-l&'JAt}{qYE3-Ǐ^%Ιn{YR 셥^vRWAIWڒ7R^(~i!ƛJ;ՏeH^ dsȐ*Kk^bup×m ʺk`I#Rsʷ’qobloCڟ :SE7݃gM8evǿz0 C0{;U9'xIد͊{eb%'<"MˇNOS.jPI@Wz Â\c2#<qKsʷ 4Tٚ+"vqp: ZnzJ *E,)OV`쐮~tйQkiFLucm>Z]?:TiaI}{YeBeW6FMiq.Ful͖}۽twaTXRm:q<9m=pG:iEJ73Mَ.56G’# \- ZuũN_>;*Dr1H!$jMeآN;[jR+NdrGi 念V VxTMhNN1]lUSlY;LҘ g>x=I'r7$RI$H֊r\huNѝSa :mibPH:e<%F`(!Q˓$)T'Mʅֺ]۶)gvvJ 0ҧ^:I r P- )BC a;k #:yޣNp).5cvm ֺfEm!U rL*Ċ)A8'Z∰eT`t1$%gH;QDKg:Պvxq}*i5%+lǾ'B[m(8$Μ torkLAA'zV4Ÿn&:WHR}vJ1w T6 K ֢J<óJ܍BOR)WZH>Dwz:DhHZԅ(sJV*;iRTllCei?b°|+r$~ 0W_SҹR/J5(P2WwֳM:xrC UxG[2om({;]0${ '$xr=~TԮ]@~JwHBju] U)0"* >R ]"`jT-5*^V-49{ϳ|֛݆JCl9 ̄x=5g5Cw[@NeYJ;ӑ|)(=UXԎh-Js7SoW/NKknJU= oO(lRO"r#.[ZRUԀ'%VJyžZlLT >;k7왞57&-ޒB-eŠ i-dGv_Z6 3yR^U:4BHyCenK-7܂|ʲRV'u:HPB/.tU#U%@sVʒ וFGQ;`0Qָ-vr?\&KEV9=>p}W2"RqH܎[㗉a]ӎ%G<9A[I%I#Κ%J.#{W + ڂqGTd3.op@'akWzжX IĻ`Zxs㭗 do翫XQJ^;J T'xۓTXb,ny)9<}K[T8 }Qפ$5ń}zNHՍ&B"IZF7ړcX$UjXZӊp8 ![ lHR'*3JtHu{VD.uBi3Yu5C&TZJ\*^sSQEoҋn"0ZQkx(1YI26>ut.WogcusOR)pZLJ-A Ho 1V1ua1u8_[# AVDiIN̫&u|`U$ڒD$})*ۇj=VL9?1>^f pk&'4dh'Mx3;@v)ˎ6i0}DTISh qt9̴Ĵuǜ-m5ӉeFyqz|JPJv m'(*~ܫ(aSü١vY+kc8S.Pn cٚ\&kj7uj܆GX+#10=^`sr<Z\ٙ;ltFE5ZKv9/,?dФ_r[8 z^R{njQRAFkGY7B7c+7י1α.Voȯ hkΪlQWbƱ. ) Xe:Ld/eY^+u S/S*G+QEQEEPQ@QEQEEP?bzө}sx'&}ޤJL E?m_@WK= \[ Yn%Ϋ0+ݦC,KJmiw5$6Ǻ[Y\kBH*'Tᶘl1!-:?J؏jmO<9rۊ'mđYLtgߕ"^pf eJzIc ?#Q\[ n3V+HfWB*t5$N TGv KK!*R|OW4 mIR;}X;U]-G:֢ ;@VkltH@BT;gi#˕I#GRcyoSod+Q Q8#~do49lifLbg~UHI7I#8"NԀ(?jF}qF(= !j P?kfW<,EK JJ#V9Zꓝ*}.|[6b%}JPZAUL|kR=mӆА>(oqM·ʶV尨6;BV~COev7\Ypmαo-hle ?mꮫC{U K|8tjޱb@\Oi*RF{q8ݻ1%1a*tz*j23:UU|DIA+K $e+Y(Q*2g5]zݜ[ӥ밟xg ^ݹX([o8' ]zoDe  gb 8۟x5,iqܺ&lZCh8y{; ?imalʻr~2~<窉CSYRKb+z R?Qr; X[JBY0:ς Xm9cҷW9.\'_^*Jl`UƫIʀ DbwE:wз yr#;(^icvj.8=[vl~̏}r7D<6mŶEvBšqHxՏnXUnZZʊFsԇGg^CPNiH zUXa_ZN2!ZD-JzIE,\KJvi:I}Dryaryf F )ƍUHBDsqڈϯOGs2ddH>^McuQa8Oh` ZN&x֔D ' PP*]WXSIL5 VguU9rEY]Z` _#irҙ,'W؁WJr@} SPIY6?_!81%E:p7N6"Α:,dA_#tj#keHu֥uN(l@~(p&5)n1sq(d~#P+c6E1 @CTI:E ՎU;{ T1R~#[o*vŽ-J v9#9'Y<)nꜶnc#*zBxۚPc@3P!ƂTut`ΰOETFk;QVeYڙ[KyKkB2 81TFD  N6@dphᡑ3/3Յ - /YӜg+ShCe”QZfo[o'ʓS7kH[h ¬i9.f6w%Юm3JT{8$翻m!W2AʊF6ӱ)='Yq%l3mU HJrTA:J&-HV%IN摁ZCR UڑJ!!%-ED?VUFo $ (ϸBBHȚTކ/-M6_?}F(G>xO ɔ)VFͤ'UuĒyqZ\#V qjVkp($̫'[ V!*weIJJ2䥤{ֵX8ZwYVGhS';پj ҌzIieשmwFg'dAI]!,,xM6]eB1qiA<O}]x2R/-4 3S!9HoQޯ⤤!rc^qKFԟ.m|uż!k}OLxB5ui9 {`dhtJĞS❍K%IW5rK*?X IO߻Tw|7qG N}ƔZ8Ȫ #n&ޅEuBPXCIiPGYQ#IŖJ&vA*Wm<J9WfqJ]pmOwA1%QT]IUEIcQ[|>2FHt6C9HRNrqIl,̵K3eaؒ(q$`oITaEi OOlaV R_RFmojR.в5iJ:It-JnL}mҦ׏h#ȌƽPU%AP:2Ķ&b<Du6;8w|wm8I$=܁:BQ6eY\>/n}vy/]H\w0A`q7]((s@˸R(ӍՎ̰A\#܄*C )o.wE_-.Ixc[Sǎ-2JZX"2*91DqPFgi'lT~_q$L!GԖscB'qW˽[=r?F}/y;QYpb}ebNkDYD]ir;Á:g%X<7h"Lم ,$H7 8P@JvQcD99;*!EPQ@QEQEEPQ@T?U]HHSYO|Ni#QRRdW/etG2< NHi+:>o'RP#~uN.ăn1dCZe TspzYC5=1Z3gZCJl1oL̜qrT]Rm:ifyY- VʐN7Ȭw܁*UG"ku9Ժ˺{!yq-O*)9@qt,/(6r.2@JE#`sˇBvXYSԪ] RPSI;#s;Eԃ3״]y4#y=?x..wG>Պ\T9^RFJOF gΤ񐶈kfWaGb"|"}9~LFiK :TK.Q+Xys4ārun% 'QHVXjXTV xsMlHnR_jp$RykZ[m >XϷl [ZJh2Zjmq%kљoZl3(*IOo'6}uy=X{*2 ŔX lC=Vy?gFJ+BTRBHd sW Ϭb"1%HOF$W% 4{iBLy\P '|;tq 4*R/>VP'Ǘ?\-VNNiE$dˏNTPqqwǙ*̩TN*9 _)Rۏ Z6i0)S_B@g0v)*@9p Х)LQJnvՎ3iyi ) ZH`F;'KqÍ\#|J)RBʲRTF;RXIR@VBy!Zr>AN8ʐhQA'.g SZf|y )P_ SJB@tjǼUƽ :}kdu0'KeY)plsUI"8N },{1ۖYlYQ;.0˪FRUI\y|?đ`[/r#DI[l(lRsGT7QE:mQ^;J ; |%Ei$-a9j Pg8Պڷ:8g*9&$)7d}Ⴣߖ|6H9J‰ +3m=V:۽[Wc6IdYr8ڇm e(g¢kJb,)\-cOxqJItr(Y5dpԢ9MC8GntbMoe J9NP{Kh)-7PRAw'!Ϫ1k!jV2]}wl  (zRR58Nm4eE Β0F+]7bԍg-y;y% @$$'ǝ$;*BTv"(^&w-HBzCQioՠ|aqrHtflx+ԁ(X5e;v =i}%A4J_Wj:;Wv ]ˑR2P1$ )$탔|Ռ&ؖef;#@pDZ,4$dOΆ@LHeM[e )$wXv2V(*lsΝ">!z0}:PӠ'?sA'6N0qt@LM(?lp ʙ.[z2#VP lx{So(5v*C\/!\G ztg@)Q |sĘ@Z!HV\qAnIk89FJWdnRKBþ>oB}!@Qwma!JaX;!;j:Rr8#9|kb ȷ98͹[SmR< RjؐKsQU-|A!ZKq+{2_i$jtPlk \cNe!ĆItw|[3)JCsNu"Z=:zl8 8  YnaYh7q,V[re)kZRv$Բ(1g[ոυIcrHeKAѷ% UݻxǛz5R%Nv=*=vݓmiyzRxTmtC2R5e3 aܐԐTI#ši'$XY kVsG:ݝWfK Ս|siciIm]aIC r*DxͰ\Ru[t3NlL>0cb[P>/kz3îCOK<4@*xO'(;+EV!EPQ@QEQEEPQ@UU)b%׆.t4\ʖ+t/qPPI4r{5JNrm T$88o6qᲒ=>!q%DvPOTmU  JŬ*)K+ִ~cQԙˉuԎ ӶuK+d:̨g+qlZt3Lp#,|cnZ- "#i.)Ȓ A3- $l04E;kw\ۊ+mI ӃG{K` QW4lfa $;{&sHrSE~D%m:NV}ܾ芄mʳ+|݌w{D[o'ylСKzvrVG3m|!G^Zgȶ۔z/N4esѩz)PVr T|VuiC-`gM#aBdRΥ4#zj)^FyAtM!ZC %9ueW Fpg壆A~5R%RA*e#l㿾%GTg^YS-TsjVX"+~i I:IdN|JIcn}u)%#";#~)HҀB|G-CK6FcF V{뎫!܁},`{CLwi)VBtĦd6]am*Č i{KQSʴDUзMzRC(ԬK=2 f vƤz#p'ciJ3RIsdv,piY8pPǴjJYY ;{0)Zޑ1IQСHkS j+m=%cK-'P8*Ӟ^ʐzCH*; s(P Σ䀂B.3}EEQu.x%A*) >tq5,)^¿f;*4}#.):4&m6)NS ̉o'nМ[Mp@N^-蟍;5K@?_i} VItHJ!G-jG{z81SIP$6y>5:I|7݁]*u=g JF:I=:G Gl;>^qIP VF;*bdKnoFϢ$gP9kc0TpR:Fzw؊sYVjͨk×K\9M\K)#?J6fmnH~Z*tg!<*|IIU9 `餲{is{$zM15>uM7Guk}i*jd+'CZ󝶧m-(B3 퀑H&[]X*ޞ$6>.6࿵媢,b))M{#5:Z({*svSq]pzIXpJ@)[++Fr*As7ᎥBvZ$1R S|:Zer88fº Z[)oJTҴr@M՗= zE;u€ (y1Zypd)xyN0M0sHpJp\! |-Ua RN;s?^1CCsjH#+#X./M JSzlmi+2wB~=0*[t>Ak89=P=Ʀ^P[#QᶚHq.(N34yu [n î"==JʛI'}4Jr?HC# =󚲔TE:.@mxH9ܞa?%ou="-YNROIsTi$'r+[PSpIgkzX{faai-@ H]?R¤\uة:\'ۍ'>uCHHGoĜqqS}KA|v*ba dxsU ;I8ttyu1e:J@ _4Yxv4y.HK-e#NyV-z⩷x,-dhPm B{@Hjs)$c+$D;erX j&y߬YI۶qaE쬠+Olgqʆ޳Ȓ뭶T“?%fF8< }-`g z)yc*NcmR;1`$7NM):uH<H(2S:8i}OՑd3pW]WM{ih| skԦOP+Y(( (((()dxa- BR2TwWd57nku0o*[ŦQ ws̞]SRGkNSr/K- IP]Pϊ NvqJJZ)#%9 ?icsS 8:3!Gs3}f -#!!HJ҉ײgD9֘+wLI#Z)YR2}{}I~jTc!Cgq5pvBkC1Gַ|iJ@&y6Wp: a uMdN3̎>gx 8&ޅ()MY$s^is̻)ۤHzKHyOi#`1*,Ҁ fZM)7liCMp3K1QZN0@S:1]sV9!О%MDcc9`zvٮ9.j ,З>6M p-.,m#},CaD:^#V2||:^frV8)%!zoKo!99{5lcѕ†U-?C|-|%mlFBTts#>FZZB) F=쑓0kJEcI=f)꺙&GdJFO}B<6y*NTo6|Am~Ic" .\Hg;ޝ-[ِބ~KNs:>VrĂX=ۚȡm[:J[gnv*{ܚ|K !%2 B3d*ޟNmm:OغáO*ɳ-3!mËQ+ZFr=8ٷb4gߺz7+^SVR4ΜgEr} aqϒOK(uN2 $ÿ13e&cTFWaYNc)WVSrD@BVZ ֔ 5lȵS -o/r'YܙFbDRRwApF|+_1.˸^1p"0!*Q+$r ['ʜ祽;0xM!CCudjw-"Di$J@pyY rt|nmCO2C[~\=ώ\ڵ$ nÈI2))XZRI۳jU2zRL™BKjoVrzrR<,-%0IJHQ ؟b5~l WR5z}RxHfu%S k G O5dnrp9q&tG+`IƤOSy.#6P6>&5eSR3k#1&FTWZJjOA-)^ۇJqN򧞺dh$>1;{pıYXn#kpIGoJ? ؄[(Ь`g/P' :]w%5oB|XWo<2ԶN.M2f[jynPYiN6ΟWǩ/)vHP9T aGq(Pt=nl[-=HQVF(;FXglJ3ήQEtQEEPQ@QEQEEPwAS6vx%+RC H!HW^WJ:ꔌɮ414eX|+38q$X,76@$qQ {Oh6#|~Uc, )Rʊ<1I\(J^.lyz3n.Z5[Xy.N풤K*Q'7ڕ3 (TH՜w 41Mt~VJބ.7):g;vSOW$.,#K#%'#MK’X=_%UﳴJH4}E\-GOž"\%C{I:RQ$r{Ý+@Խ2cKIYF7 ߟǕR1 Kj%OU'4#i,pS֊xEYʌ&gSD鏈zKkuʾdsqw(!\PmzR&>$$#BYNMs'^%mM) h$5H?95}iJZ^)sBJoso]SK,:l4HK?2R!hĝX6"h\`O`)@"*r D`Je'%P߼vƭ㖚u[f*PO(TBV u($oy黲2xEǔF#9ׇխ: AR1U05 %LL(9Ih#c`#^YfV$%?cRBV5` 'YaVz,T?-c:Y8~~0Qڙ>S+Cl}{qo0L5*]߶i~`xl7=,EԞƒ>V_8}B0DGw@œ iA9:!6¬ZJR &u\TdK.%jF;ϺmuW-m)g}6C\ 9Ν-+Wi9X8S&T.$8K-PxeIRK!N;}.ۛ @˖}cC+jB$+J|6r IRTi Zr{ׄd ޢ݂mSqwJRcbJ_χ,XdEm(ԩ{pY{g^{ԥ IKѐ08KnX$QB-G9aE qaGWBduIۖ zB XS8ucpjkK3 ̔Śԗ$2[r|ybể6c˪q;@xڤhx#;%Y1js'/!qē8cu %]Q4ҒV'p< 8t[q2>*@45 $X]#/CSSBΠ> 5Mќ~B }l• gsv҄KA8U+:w"9#νR UDPյ2S98w%6*ck2Ю>Czbً{9 "9aCqLǒ^\SE=XI*1^$oߚBTR0{bcc>jT1BUv\n,a:JGNr)Lm>O4JkZ"8hBOp sܚ +Ķ0d{+yu'!fcAף-[sJ^qie_>{՗=H6ykq@H'2{;uX5"ۅtⴧgU NR=EMJ4ۧ(NNN7>:IDž aЄg]lTtuFs+ νxj}n ADi7 T'vhM՞T؏u]<]\7!?%ZPF 'v慎!Dw0WMR%!YlSlvRn칎%I<yƲSkK6cB HTVlM2#U%T֥)ePFt{$9/HY iTx5fr綄<%l 9:,ՍXqzVYI(!Pir#) KH{j.SJ4yƤ#Poe6d]^^q_%H@QEi4kH'Pq]Foa?Vn9^, 8%!XRN@oHj6 @$g~yKkR@)Pkgr\U+ͩ [nc~yŐf`7նT6;9zB2N@$NpDՑeKO& iʴ?4Uzco+8N~"v!ō)#d WmR:nWi\u->¤8lof>SI#:i=nq %#Ւ=›l*%N={rd8.'#VϴTn6\"6[%;iǿPo ;.]BI#q9p@'aXȕ¤jk$vA獿ƭw}N?hb"r굴 QOǾ.!nԧ%#J(lwSH~[p[eQ)J;N : I)RT矪l]ά ]փ6’bfZ[CeKIΓsS+Bc5gaM- ġvaI<| ]l=ma.]|)?ж['um Y)IA#|6tBRJ/ Hi1+#祍z|rg42TR @d⟞ס:#ۊNPqE )u$z䮋[\eyaG>ҤJJ#!ƥuli(`AbAyw)hC6$dj='x9Q瓱y6+V$diX҇㤴BmHyւ 8s^Gc&l3gz%qCvA>\P+2cE76%- <(+oPԃ{{'XSMkQ?Vӓ̈YΧ.mU[lmVɞv62Tw-7)m{$V;pk|_&#d|w GU5-˨Xƒ,}Evoq[օv9F:~֔1I'q2=iTOFz*=sLהcBAli*% X<Ǎ?Ɋی/>{7}䥷N?W,|Y $Ҁ?%&LqDuJH䰯5#x˛w@ֽZSpj,R d kl^6U\5֤ v2yT¸5o!`G8aGݯV&"*#N앸 :!\PCPG2N6W=q%ؖJ$+=Ě1b]lV S o9An9S O<_xRw{m3v.<@CJ5p6PKեf6Ůi¿H9$9$w[mZRW)UjVHmC׭N$zo!L\JC9{FMB;jASe:[UՂJ<*r]w#'VSjG%TI<Х ʌӟ](H#ʘ0(G rS.ø:8kC*RMrɃkř5,:Iְ߿;WLK|T|1kkV8:zqcu؟Q;j |9zx%Crd>Y]R#ͷ"9rLqw%7!SN[:\LuHpgle#~Ja<[& Unli Ox5I8*qI6L) e*BNMnR!]z~6=ƫ4^ Rp1wdEiVbyɫ3KD닧ŇE.' y <ꟸ!.y`#gRˎHI`n@(1؈Ұx!*Z'úGk6!#i.׉lVo^]銥FOb:('l.NA$[hyYTؔ= x8JXHy^Rw]^;(IvZr ɁNJӕd-Tv\X$O.DrE(_XK'$9[sMyRU#fJ7>% o,aCcs羵CrGڐH|$94bWF([/"*[х;SoFFw皴yu%952,2iPVcνL&̸9+32]X%)NIn&rK*XlAq/jJyMp ԲU$VY-%F iVgmƒvP\ر--%{(矟:w#hJAN*H<)֜@ _p֕Pt:0I>>z^pv19 ~|Ss3ŵ!?YӅe9}?Pjz)2+rCIygqLHiݐc7w#z9mqϾJaGX\4yc R|{LW^Oe $NyShܭӕR7O0x֥2@NNϝJ"Z &CQ lcGg7m(lmݴ܉!hRJr2>(U% -eZGK܂5hMe B&m=G@`%(m*=Dڞ~CmÅ =Ϗ[\Bf ~RiԤNBv|+n8S*P(aI Y|Ȯץ*OgF4[ٷrBLTC,n04n`W\ RIХ9@p]g8s0eZ҇=lX+x'rCL. TC+|Z Ռbqmc}MwUz'~^ia*ΜmR+3Z8-iP[+ 6ՑyC6_WO%H 'Gy#Qep&TXO:Ӄ+*׌Fr5ftlm=ڒcl 9Wԩ'$ocRSIhu:!^5סBof#ZK:e8rRI#ll)h opԜoBP1 d$n2Gp\TfӬ0P3m];r,ͶO"IT90jAы*OH5CkX|t˾#^yt$H c{bpFNyua%ZqyxUr5H A(Z{UH:6k)R;P0-zqHVwklY2e];|r ]E;F'tѴ ָZ Zua$9}c(-.g`|F:pOݸ[(m=K5H#P`9EAѨ]{.)2y  )RHrsxIT\x,qI=|Mp2Tw⭾ .i1ږV|bR ˉ8)7 K:w-'Uw?/e]^`jڬEav=QmXKN}^nz9)$3ʲR܌(jQ8>!WkRFyρ4dsm{%'R9 lv$:[yGaX2;o7N4%JuNSY&miO84HRmH#- 5}ۜ K. ,y=ZK{xL=XVaW ޿])\MJZs_I-薋LKTHl9% H{q}«TvH|Z)_Wk;HF>Y]M6PqRO²wM)en JzAbq>`ar}IIq1MQY\^0A't<.CϤ!IW LB$ %ogV\pjD!I'5\֌[]DbJdBe_$JyHR5 ;{Y p[pkt>CLQ21O1ZzC)8S>+dd,L-xb+!M~\z!:lHԟyB\e!v"wכc%`sc;SZM\w钣ʐF>/,:^+(x!oypk{e )8'RT0jTN6\(q% + RW񓓾KSL*enuZ9m06uF5^Fț)' {&p?϶Žcs/Z6띺,iiRu0u6!{Wv2qM|WflK>9|oª$[Y唫2ieH8Lʃ 䤫#ڪ^pϔV]QgƶZxS\(Hm+Nq*q-?!YWn83&eAM2PD/1z!㌸g}YݓeM47bQqdzoHIX}`~ZԲH$y&.R@.@:Q+,=?Hh և8[pw>;HWk߃b0 943>,qtY}Œ|FW2AzO =k{릫]^EU((( ((( l:V8p*T+2qw=ٟT]cy3XRRB _ ޮ.SVFqiҕ(Վ*?X1w4ЄdĶ\&FI#ΙoӦaO2!OAHƒݩOPm@PGp;A[]jۺ-!  e "6ޫjw".Fsd!j 9tw0KZ6**\1YhHa`Xywթ7ln?hkT+BҬ; STc82Rp޻4%ߞQcjp7予-4jV3F9s>5tDKQӸ lZH?%W5sC6c͖(qI ~ݚCQ7^;=tv\իS(Ge`r^A#9%-ʂZT|: V]$⢉x.?viBH8Ӆ y>hcQJR3wccyRUDFnGh8BHek-_}Md)m]yd}5e%pKhup60N}D~GȌHjQt# m+RT~.ϨQ\'@ o*`N=j;~)Jdm7|Ү}[_tkQˤB1u ;k :!)F\F98<oUO涥aihN29bsH{xWwaÌ0HNQm"eK ZnP$(۵jeN%/)h62OkDc cg ףwfxj]c5.ripIe{uk m,ӅZPX $ǐ~TU47{hzxWI j aW7eA*XARSlrߘ'BIPw:IqbE-NeeqK=v*m9F|F7sMwDdͰ Ԕ6] ϾIIERXU+)E_B&l},sVP dr|xfZvK-FJT=16.B]]T1FޭSt5i4Y+QIj𫫻-})_][F&{ќ΂~]0R@+`E ګ8ln' h]dcEb A |.GO:9V3Al8TK$g#BۑxURnnW l|&A^Il+*by{)(BT l>(|*Ӆ"4HY Ճ)S),±\фn01"IOcMY4rh^BrSw|rA7c9'ĦKx`cʱ l{뮄ܥ>僁cZ\ZO\0}8}i*TrpESbJҔܮ(hJhb G%J}*J˘9,99eZFN4ؐ540;Ý,oF>cK;Sgq'T1,M)I+X 6|4(D+{hANqe k%'N>Ji899䨨kn!Ph'.T wGI&Zuv53ZJ.O5_^ZcnHI 1[}((Sq",N<Jv4,ӰCuԕ{ )+*^h (EPQ@QEQEEPQ@VTaތl(lF~ڹJƒKSh[iH;N;?T9#BA0\v ǰ4 [ixft.: [#D`QV'a_2}-S=}&Ztq.`+ ⠜`̋zڳ"Eq,Y`lq qrJH )pm(ucu d c`dJvd*!!-jQNCe'22|kFВz;J̗ 4%]O[F8O`3Qc ;?gfX†A'p0mZm,Ng'SH)Aʰ3O ϸEuZhHԽ,oCb6Nj*bڲKvE՘QdŎGK !G$'n:r֍LӨR2( c`8gخ1v߳N{S>y r dw3\PCwy^0Thyլ) Βg; ͨj :]PNNtr$zMIf1f`u_aC8NwۻWx*-Bd>eIS+uo#Q$)µy`HJBʒXm::20ߞ[lq'CO N:Y)\YRP+t, r`"C!2LvKKO*"2f3N) 8@.w*t-]\! JZ ^ppV |ۗ!iT83S 5^\xM il9}P :@Pq}6Ah<慺INAJH@ g },8 ˋ)RvɨĆY|1\RɭN[WR| ?=pv38]fu$$- xw88۾N&<8PKzѯJFV[2RkxKMVFg;eN{G>U%<6A; #>*ܭ$m߸Ϸ4w4DI}2 ݐ1k}_6RbuPTt-!j> NN:TSU$B #QI}19Bd!^|vFWKV9Oχ24 g8T*\[s̯KLuknF1ȥC3`^PiP#v"dmH(q|] eΟ&[%xٜg˕y|\e9)=c+' r6:; d-p԰BCkKm*q+o\lVטu.μ[qA$Pb]=pU2ǐC }Zqぞ_]K`"J ?֧Mӧ\ȿ_#$pD)Sm$ dripP Tg桺{DvsvE_v~@UK-GФw1q|c}NąmmO$;(ϙ]ŰnK*Wn9ӒYE0iJBTvO#rx#2nm6=| I<:J;=$z+J,Eo>rjNyRmC) cBBpfnNO }մnN{VcIxRЍJQz9ӂkO<+q|?! $s>'j+'xy[t g)t`ګ'~)trrR]ҿ_;ؗBVs#L7;,xצˑ rq԰\iPVkYՓS*;q C&ܥFbRc<:/pg :|g9S C)Ā@O/asNJl6}eXqM*⤨%x4a;㾴+#<1`:鏨ϣy3 u" =HgRR '~>ebn.eضB9K|Rߟ3ݶТƷf&i 9RS5JY;RW+s,5'vy]a(_"sprX9'E$ iߧZh_r")H |NVwD>LŕڜNI*u: TNu4˹X?5k}Ґr^ꤹL Q VOHPI(Q7Jֺ2`β?A"Cnh>UZlZ+^?hJʜ %#$ߊ!ae*Q>u)X!kXlV" t+k=Pް. wR$>)p$HVIX;%޵T_.;dxuiV՘rVsKV.9!{r; H $/r•yZj|v\5!釒F qJ oS`sZ@)8 ɥV@ l.{jT-ED'9ʱYZv@ o]XI{a#crdʜHHN3gԕ&2Ca,'o|nuiRy![):RvCcNpEd˒3%Ԃ0Ϯ8YS뚺W$Hя;k>'䯦+*%R?@sk-QSEPQ@QEQEEPQ@VTjM`}s />ha>Hں/QGE,'^%tW,5!!}cc}݀k.IIӽ'w"0`- ) ,dӸP R#8 >X֩dgIPO}9".BJ o$gKܷ.Q8LHScb}֐Zt6Icm4hrIH#XO n(#߿zDq3mS ()دvA۟U$Ͽ"jL@ RB@;bYLѠg! g9;|jA}~oė|[lDJHlEy'7K!:vQI=v)_R!ו'Jtځ}9)tʛpˊmj_uHm!zd'+VTXVXOv9;2[kw|G5'kwe!!Nu(!Jq`lFO >ΈdKc,R͉1#R=hwg陭d)3[fRe@ߖTd7 S$2&ry,ZuIVT;M= ˆ(BYQ#Yps!D_qy9R<WjO]8.[x9ɯtijpT6>99Ti廊!C͒֙RVKZ)J@G%1des_QE%ݷv:%(u\G'婿CII>s5@zѷ=@ٗ It i8 @jt}%XSE"s$"{Y 滬g>5lk8Fj[ E8_L7sGdH#>yΩ4NxOqk*W_'ؘ0< @UU''}oN^lu^+FvN⭏YΓCVFXjME6#8>v<:@ >N|OhBU3y)K6巕hSeĐ H$c)埐-r$cVfxt!dˏM:0V|=a"tY@JTwx:>wRו~FziR$q-dRsR>5z3-sʚII3J.qsT'|hYJdI쑐|iDW֣ʳl̆Tqg>I\>dWrU iJtM9i$VgפF#eqąI ZJIʁ?Rȼp#ғ=V pFJGdErh}Oi 0+ .L bpя"*T{gZeiTȊP dRNG]SC$# Je2\mi Jr" itmP<-t|bWp>ʽb3-G ·PsYCO$|BպP?!!j_Q8>V/HRou-H$Rt $hK A+ߐ=N-!U˝=1q% 4ڇ$~+ J[)>SGu5 ?H16R"E4:5-@2G[=VH EgK.2?BPU$:ϑǾuJ ~DrBj8#HKe'|җ6wMd܇rKxJq\F6T‹ԲG4ҹ%d[QI*mk:\z5k8y p:ğǮZ@!O$Esi.^$d?Z( dX>%6ϸ՝qձanڊ\X{E JRm':եGܭA I4sVL]s+&ZJQQ's?8ͮ"܊W39n *@((( ((( HWDB F\iዅ ybChu:Œp]gA%pRap kܚg8^ې 6幬fhЭ-0וNAW'Ri76(G#A#󮎰'lVI'S$R 1(,(HG*d|"`IB4n'K$r۟y5%qW9m=,G!BvXMo\:T|z󧫌{#ԾK/%*Jqu kE{_Ӏ⥡)>QvD∳7&4bR㴤WywbJڔui*R8mDWF-Qn!c<Ƭ3D 6WX!Xlw)>AVE@]k jRFEC KAX vH^uyM )ꔂ1b9\NT5ƏIziR;H.c; T]),X=ƆS[WՄw؝OZ,;>+ "2UFf -v@9$ K\fΊ[Z-Sksr :sd3r8׹*48KQ,@hlRO-U" D铤N$ lwӋP`JJ$r؈:˗&/ë) ~3H Y??^)$vy4˘i ܉`'!*m-Bҥ' 0*2g*ˀzKδY$^}I3"B׎m}#!zR@$( d 2jIn\EĖup*JRg9־v OUњlgHFyD|:<.JMK7oƜpNIm!\6w7ã7oQ%>Rp*I-'qʧ华W۔4ym4AhVHʱs2`gj0nJAX)ZTxgfj.lKuZWYNr<Ϯ] y5%hmE-9Պ8>G3+[> vzlÍzr2 ^yaDr% CkP9w8'L6C0sԝ'T#NGvrW QDu h,%m dl'ڸИXȚ\8Y%kϺ ¹tCk?ЋUxzoKqw.# ˭%*ʏI:CMW$ZW jD;lT$hm߸ύ]!a6"~25Y<;{*{I Z&UoUЙ˘@6iKAVpvf,w&n%Fk&9#4厦+eZ\ #V^ڞJu03|i(^BmS@D/jl .=HNH`=54vWoybcF.YdiHYjNne{ YI5 ~^m8%pG܅nV@0"Ok줓FwR>T$; =\ziiY9CXVwӛ(%"Ro:>ʒCCΡQo K#j#ՍωaO-m5R בYp(gIrﭱ"R\IO<9x Z}P~3Bl!AD>GM!L`u4ҵ' HuDI5}{>+f>[@I ;۠'Vq-_ʢ@^%jsЋ} RS%ZIlw;mn0D>O49**p3I'3\[grF~.3rh@[p6)-~FuD@IEn C+ ysM2.4{,9X+FnV?G(xv 1꿽/Z[V]ۿϕoz,i?p}9+!Jb{9%mQu}|QN9r]J86ZZ;Ii{+Ho Tjjb v;3M7u/Y GR+%tk*at{E[_Lr4>U m$*qpT'8.n:;绕*j #2P#a^ɶՈnl6Ҳ>LPᩨ)RS쥐h:$H)94< ?D'O/)ISĔr>ZS `!aNC~~Ro/K,ʁ?~4%)Xr)#hl5\nOq79Ne(GL2i1‰#͚b40VX|=[+ u#! 'n[|y)+a'r=蒕C|@lŋgWtdiQ[o)|JqɅq IܛqCATԯjv$QEHQ@QEQEEPQ@QESV*(b/4~S\m*v'Z8]iV2-&-,"uZ[֢A# J%spG2`J9oZiҕ =N! ))5wIRp oӥVgB"HÀour5m;Rȋ/t=H*BI|[Ed%bkpAZִ8;:Zk;IE )99ReoƵHoCiYECKF*Oj'( =թiY&-z퀜##xlDž) fR58]: H6+\YE)ZiUѱRʷɤ;ynScIl6iIo)5ȫlnR O!2[C>hХ:w;d_-rJ}6vW=V4v>8՞܋]!}%4n:23d>aJq iX5D?HQ%>)8N2<|;^ێ*;%m,aH=>ڄ}C H4ж R*usQ# @1RC\SgsZTB ޛ5n9rCA*xZNElP02jn>@QOgd!ĸI $a@xmPxhP?lIi$hR# }~"NY?Y\WӭE&A5h5uklʐڊG-:ږ#BaEW.sIKiXMW4iE[oɊ #"tR1}fp%023Jg[OLW{Bt\w:d4O4`H+Zءnnmj,(gE$dX>z^#R&D Ih;#!^`xVsCnj ;_zz<+Z*?v( xQ!XuuEޱ=X8*aQt5!\ o*qt5!YNխ+siac>p;9 LP&E6H_/UӧjL&}hۙLȪp!O?D5%zt5A)TqDTG("F4l/m+r+[^6NsEdX"CZNB*En+Z”#6TiW9dN2Br|č`Տ҆aSF5~YxPqUʽF솘V` ڊ&bCcQXeΜzX{8BKKi2O:RnoSv`3$ $^"WppnDC<Ӡ,cO)j/v4\w>̞;,6zmߑZ <e9B^J zrUǾM!.:p AՌx{GSS*k\RJڀ)L{lZ޼[ztf׫F )>_OCi.-J^A8SR9mjV(\D㞑$j.ETWΟj4 aA 1p=w˅d-5 6礓uƟ3,k-Fӡds]e \q=B뺫4X.S}b*#Y՞CszZG*EUB( (((( (>)}BJ-KaC6O*꿪@$f_3\1ޞe |N客:Po9yna~N>JPYpuXՅ ;./S6@JVȔԗJKIB)ڴ&^66JےsÐO*?zĨ =62\ e * Y ;ηȰ\I-FI}c*#rx/]ZœS8 Ҕ`rN㑏*],gR|Fe+@)g5cJŖH?Q+e#ߝtk[qЂRPu+?'~1I p[זz3;j]3:OkRӬM9.`BLJVtM?h' ,wUQwbj7vBG5*W\]e[q7H|1V ! ‡4毩JTdFJR^ zd Fy6PPs9#qT䄸iJUI[{Zq[N֕Ct$f)NjW#mL_' ${\ؐ8Ҁu8;''`s]NF|sQE}%98YLZb Vh8UaBe2d#SiJsr48⒮˴?—pVVc<[*Q[>X k!NzeIs%ML.HB~*R3񻻱}ST6~JPK{֢(ԛ{m1kd)Mj7 "v--j*Ny %hKJgEpӍlũK!RI p%jm,'I9^XʊCOh!i 씩=RpI?Vڧ !mjB$wy2lCۜdjNVS+i:] SmQ!H:9BW$$)?VzĎ 7J8x$㍨$LWVi IBjJN660Jb+zl]Պ <4|篒HYi<`K=mcM8)TJ#SG diCNp/0]fBXPp}^-mpqUTL^fGo\Y-' I⨯p,-զ ʒU:o%rR^(#lAԧl+*QcsW  Z!h,@N|jNhCͫe$p Z K4D!f F~׬BJv` ӞP[GXQK|Ԛ7 SRnjBxȧ,ٮz'~emJe/ Pr*QN}B-*(CVcsUpF)!sYb[[uOtK$]i S ƛ:2ޡ\`)k⃊ `c33hO[Ե%Ydޫ ha@קp^(D{wUl5Rl G^V(6R5ĵlA A*Nݻ,7#amBq cUE/8vTbl0Gq;URh䘑𒄰zzBƯ<{#¨[F$T~[5%MC,Q[liح`Bv  SZQBC2x8-0XI)NDc8{k=:կKObϱpa"lW)U$cmrjL?Cu>2S;-D**/Dq`gƕ:ؖ\ɒhkB)NW`wxwZm3f?UɈ+=K3fn5(Ϋ>'̂.o +  6}Jv8Yp{B*mTcw{rlG<~hdL7eʓ֬Jp qRBmHy`r*.q#4) # cߊRi:tKXnQ.FJwa& *+dg$oM.*U(yQ |Ckoa%$Yսo=?oķkB Nq yǢҕzߌrU[GL*ҡ޿}mgT³V~CQZVd҅9]ouoCzs$XOjtGI^:䂄l8Ux)jxUI`OY%ē~J$| =gF\vt~Y8d-%#rFsҸ6&JK,[A+!);n<#WUϡK8?b($)?)P; TURʒM!K Z5(U=ԅԴ)C}GApVyZSg8[㴭 qnR.CfշShLc+;RV+EwِRAN+}Mg+N7Zy@wF&hnTu!RUA˶;_JsFp}͓Q+EJZБ՜(CZi#$dVSmHf2FLRyQV_G % #9:FU ԳG>CԴIĦ}u?SŅ62$,( av5l&EUB( (((( (>S L\Cꐐt lq-u_(`drAzDt)::a#>|WJ繊C$2!Jtv@S5BJTpu]I/}h~1OJmrnA ]!p(mp3gN~Tп _SnO":%OoiJӤ(V7u3}e(-!%dۏꭐk_;|.ޜ8 (w ,u8Eғ͔ӗy#Kf*K(嬣I_vڵ(x;W\gHj,%ou!XlMՑ70wmIH{4Yr! % 再eqy3%BOzX-[֧N97 婍>֥$$|[g9׊G ȻJ-XR;d:sZsNpۉ i? V-kʲyVhp)Y;܁["$]{ox dRʒGBlh ˄T~ar<9J ƣ K܎{ȥ֛a)*R 9 YKlt+P!Cls %k9ŁymZ`HOxP'0f̶2du:n**Qږ@~]~rDzX2 8(џj%msfj`u ;sqN8) 00Hǁ?Ay,(FK+Iiӧ9GwRiMZV8sOPRd+D)FJ Ru {[o-Dcƛ-!8 <3Jɪ+MǙI-1ʒIe'K rg%mxSsP "ڿkH%G^)58\ȺCcE%/um~qJ'|(`lLper7( [\uwZTWًԞFxs0 i\m]wɋ7IBqԴ' &1MmuRosyf{R̘2K֊Ӂ>unvߠm)qV5r5tTn L/ڋyw|yUP͖R$#) ljCÎO0]yVHVZ9H8(u܁8%Q[8HKuӀ :z\Ooa+4o75džo BbTkud Ӥϥwȓ+udj:R [{4PA;'BR>7!4WmdqR-/THV nI8:KS "ZvfT׆c6v! Htd7ԍqzIQ{uIoj0Rc,1({8~cvvY!ˉ'$pVO^z/ pLQ&Qԉ.8%aG 1Uׅ,hmFzCB(#r{HV"v̂IJl{TlLh͝-oy2;N ds\Vz9Yt v]XIlu%e]rrUC0q<߭9 ꒴n RR:RcQ =|JCgPGuC nCkؐ9UrL]"2xcn)ZJ@P4A{8hJ0k`ڔt"%.)+#՚g5/l)@bT>/7e}:жz;0l1S*\DXi9Iy#%@[(4Tڐځvvmt{3na캤_a^2v/fORlJԌ`z{V88ܦ2߮[$ŒCD V@eJ)QlM%|ܖR(᭵B3<(J0y}UBXQ:HuOtQou(|`BЧb:rX;Ri@{@Jjrc"4-BV$e'ڜ oUڙBLx4w*ZNBΝ@I H* -KBFiO~B}&#ɮp_w?~B_RwKޠJG]^Op+I(( ((((*|㢉$ L =YX֪i 4TNqT W)O[I´-H}t+ 9)t@P PjTŨ#O<{E^ i)%GVJw~"^ ,u'oސ_)U0Z&>]-'ARR>.|W/hb&L.5c(,u/;aA!$drSCW&2|GJ5JX9⭩\shWվҢݒq^f/NDK8As ,Qrf+Ku+t!a$a[$G#S!ȓ%:RTAyW; )dGd*;yܤ[}#̥eNIPP Xɭ}+Lv(C:]h s'潹K`TY!%CI׏#mʢc,d+@ ͌'+\7<[<)V,CqU[HCj$&cq+ 4RWw\ ۈH92?$yןpd,{>)K  }uag RBT <2n<<ʏ˺(]tvUR<(])pZr#feJJ)ŪԟOp4F2%Ţ+a,eԲA8'*s{leRր5u86h6})anue)c=;viGD5r0P~*Ժ!buDv,ӡ1K̨-<"v&̴EQ*R<Pr|`:E&2QhzQޗ0$m /im{}%Hj5!)Cr{9N䠅F%Q4tFSP!HTbruUQ?-JdѨ.hN>X9l@PTc䏦620 I'b>Y9aBʙi-IJ@Y vDt>.8>E^k\Ċt]a?6j7bRPF`'Vpf,XzTbAUG{[husXXP$a@-8?eQҸ@+ZZ{r<R;rb5)䅶r'}di%{6Lme*'Gq$zE9 !5Z u'I!UGyV;5c_fu$ˊ*Hu^:i3 )`IT@|)sWR=?)?jM=:gR)Qp+3]JöR(XHeH9>_odk7K"ɩ2VukV0}Ɯe5$&8{#;oU[tVՈɒgฅDFA[{}A%*JR Sj㮼ur:S޲;IDL;KIg2^ms<VG,R ؕ(Hm*OZrʥW63' kOLfCmKST'Iޟ!$*ӌjVӤ"2Aۮ6D!_`qKvWm}bKhV2O%Ǻñ .-ع[}YP^^}V͘U(WFw1;%2MV OWQ~7≼Im)IKKP@=܎8犏" l 銐pT2zI5D(A!FO}"PF3s=ĴFu^Dt*H@;gHm=ǤfvKbJt7úVn̙ ultk\\$ Kle@HMdYKeLH,˴VN6ぱE3n2 @qs+W-M7V$()g7doFYBï Ii\y%`$X>Imi̸+Ci$`JR Ht8SoikINNܵcbk4\KM%M1JsB6tBN"ԮC"ڵEIR%8'JP+';{H! d[԰GƢJg=C>ULvΥyfJ+~'K%6pc]%OJBUd~*G!@[iY*Ԭ`wFJޔ )Vc>brX$IY4iJN5n7$:T@2i;6J1C΍ zYJucGwʺ~N:@Hsp1WzxOFF[QZQ@QEQEEPQ@QE[}Q jBkޮPkujQ9|+VJAW+CɔHB1*9!- 2+jg#ӥ%64)!Okh5idږs<<=hl.;(JP3PgO4*P }Ƭ .:Ǣ:EDu|1ԤD*PFR~ @ƋQrqI; h"nl cϷnjZ4$RQ!&IeV;&f"<$*bR )**]|)M VMdED)*-XQNÿS%@E ?9Vypa֧?bxcT]3nR7ܪf(rH6۟&&K剕'|q*v pʮNpͽrRV:Sn+ftd_ 9 Մ_iytfڮ J@[6 ˎilR=N|VF x -I/7#Q;A<Ϻ'5+5 + ?jIlڹN lT[`cO' P)=[R96+uj)$piV4d <2 SFqGHQ{? *"i**eY)!IOM!Pۤ@S aIl$gTw҅p嶱BIxR-ʪW9wBԜʯKr<ؐ`t,㻞ڨ(Ky!BT[vCAZ73Z-FeyիxV] }#lXqM 6x~De)MfTNqHUm3I:ReKcؘ-8hRS_8~[,WЙ’N Jno%C8%RzJJrA)\JĄz4 #H /bV n% eZtr<27  s8X7#\u|vFKiԕ +5=H4N4ܠ!+* *9o)a'IqAVo2N&J.:6Y)22Qb9\&沮` uj8#MpJPHlJϳ)Zu Z4j9d"8ʱW)oZN´)kyO-L'$g`e`MĀ>zg]ZbݎDuP8CG"i:hm|?ƭd2ZƄGFOg^9;(嫉TJ$c+B ەxJ\P8!@皶 겜s- e$S٢kˡVtD8rTUN|bNϾ*-T7RQA!;~R6JTE{`dBTbq6[NU"$]Jm'J%'e ߻=ۇљ,e IY$Gm!@cx;2\eGVt GgUY߂$,uaI䑫qlZf:dnNF@5v2ርKplHl$ tzmh}׀<7}8J*c/(I x- "']3F *r$(-jxZ X 4X>9TĄ%)Ҝ#Uk7kxCA9=VC8*>t2w)x(v>C\ R@r]gR,FQZoPH%D~T| mQiŅvRGdVkN<}gWi[Ewi'!QZ֦J翫4qJI-d;du5$g CAjD9OZKr⧠qNR$o3H`[E(uX =vVBd[~(kRܳ^6*d { amc-4 Ĕ,p;<H`wsĭHk8 ) $ƨBeDsVw(Ի &ܤeM(ّP{\m*’ҎP8>U,=C#I#fO^=T*#)ROH0@HV#zKtv5a-î* o ̷)*XoN|`|+;IRUd$2ku'L]k1'x@v^Y$;F2u)J=%:F=`BxVF;+dcqCWCz!;U$}h@sI><6d@4ȯRֽlヽfXN3nIjPRr'|85(d5hPRKZ4g 9;$]RUէPlxfOk 32KWq{Ẽǁ)R֍m%k)XNXӨq]l”JAHR^PN~7RQe;zo $ uZ|!9Ђ^uBMpF QgZ՚^5gt/vtYX#V+5RJT2h9Oy#ºvG'ޫ֨H't4Dn8[c >@kZT\ہlH?lumW6S}b$Y{>[d%ZV 55 -Qiiqv| J2=6'S l DnFQĭ,$+s~Jpۅ5[α */$vӂgI>*t.u (2|氕B]l,ǘsm$Dg<U >8bLԶF{J75+[\oHiS㺭)mK"%c}cݣ ÔSaՅ|{\#Sw:PƔ%SkwcV݉[4΀iA#2q }SxFJ*2Uwk̨-5<2@. ]6 P $a#rO }t±V"p48dZ5"O qBju4Rp ( JQ88 8Rnux[p807wGq6G^I/}$Jdže":áXk  ;wu:v=Jq ʴ%!QIH kc4H\n̺|aԡr,s9V 8 m+HP -;ɜd5U1IDRtZB}$Ӌi,(t`{VfB҂ -v$ԕ9Gc^FmXZ]O: t[HbBRRi"6Qot;>gu 9 /Un7 s!TR:48ǸIaYC{TGK$uIi[)(R)ԌcVgOFz -X%AU*BXX^IMo%! JHÜR$iJ$Φfɴ.u23>i=yTfdmI\BMowm-~N8\~à$aX#wԢCgtFP/sDžjH氐;i.|-vld*u[ u|xR$ͽG: Z1̥Jd`ꬆxc$n4V d8)2 $dh TJ1)B=j`qU˳*I$ h*Ե|E[Gu,g5RA p;|I53yL7ѓ{fGXW±K^.]j#'2HWkd s|eꭩ jJyTn7ȶ1'%cRAg,,Ĥ6x )#J P;3$ KIIH>XfZq**ǮӜ䒟Wpd$BIg{GeEY1uZWdy֠%< !`}@ysX8 ,WbdD0=`FO<fPQry ) ۑ8'ZChWh{wԻ*bnC'9'VRa!I9?u(Sg@W#/ʨ%NY5D 7sԁvuGxL14'Ս>ݲk%o=BF H>JJA)P^N5wdmY |O[`\OB앍`)3j܂^EQAš !c{+<6ڂ{e$iS)R0[RIZÏ&6B54grtiweq*u!ox%r*z8%V %>sqT\[8Es K)RLj;r6oTQ)-h+'ϗ-QYqLR:Nr\QpfMCVۍ+c{F#U%e!JRpH#&$(+q^,jJHr7* Ius~ :~y<ۑܚξ)vBP[bX mrPIdwUVSO*x{YŒN*gA]yI>#*5usˌ; \aKkFw۵ȍ񱨽6n\.ZmXK׌ddjA㊓S+~U ӣcǭ⮐1֏=0MnA-@mrӹweC@2ԘJ47#89vΫ 3%&~DR4΍E lEVEHa G} چys6?<z-xwxv4SO$NFUWfj)QY=M DM4Rqp%Ώ[ws92:  wۑ27]zЦI8օ^OfO>&6!K?x'oī}k{PJQQ3Lt$%%C}>;ĦVњnnm:5c8u/ԫ;%nӪōJ@'R5Ns-,HR{JxI:BA+H-'0~X+B?be! yRy^U Ow $^z ?ܑEAqVw:)xeKKhRuҖZ@RSH$+~[Uj^j<_fu5c~}(_#T+#V>,~( ǁiMĶ%Rf6Aj?{L$U)7%$(`oΦʶ*ϣ3paV?bX{Nw)∌P?Ij7.| :SrR31@*bPK5ZamȪXtxU ߏஆT8@WN8'qT$V >g79tN}-nP+%Ĉl6F?h+ gp/ SC'qHulAØ]?rKBEdi)ee>-N< \W+o3ZP ǫd%lWio #Po5 )J} dR%!JI$o˝t-N2y<. o"|Gb9~M!D-8^Z"=z\[Syr5moID1?[ a: -?6$)XIyTP3ui,\KA+Q) XHs$}BFqGQxEnG(Az#^k'(#Opm3M!2mCq5%R6[ФlZ(I,s޺Ci%ˆ)gĘ[jAۤwӵG u#6DBG5 `# #(KWĽuyW0)TH nGQXH# Ry  4\ 2S# +=AYo*zg1{9 [75**Ju+ݽix4:Rt'גyFR|A}<)sMJHnkAIk +՚[AX!ƏiH?VB?AcoGռ󍎠qZRJ q#1A9IqKx(o *Zޛ#@l0{)2H@H.|OJ-Rd! qilvd 8m1rLV,›ZkZ\C S9S%n:TAclKWrRmiғ2GrnWXZpВج% `THrhj_c-? 贲5!IvSV5Ѡme#n~J5m&XMbEweMf.jjy qFB:1G2N=ygq좈 83uGv\)-ާM[$b[I60~*fD0FQ=GYkpSvzyʴ35bMם1?O[wfl'v4iy8Q ;wt0O\f1#{(ue%ȷJ&G9?Mbհ'>.{sU^8ܒF:;,qd" Kܜ*'8]:^+qKJ sMwNj\ex(TEZV Sz^}Z<(PFu$+#$Y#whA{cJkGkxw3&¦\$)' `qO:D[%Mm\n1@qрTz8!Υ 5y]2t,y?MkU5jWlLāCgK#p'p|Mlt68I.p6@p8˩ƑCǨmoBKS1Taۑ܂Ǿ7i-s32-+9kIʻR z`h/g/)63ޏi>h$;W O X"V`Hqʣ1%' ?̍A۟ޏ%qBb6$b X#g']8 qF+JPTJ R) NVXw/UʥGP[y7aگpʁT$Erڹˊ\!:ZH-RJ9(rջz"kCR_ ZP SddOJR퓐 JB@"ujc+sxmżԐۮ`߿qYYV3S'%L*À] )ߩ>Ib$! e:>}rg`=!n K5%eRs\Tz8dLϵ_i&#+R #Tf(Y2m"BzqgKF1|ߜ5:!_SWoU,kWLwK? "4iVQ#t|FӁ$"rK@]MX ! aXMwW]/w! 8MƓ58yBIV7'NK'Zzվ[Բ􂄜d`nk%h3c0rF_$QzPv+h>*64$$ϨT _nQ"8җm 26Ϟj;[X:M4]q #*RĚ(Am}lo̐-2yȚlmNw[.8Rɥڙz3rP-I> 38/ %jIz;'brۚ)ƄBF!1e237ߞFƬKqmXHk[@PR BN++#zl yWnk &;=tcNqV=fذhK*O`X/qRP},ylq%Y^-m6nGVR[1iuɫ R{*mwRovGecUSօ)Üzt%,&[ 2}m[(FKB7J2UG2_RGYHUĉfjy W]%RQu7*Srܱ"!rN\q*ղT>4>zƆ_LąV*Ŷӭ*N2X jS #u>:wEE2HBM:BG4z3дC|4 >LI qH,Xfµ;wuZRA%Y2{Dܹ=!|Q$6<2w84ubDK@&cl(0Q9*;}JG!ƵI^$eÑJ#UTenBkRXF0?j<~KZ]m+o[( X'dgljy$7)%Ipe8r*MKjN H߲[<䮼bBCJ=Ǻ)F[-1֡[m\xkN֣}0KoS%)}#cT=Iȱ+g 5Ā94nBqwp7q%2-.`'r FOdk`G p XNN:YSPB lMy8J<ȼ4ef>6刨$SGHΏx>~.u֐Pή oXQn$7zvThq̅ȔRj8'$X gUʟX}?pFN4Od;)F9/J/-Ce׀}v#:v*;G8;BٯѝpQKp *ѩ@i~lp\EjYo(|ޗCAfwyl!a8 7܄*IEh_#MVPEf'pQ:}v+m0!b}aWs/K Rb;+T{mCC-i$⫿RM\"n3jRo)oGp-ܩOؤK|bGtKx Բ:;mWjm=. (XQEQEEPQ@QEQE}s.CjG m*Pn>qM'8V)1m'oY=Y%JO<9#JѺ eLMa9+5w.4\GL֖*9 dViFF1X1$a%#V;T)n2$)4U L6I)HK6)A@YLOKq BnOڜs5}6PI= ^!UņИS&:֠:6N%\F/v(I`>*' owA2u94 PP-RT;i q;'54t!HAX9&2FOgj8;X.:\'$ԐFݒOU96BGn"Q :/bI8e\C|1r{oĕ$%+yyJzlN*.:Z#dB]KSbp($"$d {vk[o6K k"@Z䱰)<)F[$#^BJR-C 'DXiEM=ue㌼i:Ϙ/8,[ [|VWҙ2hYPT>0t(?o~l}ƣܦYu+yPljgZ Qu[8PS$1')Rq}%ƹ@HGaH%*'#<1˝vQ"=ЃRYlckL$붮,eu2sysވ.jl,g;}*-IR=țVBpúū?a--$ uda<`napߒ[֦@RNN;UЭ奔pd ƛK-!(Kx(%@6TJ1dפN*Qc=STRFrP†;>4'O×+ʎZRp+kۉ~jӝw'zXD(RLB`PJ/E[os\\9e+BjȟCB\863֒ "yg|Rtk^.* q*WFvE# ݮx?Qr̃:VբEua2.FR47 [z-Ť0ZjXQCiIQ’uvDQwG wuLNV;j$+qXALQrѭT.q` IIxåܸ6I^a RFAd5 d9V*ByVxZkc6*.۽ף C{ &(A#; Ml.p!eI%JU3#|jfž3}L g P 4$ IRm0´Jxs\(HJH_Ip6*5hZH<(|AUJ`BӲHi9'!t 6N$*NDBgSIGӥDzxӆ |qUxKY '8޲TqD7߹Kl4r!N; w [cRn,IHA;_绾˳Zֶ~մg`STQ\ȱqa\4SZ9è? 'VIXJoaaZU&vB~֗1Go'.>l' ]Ww*yk!iTlG#Vӥi'p&n"4 e4էI=NMKHP%h*ul)LCyNBBHӃW(O̦NQa9*c^i#3U$3-iSsN`'=I5icªicH UQ?;C]#Q=h*2nnDyPN9i*Pv4d6( -d&R-| a{Xa 6WT,a$qBά %9~AR-4$m85!)#X4zQd%;RUԽU *'i\= Y_%%6[uRWtymc1V\-%INBt*:-UTTZl1krQ-6G6 Q RV#~HHЗT}ᚭָz""J$yJJ^Q -rw*ntْe(Rˉ GO7W"qz2\ ZdCH_3l)CW]eAI Wa0G<;?r`ZHlGU*U#n˜1:- l=^.7)눛ր:QX5t1bsm#Ryqu!.$` ǻ_-1/iJJu nU  q#6=>G]pI9 NGK HJS5}x}鰮A!n5 l\sl!'r2{DVĄnl'drq㥹~+Bpws5iX0.Ra$J'VIg;|B~9ؒF:v#?ydhh,PS Rxui($2I=Ap=e%>u$'J m``Zo[Dt:# \$t 9T6q+1˅*ye.<$ed큟:o9)>Rpmic~ۺا3*rb[)mN-n/H$nBtFFAְ  W_L+]YpiraZ\fA(ߚGl;T=՝u*'cco,Hm"ww3THd4fEy[u+r2 dwH8% c-<L K$DG‹$-2i H8'۟NFz0ng̳sW-5ECímXe@$n3 ;SNbK.TZm]$#% G|&-od1FΨ Ï {p3򩄫<8)-3*d4m%'js~XnirP1dRBy`VJ] ڜy ֹ vm*rL4ٗrT$k9)G/:eڛg']J ֖RYNձ(\h6i_6hZTKiUBmqࠬ% lR@7SӋ`\ƅ&Sߘ4 m0[g ub#+\J@ P'| `\[Q0I;stMs_E*Vds(gwmIjJu<مQV (((( ((ODZՏ h5 j#pTUסJgZ>UOwL @ڎ8gu)Xa0n]9d)eNeDgF*[C:šC)$Vycسؕg+~JFw:2!ırtX+d,!'mD>[TUe(o^]Z F,mcN :u#U3.c@S4,5dm(\G2SqfH۟)~l/T fO*U'v|Lr{J\20@<өBkΣ{/N7O.ݧ& WKmGy^N],|K 7 װ0 O⊥CinJO3zrs$yr Us=0YBҗ@gplG RRʐS00RO T&uYr<崥NJ)={NWjZ_ou(}ל ;4euع0VqCV{*cOCFr]R 8%" Mqǹ6YTy$`s(mVX|.;ʘTɍ(ZH)uK' XRt"HVm")Jr0Vޤ.D)0 S DqB@98Q8WR$FPSQTQ3e3b楹%PCeh욞^Xa duICXB88@-D^3uLJ/2Jy^˟>t"8yPlh۱ն9ҽ2<+֎*1yU$5rJmN,uʟ. xTDŽ!vid ROI)ڭom!8:h::ψZg5np³Zj}<ހ°0~KpqT~ߞ='@1w6}{=CneN@QӱF񓑵%!!NSD?F4-#d=818]wKc{vIJ 8B5 N Jbj^}ޢ,<(( Yo;C9RIcLVXR-;;yVH=YqĨ6FJ2{NJķRJK6J;+JӨϖإ$Ւrv|jm+xYRV% Ogǘ'I.)+N߀vۻz#~:R Q

OiԫF%m{݌oN!ٮ8lF@FڹaʀH|"TӚds#:Hp|+DZ/GKՒ x 3u.Ql;PҖڵ @) Ar)[E¡8'VܐoԐ5i)YHRI'Zұȃ Xu9JHV|S3Nrڂ՚T:Qφ<7- l#p1zu#HeJ FGBhg!Y1t#XbA-pFrP}sZ=0?c RO/YڱCSy@ՓR*I2-cΕ[_1RH:1~qIg8d5:>ʢ<99Rb.DbFN/58#dsYbnF%AtƊ K̹`w CZ@o+8iwQ2,@qڑJN`t ښ1SVYsJ̼!H@9;c5jtoV1ov9^T[դ)j}8w n]'ctj(CRE MڝK%.$Q5R㝆+J~@NnLkhn,WP]N^JTO0ͼi[+uĩIA+9'*uELu23p³9pLDIո 9Q̌ 譒y63E:Z(cZtzwHSZh.jd4/>pSOxkJC/QB*߿w*qvI,aҖdc{5GeY;+g*nNP↢2ZqNμSqJNT'li:֔ N$s52PhyY<rF74-Re4y9i°DXw$Pۉ.'W'5ODPuoO}G"e mT|;t3.-Z\|iש 8HhƟ%yʹ7!Mu(cr|{H۸uc\ˋlmeֲZV4dsڸ6Bе:M1?Ŷlpp)XBdRi $^J2m TrO/ k\fʚ]ZP]ʉrN98qTxs,IV7+=>z6Χ6'D%v[e JqGҏR.)[hm:pu/`+/޷) [G NvβB{kJ -8(;r>J%(]fLRʢʚ5#纶v 2.wԝt{feC uZ<Nkx{mc8u菄 3OSv|/Iܸ@hlv>s_7J\ˑ5e!?;|}PKN-0VA9PP8w![vOc: K%A ][Ӣ7PlC1 N#;xUݟ]~+. ë) +k 9޷aq-690.)bTnun:B x7l.c)ʼnJ(Rҷ[r8)([RGZ$]q[d4ޜZn IbLCQnܒ $]ȭŭOYuɵqs)+s9mNwmvMjb-Ժ+`wCœXfEs[^j3<t'EJ]7 DACB4Z#8AŇvB[D[o#e)?> Smd(}9ޜ䦛Znd%ds6PΓq}fZG&AʖHuhN$@H$of |&rp gm#;gޥbOBe婸'$ )W:,9I++(+$TН>g<]W9UŠ((( ((((*ߪ \>'\c/[P1l RǘUB%:E88ҒqXA VUb-NpC8HFFJ6j9pl8ԠI Zxָ - 5ƴˌGi"GTr3 ncc^&+$Ԧtܞd+ƒْJA8’|짻 5N}.99H?I8ǂRKT3)rx 9mD+c;;V?#)Nsw|=JQj+Mxǃ(%X[[_GYch[H%)HQbAw[cJ( -#Wqw.mD{1z]ZwÁ5yJUη`:^KM5_HHR./CJu$mm|ocbcliX)I؟oYJp[~HJaZcm2yϝi%%tfVu$%;9ܩZLgtucN6 w>}uRλCJv#odHj8 4y<"ҖBFߋaD*tބӍ7x A2#&S!+} V޼\XMJm\YQRGG!=S?Z``[gECO6̕w1';+ad_pgGҕ'Rs3ϐ0؈*LwJ#PN{zsZv2Pc)H PQj?,Bj"m *S=ֻ{g n6" 1D-jᜏ%Նsia9`[a+x'bO:o1D *ZRN+b8eu|XS2LJ2س^*Rkj*#'#) %jKŒS;Ւv[<|`aOۦ/*!4 xIϯj[n[N9 RI y{N6(N)KSKPJm]i*$>Tu.,5줟6z7-0+B( RFH#J-&JG^BUsp2sGGtK/ĶC,e@<{$HjnTUiaN:oV '<nTeӘ䒗K`g՜zČmtdtuHmdl|V!Х"2>QL`cH#)Kiz n*T(|7x޺ڎU쑑JyiG~?5&JTAEV0*2^ea" wzAqu$BLɷ@ #8!Y6A<(='@*rNFFRC< Ju$#Z @)p9cʲSM+SǻjG.im)8'Sefdl8ju$#p+[[!(u(8!AG5\čE\dw;M'#zưY9IE]"$O$|ڢut%D!di @dkS)’Fy:03Xq :H cz.mΐW-=KVA]N ~Y݃Z:*:yۨVŒfHsWj3;KYNT#+-1arKS*BR3@$ 6X~+nP"4[r{GO*@)Tc#`0qOR}O,jJOAh&nҶC$r s=R8/{՛\IàB2#Ͼ\V AZPsS]pEjRm* ,H!R·SYʇ93evވOO,Kb N$v=& a$((cl`f1za)*i/7`_ tE1qn֨d' `lI#o=mFI  +z1s\opZVӉ0=lX֨&D%8ҀHG X'ܟnTv%7J(> :p je9S Hh( ;ΤkZHo[&naosZ~r=fց`HyRN ڤ&eMgval`+:Hiispxpۗ 7x'+;`'JJWNYNJ.3/ݬJnǛ 8PP9ωY7|I J.KM>wc=ުfF\b۔>2}IHCQ+U-x58V;@g`N9u9(jG/ͺAl%;BB@(wqO92C+u!ƒIޱY kR@$WЕž{Xs?w8V)N%ho:wf[ArcI+pAJq翖i\]Ėm4p%*$qQZuIJ% iN*#=?Y{\aej oSۊXێoo,Tg1~9|5!$n 3.kt;2;Q46BS{*G'pdiJsJ*W='X6s޲Мʈkw wѣ\i@6ʔv{cU* t >f8\Sm5#2;mkLhh>B\+R '!n KktYB+T؋y$O^ٗ%d8!]Oڍ MJzN>@ylp ETyl[[.1V-j kJ>ϬxHHA~½6oAV>2At*m>YM4ƭHHJGRu}ӊ!JI][7=9qduθR$4'ZAA.H8,*8Jy *VvC!AI[&訥\BGIs%*Xg嬴G[R%#k7R oPF[LPlT rA5=2GDPO;+$Ĕ˔4/^zÿn* Л*WMB\G5nHV?tUOm@vjt!ԶoG@֤}sR^"gN\S;z]=$)*XbRr9>& b?tssJmnh sOp5"pn6C OZics(dzJуFJ rul o?r.eE' w)䋡%vk\hvFo( pqɎč!łVzGxӎuђTYVBG{ɷDi6BZZ):mbWz}0 0nd g{5`ܤKRêYmEY` xyc>;7$9չҦRCm/9Iu4 Zai8s g* )_R 7eƋH<π^ s"k, CJB|$,z=rsH{'e -48IpU#lU(,+MܮBcj[[ wpw?E6_ըHOjZu:I #ߝ8&섏]租[.^]䨇Im@\#QNRyNSJ"6/CIҗ HHS 5o?;ɇ i( Zw[@g=Ԟ%2BFTR4Sn0K@ ܭY;Dm\b"鉇za8TG,jey.U6L1#d0GgV܁!JRΕw9aED'STZZNACMvQˠ{ت|ԭ{y+ dd ϑU8v`-E$: J#<9 "~$K~jԝPIvs Yfepd8%p;A԰RGL5oqL% #'rIN'j\Yn4I8ScmnmIDiQ9Rmrn]Z\(Q[`Ii$.t/&3mJY${=pq.[e95!AM)igg̝mCM*JH)t'm''9n~rʜ19qn;jͷBvVMwB,n1'46\h /qr)ymXq)D<#p)◙-*;}[8rsʚ8DvOj!)VLj>COn+[qHxi[X_V[KHhQC ou .+MxmglhJ\Zu0Tq{OBj l?Nr$)+#b>?-cjlץ$p-K>;G2}UqaⓅ>J@2۷%R祍^YnQvarSiaFd6dF*dCpiШYoT](V0s ${ur_bI-mhHZVNJrO!Z_Od,RmAG8Ryv1Lh8%NGBCcWNpHd}pX nӒK2p61M,].eЭ"y9׬NW!Nz= իK?c$ŗ%ĶrڀK[tLdվt96ڑČZJe8[$G(Q8Ԧ5>s-;}l JqDvS写qZXWqWRK!,dUmb嵒ҰNH9iH e༔ϹM/Xjҁ; $hӚy@TZϱG3Ub BWݹy^aZ#KD9Kg0fs2X>_jDz@%=ZIi씦A8;j';cjLtE*RA΅xwvV%%8ZW\+gBuRE;[;yDMJmk5O::8hX^s9a|d7J mIXJRY >T$*Tbrd^|"< -I)'IV*!Űd) %`K:<0MJxh+u! ^Kj ; y{Q)9mO+y)yɺO:J*Kn,$NsgyҾt=bV% )byr#>cT]˘dմQ;H C; 黊+^R_coN`;xN.[H-Қ2#Q#Sg)sە ``r$w&ЖH|fZ ggۿ«N!iaPQީԥr7^# Fj-%;%.[,)lJAFGvUQ&cqd8$lNl˺-leį-! PICeEk xcUqy7#ZhK-HّYLNTrRM-֨@[3뭲-+sb"/ʛxχGLKk(|%/Fix5^p5T+YI7S:`3>U%|e(% )[nw)Z84ԦIo$)Ec7QpE4͋i%ZaJ)aϸV}ʻ)='9ė0G( hP&_&[7շⶀ+lx*Յg謌iui>I"*,GX}M+]G#!K? BTH`E"0@W%ż'j>,^.V^D%Ïh֕HI9ϟoVRNvcYʹ Aãt4 μ<6?&И.(eH;=#^L7XA>6uB<@D 5]Ɯ%dĿhҐ JNyo\F}Ekdv,.'x?qOR= /VO"FtOnvd7 "K_ykuwV˗MwY~z`zL0B–r^;%.)LLwT` zrHD4#Y8V4e5r[e '<+Mյ!NqҶrNjF䃾;#j! ݄9%8Gx#F0w:t6nVRJ/fҕ FwTW;Υ Q|*ZXڗ7 e$Zn7=Dw Cnn .* #'RsJe@Z2mCmFRUJSn(dqk{KN0-B\SmOzR$y)/ ~W 4iOpy,rHyRc#bKmTJ9YhcE *JSvxsȨ|w.$ve<Ԗ, 'hnmMR$КE@E^W'i-c'Dz~Qw6Vyn!9 @TYVxElTuI1neD$ݱX\.W.05. d9ю}: ߊﬦ D jN2t݂9+#DK=唹nm-vqzEh]*qI:79NvQq|I^އ$25ug vVspdD0Ydˀ(3g$Sr*K].{mʔPJ[ pԮU^.1M iy<))ǷoZ߸qdv e2}ḦKS %%'>sKQ1GD` ++eK͘", e:8+SmIi%)ܕ'Ah+ !2֍]VVJH>Sf 8tYeV35'%ߔˈ=BKޤ,~瘭7U.>LΡ!yTbq'+I8'{"[ўVIqn U2ŏt ߘ8I%#At=ϖgo2΍ jk5l-֜^ih?;mjmxBm%vH~orh5֔UU:*NlOc \dl}֑Kٹ|!=X'l^Uq3]eb|FrA'<ʼI$ާ55#B1| #־īK,̕rQ\9/RIYYRQ+ >U"1Sm1/K)9NkFeS澑.1$iY v#vgHmbB]X^VKvF: 6cն%T5T!#]e^(#-u|QEi@QEEPQ@QEQEEPG`b%ʁd5_e: {]\䮄nηm)&\)2]C-ʆOy8s$Ui膻%3I<JkԸ=kҰ cs祳xfS04- %]hy*卻(YH/%TR iGxmiM IszR'7r_$ h% +;W*haHeQ@sw;ΜBNWqS[Wk.$|STR8F dFV=R񁂍c$Ɣ |8M(eeY>u EoYf5AR. n΂W3NCR{;y%gtN2MebIqp]qԷr)J9zxր!Η[QR VǸwciТr#$r g>8XRKk!@lT1RhE^7R~2{NDǘJMOU?rqVV_̇NöpA;g$A7r\Îέ;svh3kt3ü-w%L`uxv~MaY i:6ݰ{ʒY,r_Jʏ/sU--+%ġmf,LxܝBنe AZ_ݯU!5 Eԣ>=٩wqJrFa'| T$?oWڵ,T{C⣈ZA8V܌D⼴Y|I=$+!C%#nF3T `dul]IJF$cׂjrŊ0\T4.2$`nz܈l̤r;꧵HZNUZԀn`QՒ:-ou̡ԍ[a)i1HX*샜'ouxZp[' BAǬ>s.78:1M(';yT۞TVR6ca3-éB2{HI շ}%)FHLE`ڰFh.Yi2bڒH0B;)RHZnL5%$+2h f> cr| '8CӥRđF)koJL2x}p|)}X:TUsl3sZi9)'ׁ^>ĂXK9.>jDl[Nry!IqiޅrVc)I?5$ꥅEbq5+qo.i=O=u!iIH挟E{5ZTWt#پYIwRZBveME;U*rwh Gvꈮd3i%?dZA8*BA*JG<J~,w;{:wjr{kZR³CRFv川``<rtb ,;uDr=YKKaKRR N1NVW}64RwPkaD? 6vYpw p,d H5*PG2~^j-M[ڒvlJeˠ~ZeG;7rT:RN);JdoI$0=&,~-̒7a)_';o0y,Fi/:% !di:/h 8piTLwB"yw%N1q5³S76\rg~` tܧ%o6 =;RٔXPaǞ+umJ^I$UlDkn|GP\- |T< E^R2ܨ)}!i)k@ <文{&d^S6rz% @JJ9ʎFD+u pNJ̭ƫ; 㙤鵰?Ǻd?IHn3Ql$~tqB-r> S@v:_hF;zK? * I~e)$m[J<1lGXM$=A-bGv MzʢT!)Y,& К)X8W+rR4%qP3a}kUf1o;Z]CDl־/?IgB]LLUlи(Α]`ңeҠ3sc` I}X.mBT+4YJMNۭb?dRq#B8}t<ףaYy& ~xdgL\BD8H~jҡ/XVi!-V»vյ*/߷f[n1ՒknV;8 8a.]jNJҬc8Ν*7*<7n I}8RpI #>ׁͩ܊]f:G2BFp3)dYb8eL\Zm\Hoqf-4䴤cJT72g;"kr ]y|4JSte? SiSa44',: 6lqaqF6q;-ZH*jST#JT{R2$%52aDqGw>ʗo™-)$dξ~{ ߲*I2ZA Q v=ptm. ء[m" \'YBwUA!7,QZQS̩;ymS~n`e1u+I\+:C`G|nd]w>سX.'n#Buw<87Yq/ m)ukR1嚐e,N)\IrƧ>R c= 98:Zm7NM܎AҤ`垚MrM[ 3npHs%)Q)QA ' %j*# \KcSK#%Emߥ#ي}~ԘYB@u*sܨNHߟxۺ%i meIi#ZNNXe,e aR#!IE:S{֮-ҭweܥ. jcY˅[uԥKHԅ1mPֺ-RTW%g84LB1zڰGRt=dj Pj'fnu»> [_ve*q#LJ)P֝q-K6sS;l2Z,wxg>֩nB 8#z8 rԶq RSUu} !Sor= ACՑqiq1we^- [*ZXq@C=k]NECI' RVZ[QS^U|]5rHuJ[FqgaحW+x-M%I@RĖըDN{|#rb?Ω)rYNlIr !idIMg,rHe:A 1U uzbzlnci 8T d*R90q|&VZ18p $a4֛w j*r@U:?Jʾ61\ͶrsH5>LIw*0p3oeu sCv[,ۗ @/ù;[ E; *Ґ(( ((((+;r>gܜTvy>lR1%`ZqDž^U 3,Zqm )*I'pG*垏.7|eoC) V^RN$wVL40JUB~ĕ[8 @Q pլ4^ |`x#qqHn7ˬ6dK]q>ܫ}Wlç䏍!PT+v+K+ ֓V":CN WT11>JD!9 >2{qaqMؠ1,ehp%*?>U7w`{KN%JN0 9gqK Д) 5,N<@LJA8S((VT;#O@iĎ/>&IR: @*$q[QUocKFw}dʈ;|ɷjI0 ZP{%xj/X6z!*8;l6c,֘irnBIW,Vp )NuCSƝGa۲@L\*C!ZNsT\a Fs1[R nsʓNH !a$ v2}HN $dQβR=j¶&α' ve:ҟyqYuĤpZqu^#5ϩ>=ÏI5Q˭ĩ'5#TkeD(I ( `;c J+V}5l-l:@ySarjc8@ B]RH-#[bFrAZ{Jb]%KkB)9\r{Xx69:&W$[j:Z .5%+vK\4sJs^E[N4 | ie, V ^羒Ln:!6N8Z151YI Zrig:[H' vqwmJmE Ћc%!@IJZғܴ$gV X V9s4Sge_;tt:4WNu-Ƹ* (I#H;{a v2Tڞl:]'Uэ+)vt d u3=ωDݫ 0Iv NIrJI|P2'!:IڿYBjEjr"1)DE0y9Sŭ>qͰp7NTI@Vq+OUl2\|7!_V**2XËr~I))Zʓ\vZTt5f&c^XhCճN9Fgvq 5y}b{`o\hju~yg4%cp#{CX=OŶHin/#[gٚfj5)&_^U;) C A?џy5g$c1H}>9o'V|oo2 >nHTg|2/H))W# H:#*ijnظ"#mH981WsEg&biJV3v>;_C_>(@QEEPQ@QEQEEP_PBzIoṮV衠8ߨ>wƯ8r|cg,fb"=|J!]q- 8T;zSm*K/-A'{]vwDcƷu?.1)*/e-T^$ }yUY3Pyd;ѫX PIlJ5V=)j#V cp<ճJԣ++uiJ;H#=;khts-DRb4!A3aw1F1@j+% 8ҥ(ㄤ2v; mD:[L;J} [.HJs' j]vEsͶc.@nZCp03?k$~r磈CJRPs}:'1J&jB1#xm)B)8 j%D F'Vǯ9fn[^R` M=$ߙZjDomJ[PXVV@I[A)n=xZ_0O~byxPH)=J~jj'Lג)i5՟B0 JN:P&{g):&R9iBG2=n@(Gzcc~&>SbR>`#PR1W{;PYIӤ4A9NޓDl~jؘHH¦K䢂J\< 7Ȏ8:A:lk Ae:X zw>"rB0Pw' K,a1q8rI'8oRi*m&Q)bc9+hўWCַ <ŕl d ji08(SmϰGqD  #GcNF[֪M;Ş6.. T{ղ$>*8!":d>Y I,8> sfLGR;$E^RN;w7mbU`U5v$u 9 Z26#ynߎo4>0BbZƣK*Zz#ds1ʭ{Y5\CJAuX }nS lywo[[*P{TFFeucLڴkTeN 9^<u$ A998_Zoq8q[iSjh0`gPOvU϶eZ[IRwIiunԴFPy^_"m2# |yrE:[x%7&֋-uI2EWcJ_zTGڦJB!qEN6>usb0RTiu?q,=*bdždf(ڢ#Vz.K|_MP~bOL8v]ŵG ۘ7pHw/pʞ~tҌ9vw _4f.q-% xShA>]&\vnB}*$( ΍a_ׅb$؉Z<w'Ý}gyOQSABӺ*أ ^NhZu*JJT##שV"cV z=UXP[ &]gjY J'\]$4)繨eB*Xݼ╶εOX J[Wnw^FH񨶶:NIiW/2RԲ0UV9Gz}mְrX1.R~Ȓмˊi 'ڡԷ\$'urJRN9-<,v, dXR!9qT(y9A '*S+V$ӿyR%T@ÅKR:ܝ)@#8$Qlcv۷xm\vu< SJ)P ffQSⓃJ3wSXW2ʺRVΜNrN{ϘG/͗S5[RTK!x'|~V-OTXqP#=sH\nqYʷu!Zt#692 vUwiΖ ]bTNSnKm`')~wRWG%J$s gq6ʪaOqErn ~3Al)^lGwZMst@=TN(.N?kRVľ@zI؜cc쩪8r0bDHL|rDHcЌ|dqD:ѐHIO#I' s?Z>Rp;+!,ȶ➌f\~܇(vK%D(6W-uISg2sR}[MhOPeRc>%Eq 4U HRK+Q*$2sO~9Ԋ ؈Q@TH8jrkC(mM/|;,TcF 뛖J&2_8E&C 9|һ$[[-V WZ mNͶ'I RTTT YAi(9IiC|,zp:k+zOvѨA6%~kyvhJW +$@sN,[4HPI  'rv m4vgo*epdDKj9GZT$^)6k\ƒH}y$z$t uHbJۥcEKIQFY{w䜜drV;$\Gy:VN'jWl |g$4AyCjA(4ưX'OxǗw3ZeխMKd9foBbcs_vB]Z'#+eTXy XBtFd0*Bw+p'G"Nh8{°w]%V۞r[mK~[ x-J#~\{+bajH!aIғݷEaqW(;Hd% `6pA``co<)b/8T[֮Ivۘ=¼SIB'=imI薥XKpZ}u7*e@訸u\9RY'';Ͼrry vSI?6$}U8ꕑ+Ǹ $m rSc)*/onxFVU6QLx[Iɍ1-9kjY: G'q1>jf<2GTyn<ǝi;VԮ&@2ZnssjV[28zJU(c. i9 HҠ}cPtY[ļL+}|bcudH ۞t%gWkqU4)$`ƕ Yލ*KM)HQtְrtQ⭋ ~>_*L8^j|xiXFJ I'm1:uoն1O!~oH-G-F+kIv7X5ԣViUW nɽvuiR#`J9 rVYq!H' >ѽxx'Ԃn=z>564 _]iVS>Tp|nLyMRt+ȟ֭d|G:EoTRрTްygv(tq\d(Ɍ8ɪ枎}u;) IIjy S8HpIʵ_E䡁h}mUn ޲MX_ձ6ȨC2Q-'ޘlϾYV3<ʁlfkե􆌝ѯ#JjOB/xUu̵,)T~g(WRf7vXU>>nXٮLȷ@R8XV i  Kq;]mؤu՜:jBROu2%} rT}dLT 0)d;f#V|Nk4U'!vrc֜)4cʒ}~f#a);7@T#*9RRR{Hhe]瓜N9U$7H!؃?纶,o^C(;ueʫ䶴x0VlKb"GHP ctUxJeBP2AdXjCyI\!(tFJN (U&sz:sq %j#;wW?ts383gx(HQEEPQ@QEQEEPOx< HB>yI\n ߧ|9n3!Au8*'r9 Ɉ2\ia5@lVryTĦ)idsP?jT< Z3X> 7XMTⱨuG;oe> *GXkBAIsI. KqMI[Kj=痍nSUQ)ls#czבCj%G|`~!s\n2d9)Ow_t!4"`S,.$xc֩DXL`jRK* $VmIs(|˪m.&ⴃd94N1/-%-XJ'1DNIW\䅍J) /!9uFdqMNNűa'4<| Z։! imJ;(xM5t 202{T*KP%UĆ yJm`=z)+mZRԤ )pO)Qխ*@A d Dxy׮4$[ $me[cuFZl$-[$ ŌK?q֑6Ď´%Ou.wTKh;qhvix;*ݞ^ج&csYJtaMc#1'Ieު_))W R2s1Zpa~+`-J8R0FĞ{ƧTĖzb˂EķVƝ`mi)sΡq#;n^$;S!!DRݠr@(*=;XxByVVcZSgIExwZ/X۴q5ԉ2T\9RR>xDGmN:jʜ#H?5*)UR?)>F$oݚ-Ɂ-\[kmd|rmQ/!0(y)ZBx5zLeVwY"FF$n+ weӔy!؊KIRj(yv>yl}TZ+k \k&3ΎSB\H!Ky~c!r7{ JVU4Ɏ V1 ]SVU)#WJԓar z9hvs$JnTT8Gb!dYë3 _V[j|AHKOPԜwyz*ӒkJK?kTow\)ӅG$`q›7`N\3*Nwv~&$*/ag$`%g$"9Y&8 I8BH<5xb#4.Bq{[[> Zo\h_mJq[uj̧_:@*\%[I ‡[ÿ#*m|IP#K(4W?o{Mw[oi%D$!Ô<#vou”S>Nkĩ``+ƍ'MޛdZ,G^ cYRe6ZBJ|׏ܸ $\ʳ4O0u.!*ϝ:[oiqnn ,~;YŹ2Jäu3TB桝^TY{e:N>#JҴ^%1NҵH#']簝{}fNQj *ȥ͸i+8(0]),$y c$v9&r Qΐy֗Rs%]"O*L |D7I# ?k=}y۫Fg8vt HsJJ9VO =_:am8BN$`@gjJ-:Ryb:nR48ĴdBeDgRO$ ;ɴ4gH;~i.GSǙ n/$*jM.Bqo{*Ÿl2h 63.VnZrz*9A87$FbBsSkݴIg}%҂ANPN7iIt[Ң@"Lؕ1P 3 rPziGXp/JlLWnjK qiRH0=vDגwqYJE)<9im'HOY)HBA?lyV[# LRѥ$vzāNHm0sLΤ*k$ >U.F?"<#)NΒ%CJTCuxv2g@}Xi8d (w9+Ӵ(d@mN>V ` |*RPX{i٨9JN6Ox|k.˲gw !G.QWGt or[$Eu {nQM?1PP+Q]0Q@QEQEEPQ@QE\Q.)TFT<{U<{*{|3)eki.mi P<8:<+y:+#WrHGRWېج5XԪ?ը-xR"cIH_[Q^rGKXyG+̕+;wrKu9 OZN@r˼Q%*+n89-'$sRW&ޒ$$nH>udlmiցƕa[:OCr}fTґ1DF)mIH7<:a O0@` ]O4ßXݷIz.GYǖR, Nʥ]:Ad5 /rx2\MHwGe:3=Ԛsi]% ߎe}+l4P oVA:i J\""ItBo!(M߹,YI[e6jI'~eR)^D[@>Njvjo 1³|yz[:tI8wpO@&sP-Aԑ[%lmYD#%$T6CV% O/]]/ MdVAbrsTF6;羯ipzSIFsc>^5M+ޓTL(@ZJy4}HPv1:I8ag%;t_Zbt*8o>?uG-ǓR1e-ҢÀck,69/[2j ^T@R _;_O; t,V7QR!9F;tÓ. ԋǘ(^q6φkj3¸Z{?1Q}J~Hl)).c;P$kQ >+7g$+[;)3-~π[mJBȤjJ:G톬t^hM?ye uեEZ4b'H;m̏n:Ij?Mw2ܯuKןF})Z^VIΤg#Kc>'\VX(Wg3ζ28`WH@VdEQɞY\R$JT I )8d|뗶9cKv8ؐNsk[ %Jֹn26\^B}MG3ХRĩ ON8F?ύzC)-= NFHxgcqlrs@RTqeÆ\;T)$M1cky䤲R1y愝8;SUjc{F'өdoY%fzƽ54ow Hpm+:_'7q;5VF;XQ섩\77iOKi '핂5gV'#r~a@w\dt4YմNI?+Ԧ> ؅KP##F~Z`*hynJR-:߻{NtGOR46,z4"J.wь{Fq-s^M~FV~y,q!:*}Ÿ8e{ %!A?(FyT&BV꺕y|QvNIB Mқ)7瑅x5m`*ySQ Sz0~2Uт.!)ҷ2|q}TWS,P5\dzK ZL򦼕%i,FĞxQlȈ;F`G3k8jH-,gSi/K}LԧJ$d㒆GJ-ZqT7jzR>%OpUHGgW.;: }@_N=J:uzpnPMY.ݳPd7==NH:[Ԭunf]%./GIѱMn=:PGqF),B*R)kVPG8)pxjTQV"z]mnd}y\էZO*hr-Cn<;ys|#+{:T%G){/(PʊևP%)5(nj aє-F@٘;7M g ul 1Oq[NwOkt>pKilԓ'GWg7aCC%Cc緬sbmǍn99FM;3Q\X ЎbKwhL9u.> o.W-7G.2P]ڔ;4"v$ RfYq(m(R!)d %!% 81'֟(ʍl:J/p\N1"A֓2<=H"-|UQ7a*sv"d&kI-+Gg_H۹8%snvoT~/{cԞ&7l?o 81dJemIQY)Ͼ\l .H.-ɴcSRZ[gΝqZ)%'b/rei:Y|9#tyͼL[j\ Y|פA;j5$gmc[Ȧϡrk@м{:KҴ$03Mnr:O#*NRw.BS*u83glnie +BVGUIr+kN%X$kKN -ߟiۈ*qͻBU; Xjma"EPFWu28jA:s}]ăMyC>0/f#*ѻBBÀ$ @<߻걧 V3>Zf]F2 '2rug??l;?5)SB2N1: XKNwwkK,R))e(Š(((( ((( t1ѓLdq\zA.)Iʱgh?ѫK?Ү_TX*YL75TT$ddUmII*/zsᦿ'38ٳBJS۩ݞl/(sq]{$ [+ĩ8d$9%ԥdrMtu*B/)RHQ# Rm\d Oriy9)WzxXCny\[OIYq#t%#|ۖP~GsDh{B*OW)GتצQLCRvpr77EW1uUӨ XhJ~ZUU+9#٭uFW:ܤ7uaI<9kTn] !Y~8)Cq SVVY;{}uDʷ2e䞥,!ܠWvN6BJG;mN%UjFv8wU!Kݏ\'Oߝ*1Qz1.!]()n[RR|=2e$&yҷ4,#l%@INV]4'Pt!IYymjKEQ4ʑNydGgMۈSJIK9Qv#^3\Z1JRBIN9;j,SÉX(A[X aJNʧ4]4ݥڃ+#9G2rp2y5bF}ΖI ) TOSozn -G'>X9?[&Du8& # G~tҘE jxojOOp+-zB & W8'IvyөdhVh'>`dlrGNki|1d>hvX%QƒgX+Ē^)4O=coJеmޡW=䕽S@HV&Jֵe+JJG>淨6p2~}%-Z s[O+Ԯm*Әd``[>U~FZCR 1iK#r՗qZ!9jJ6BBG8<=Ö+rAq@ F}UwdҴRG;:|N5i'R=A@JHR1^-]Ur2IZNq yC,@8PDg q)PȤ[p)J#8R,Db:{ ݳ|+]HFr͑!pk@RTf2)ӆ&5 *7}ҧ7LEvS%ywg誢{}qZ⊔|9N"!h, ߿ WIh|  .|XZ$E_#gd ϒ-G= f229V ; 𬰜QXdFB|VsWq\{"bPz7#;?[ :-'sӒ1m $'A9x R܆]i`A|>.ҹkE$-i3qcR2>ZpIv;AjՓ[T#]OEJ*iįaG5ct tI*獪մZ2\֮?V$)UD[:+)[de9WӚ=M8f5߮$.2H OeiSM.OX6zP|MIމ(W֒#ILj$M<dGSluQJI0~ު\RJlISq\J>yjl%X}7' žVcR|q-u`+5#ylF^SM S3G486޳T(Pҡ9Ä@Nr)Ղi쮦BW#fL)w ӬgBRSd۬%:2inisHb%NW%|d$(N9R3o~KpʔˊbIiIeR*XN1VW"B:(>[3&;RP=ݝճbYʛ6) l؎_wiŲrK !IIx${jU)G+ortI+wz|yQҸ!ml+"k"TUF~JIJqddGKaqQs;#OqX#U&%mzz[ZZBRrOB~1ڦ r! 恤[:tTRyjSGc:١d&zzԚ(9@R|NqN)챕dw曆KpTWtޤ#MlF^p4po+NJO?jר$aD>'p՟Dթ'Y]f֕r8ks=2sz;~sYd+#`rVq쬧/ZYNDF|-Jx$IrⓃ׵]Hug'XI*:[J9Z =Ԛ#KJR%I8ϲuqZNN0;JP8KoJ-.(-'pkqR|\t6v-Cvf)A.#9ueҡmd;nyꒆN*ݍYa,ՙ(BP\0C$f(]XWj ySJx%)$\U7C *-99ȷ 5w&}.mq'!iU:҈zug9+|ŽPivl[o$=nqLZWsޯyy3vBB76rp1=@Wfv#Ipd l;ޠ-եn e9g9ﭦ:9s)ԬLg.B[oCiA Nx$ձ!B 'P iXy5\'d<\Xdj'#H߼|^ g$$iQEhJyՄ6|h)Y\hy x`TI w^B̏p.J1JW#5Nl]ο 4Pդa9~^T2Knp0sb yRPΖ張ԠRs}s('i F@m/ tV})OmT ز<|Vf|*^t23B@J>05g>X}rkoғH0BR\8@P#9pt~rA#SRVU|ࠥq$e vR?B~k%YnGo8N4uj(I^VP~يͷ^q~_ǐ\YKyT}:Ojnj@*G>*PIBD['Q:T]VN S>]QfsZ`x'r+uq n^IIO &}*ړ)9*䓱U4b2*Tx&;\M+Rsܓqn84;GݷZBޘ$VTU\F~|) W0 J;~ˍ/yR.*#OeHH_=ܽtf-9T?Iy huGP]e]VTi †Muln/ TNFʬ's˩2N{<%olCzPS&s6R=bnqDˋHV yVv<;0 ph=K'#wG첆 aq;iIa2&-Z`X~_)VN}R?DX >4,xι*,|^mKFR["+2㓝Nzx!H'.eX"#/s - (N}[R/&e !-'[xPv~'$yK&G#<[rv͡[_!z8-4 A;o4m2+rP.4=<ҒA #9W^5zydϤTZQhJT+J GSH i\pt]EGB#\W? 3ƺ2S+hozwE쐹/tWx2 _BPP#֓Nj,) qNG a<u87ۿ.Ο]͊1Nk +_ ZQ݉$γko͂BTFGyrwt{z+JWԨ "=Xxz=_ O<_WrNfg /l4PCŸvMq8 qhk9aZ7J4a3gZYڒn%QO#SC38E΍/k`8g#|p~%4'wWHPt k-_D/8 rDErAbJlLR} {tgݴSBӨ` ɭqXq:Z Bw4UV͘l{Dp 1 _~M{9;9ɮ(Y~[OQ|N߅/&Orwk(P_H|p7oӿg&bT=fO-_Q|N Nwk\`A;?&z52/%Wp2x/FZ{Kw*+|*'xϪ2_iݚ83?wsGgd|b MU ~cMxx7s _+CgZ1cNNwk|c֕}i߻~ֻ(\I*6p/g&ap}bW>ɿ_8/Bsw}h<8߄ޯ4b\=b>v8'4\ƱCFP^S_@޽|0Q;+q9տv8K83z3xZ)RN :qӟ}E~77ǿ&W*)+\ڳ<8'Hj<LjK%ɯtS]Nr>l3v@خ%iB8@߂o~M}']IyC| 8ԛ .> ߘ d=eԃ9e>UW rKӽFO!g.2sksO.p~*W>Oe/Ē#mCsZ+nuIPM} i9x;wx¹ *3#r8+BA?=5a*)IJ:>Wg<*2+#πxo.v]Jm ]b.,)|)~N ]ѷ0wOw^+SUsP'ղ[ Qe|mx/KÆoD( 'Փݍ5`QSRd┭pGwv)''>W<2n%ic¼R9pE(g(gn؜+F)wC#L9z"O5\htf R{q]Ɋ1SACeU+]JB Uꎉr }$XخNcWWbWnz5{-Ң+ZTe$u =zъ(UjvkQ\* (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( 3LyĶ](mIj$$y\hDÏq6oᾕ=eGoVtP Z(c>gDZ?tĉ;64eq>,68c :7{3׃ azNCtq,*wxwuxnþpգJQ:T`8؁Hl;OwpaȺ8RRӝSgRN݅oݚʢ:gףv*faOZB :ГJ ZA=1ի/vIϷLl8ĆR ` EPQ@QEQEEPQ@QEQEEPQ@QEQEEPQ@QEQEEPQ@QEQEsMKuꇵtgѷ͘,YB$mj(fs8k>+^%zg*ɦI҄iY j$tsk)Ս|wDfSRtb0@ 4U=Hv.?4ݧ[~D[8%6jhJPSsJr&5Lux:VHF:ۚעrHxI8mp jji^N Ƣ4;t=6{EH[.2oigO;2iK DWա/B[ ^:I?[x~i%̶!IW^\H @IVHmͿ\`Œ/,iBRTv=-/P5fj8.uJ Z dd$ kES=tqt&%Ze9lz8t$!IsIr@¥]HW F̎kaL3I%:qw„QTB}z:W}!-  pްvʏTq賋o4$6e -!+>1@XTdۇU׉b}X0֗m IH 71I8ӧ^;ïu$ (I ;'"h.cσ!1dYy!(e*ss[( (((( (((( (((( ((((9~[]:}}KXTQu}+pHp^nB\TԆBZabvǿ8j1;/.9wFr U/ÿRWFdK׻mjdF֒ c;gwqB= ]\.\_j}Clr%ԟ]2X>%'tskޔ-œ)lkJtu?f$6F;bz&=>@:J49qHNC@%)Q%*$iQj{]xGxj?2Ǻ;b-NICْҲ'cح\#>? qM"JIB%˛)I)&$ BM}P|oťǧD_I N| HXRq<Z.\i0BhNJtVTIt!G+ t#x'xA&Lq ΞeIP)yz(xoq\IDg/Ldl683Y(9*ޔV/tW./Tfk!Ah)JItlkovKd::(+r5|PiRF/ K~∋Vs5c=ڶ]Qm,7,f 6%$P ((( (((( (((( (((( ((((ʸ.AzEwőxrM3mrS5#HIBAJ2O/ 2*GՌaRn01]]mHM91W4yKtt`!8'>6/ENv5WKsG^BoN19rύ6D=QDU f tkX[I&ڻ'~` :gFrRYl*,Uӯ[z60c]M 8mQ%@$wRgz9${ntWmJCgSP}Z2%Q5jXۚѪCa_&k>OT dJK;FF\+#9 Z 0ʹJQ<8}f~$c>:;+$RVn0TBmP Ϸ:9׆p[$돦[:\/Q *g܅}niDڡ#)=d4anTX(LP PI$Dz$! B@# ((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((( (((]/GwfbûLlCII <59@58'nv/|Cmz|˸H6Tug@ع"w]887qe.;!n!e NPӄK@$FjCy(ui((WŠ=dxN$ėN- ķ>o\ yIiPIX8Z+헙LjOȔdHe$)4!RR)@Zׅ<< {q' 8),Tqա)@!Iy)dJ(EVT~M&LhM9)+p O蚵' v"u'W"807U) jC\U$v 7N[l@T.DT':w@#P<1ijw'W)hilJ\yI#Δi˩Np@JPj ((s-We^'LhM jհqB)RPV0+܏\W䞐7NIN*_jSf-:fRiq޽IqNySmM |Ef. N$FKCE#/Hp(+  P>x7'8bHzES- yBJ5('ǮTWq ^.-ag OfCm:ࣂ@ANG23勇q,Y)HMx\ܡ5BRHV- 5nGI;7k Lh}v>ąKud@&I\P!}:M$ ŇKZPu VOT%tv!q5/wjiLgXJq2*@; ^#\̕"q;\f´]XnL6up}I!9jێ ^,3V"eLa mI*GP1FP@RGlJkp,#Tޒ\}.]a|Z ~;!M%JJ*ZR7Т@< SB|ؗ\9{XBfCzv ay$jHE(Usxvusq/MuRN9 ItdBq qjTT|I; I5\{4GH\IlSL$BIPSmjǷxen>%&US\OT#:!%J'^ zgtи^vFuf ^'*)E~kF$VA;nqWqtt[[-iŪCT=S .7 ɮ5-VN!A 㑠&Y"^Ut/,7 t.S/""ਨakBqp5kSdqO\SpeYmnORڛ-U-yUadwΐl\eU&iM6SJ#| j#hY62X]75߰Himj= +P{1 IaDg2M[]qoq}2U CTk0rH< QTJ7>&WJ1)[Dl`DjS+q8Ki#cfGA/$*|6dޣN;;Ju$:rݸA.sXBFSM$# V׎KԐHH,L^9[NLמ?ő ͹yPmKj:RečBMuʐK [zS,7AXI_uєW?8Z#+e٣-L%Xa:#lqWj.J=(FFӜ;QEEPQ@QEQEEPRy8E+y:HT3HڟK7(n `nt`Ju\A I884."Z8mq: BAGpP~[@v̝6(~Ƿg}ߝ=\VcЙ*[IV T@Sww + z )puN l0)뻄_~U]''ok)뻄_~U]''okdd?={_Y7Ŝ,m%-kPJR͒v \Vz)՘gxy"JQ X>)ء%!60!- (%#aHܫš*)U !^|5gMX;kElm% Fl!p)|5gM Y}hG@/|5gM Y}hG@/;e-a1- >܆B!c<ֿ?#魭\ \H8*K#>s>\̸*;0[.=|}jN8x?mA/-?mv1K@g| =: =: nL $ o~U ϼy \ \OпuQпuP F\)kB]q* ACY4&'[`7 (:/?9 DŸJ ia[mxPAYr+ BPlJӗ1 =!HPxvdnCa#8[QY KW5;NULf( VHc3zC6QX/:c'4E%p&KcL۩R'P#Zn A2~Ο/~ Q2{7VTRҢN)~)S4)ykIZNBAtQEQ^-IBJ@=ԌA1nP@K>FF[xf[E ]ЏKsCǥe<3&;(i֠YүQ6M G y6TqW@LlHѝYv)3@V3"Nd SZ Sem8'#AVr_f3 !e+ZO*e/U6ÉA(T„jϐ޶nqN-Lt%Ԓ0oF}n_v&vxuE-d2F2kd;kC0$!-<4NInT(&D2fS *J]eA w++ٻnTV]u R@m`U$'38>bLi (ƞ4C T[mGF<z8fdYZKP5R(T +}nf&ϲFN 'I1|9go.}y|dLE*'Nh[zn..gq5DV$@Rrt#nU sQ>iT]À^'Q&"zʗTc8Nip3}öX7vOiAy  di sQ>iT5"4I%7-p9B}>F|rwU-ZZXpZS@'88=q%UcS XmNEDNdNxGQdSQxQގx!(gÐeCO@FA N`d 諣ϵN-Chl#8VIY )DŽO~U^<#(okCI<+` Hq%Լ)jICΕ%I yXxʭq7>ҝbku%KDA 2=:xZx?ӁZ&ZXCV@eP4(A A[ìt1-lT)¢z$JFm.o}4}qR>x9Wco񢡯\UWPI) Ƥ$e')9Sp;Mp~mIlRAUȊwo}4}qR>gQWc诣60D6 zTJXlLDDָVHԵ}Tmjo}4}qR>gQWcT._E})A+=sJ}n8zh-Rui9A)ʤ^:GJMޒRђA|˩F/2pWfYY !֢))+R*ƔFgX'\gYlērx-K*R3ԥ+*'4;o֧;o֧ee>[z*؜+ӌ)ISnNmtgml(dKR+%S |'m4|'m4̺}8 Zxj$d-AҤIvT’|'m4|'m4̺}\iw,+]"N(0"b4~Bێ*t$}Uw"=#U=#2Q ;4V0ԆmkJRs8>mk8iɲŠ $l7#@:<1@;Eh2$:RZVӁiԕ9 }Q@QESξPVRJ50܄I1qr{<>b>S$Eq[ %@INj*Bq#9bv1CsOmf-,BL8[QIS$!!; Pox`%DU-LP+JUIH## c?}ɕVc_z2((Wgr_U¦?9IERg?i=QEEPM8#'Bi?Gz((( M3~qRGsQxQ?8KG5^@yE{E7~|շ$Ib*%,q[%k %)ǙVn΀忩ms۔ܻ{Fi%]- [JչRQx&bzpkz1&̋_ Kߛj 48+)J-Όno\ l˷oq)!5uZ! F*H 3R=#{ѷ*( /^+ DsBc-OPBSȍEQ|qiP1-[zFƱ$G*Txѳ"SNKar :S]a^iNsP [*aoER %\n}+m-”rZ]'|p2ͩCKtH(NRGuq u{(6.M0\o#[.Ay㤐J; JIdJlgIUjzۤ%="Co5n-Tf @%)PIBӝvy8HC&w}Jv b%CTTvZ]Xq07=ا&?'0xHw.2bsnm49$6$c+Ӄp<+”b;t |?wo!Zeb=ѐkf Y_RZv\ߌP2ɝs-R[S!֢P MzC-]aQRk49Ϫ)J'to4lV%]Chh46ByxT,Q nIZL,)7ɲCK)*q { f3¼8mʀ~ ^,} ^,f.{\)@[3I}'HV#`IԀ8ngeǝlLvZC.ã-N/Y<1}#9Ϫ<53;ߞE|cߞ|{<K ;xQyEb>ǻxQyEvo  _A"熿aLMYOh(=VXˣ’R??]u|O}US&O=>*j/ni* 'Ɗ*6X2|h\X3V/G'b.]U&78O?G/d9^Zϝ<&?GkYcߪ?_l8mO^ZO+ &5賜S0 >?w.fqZig3}) )N:NGddaP*opLȝ)jqOFZ jk?juy8ƑU^y?-sWk jC,ZPָ–8ЀQjV bje37&䇘Ca/:I*Ga!$s޻3Œ 'G=4?2EV#B( (8kyO\5Ot(( ߪ?_T [oi˯ƶa|>kj~Ț('QEPhkg95賜S0ލ >?wQW`QEEPQ@QEQBW5X:p.@r#K=5 [I(ԞV@BZ 6ɠ:V7J"SD&̉LK03/Ys (m0J$%$1o-  PuʆYR!A>@7m `}kOW&WZWUY3([]oҜ@O7Ǽ(}|#_\@i}|#_\G<%+w<%}|#_\@i.uYG*i<%¼jx֧ \ԈN'.$dv?U&8sƓқIέ21Փeίˠ pGvO:q_S> 4'KlW_՟g=M_aV~>W_՟5~YhM_aV~l_L(TV-FS#С yԡD>Y8Q<c'ҕ蟦ʊҕ蟦JW?~*+JW?~=)_hnΚ}n' c$Lw*J\):6$w("IcCwެ6Òg=qBuRB@PV6`~Ulّ\-˂[ S8ڕգ:BF@tۋSW"QHr qRS0aJwI}QEAc XHZ͓>ޕ>CaZF`G,怜T'tybjU%?"#|Pڝ899u`F|%Vϙ+EKij3A=Rt[@/*%ineˊ&L[\Td 0N Rv8ҟZu sW2lq24ARPU@Qj±+eڧ$) rY zX+ o·-1,DVaC-f&GY8y )#l@\4TG:@::oWia)q+INP`~ˋU~%KԨOM b[w?=[w?=v>`Y~\bUnpGnpGӷ}?Rcrۿ!}rۿ!k~O_ȦZ:nkBxQ,#F07McO gw%y]T|0_ tjm%TtUO gw%gwV_.4s/nzu?GY<3noTttxUO gw%n:|4֣q܎Wc}<ӊ=}|T]P, C*[kRʎ{|9A˯*NOw?:UogݎOXh Yw,s꿭~oh Yw,s1qFՉ&7w9A˩7 Aĵֶ2*BP7ʥϗ͋Ѿ)*=cFj ?UgVʭXa_é4f@Z_Q Wk}a_é4f@Z_Q Wk}a_é݌uoXUwUi6~X-c7 u1f[V%du`ge}9x?o RU)BiGGt"5*x_?~=lO蟦E>%_W{bD4}/Ԋ投z! <$6hRBW$,e vB 3>N:fhQ:ԶAnZ)K5 @A8. *)6.fskaI=įCTygzQ@bjm`)*{@/8!D\ " 4(@[-(cp1%]=j H*_h[oO!`VDZ&Oy,)םZֵ$SnlJ쿫w&g/PQ@QES~,|~4NTbwi-*Nr% ((GySΏZTQEQEEPacT?L;g稄?ӌ*TG~(((59LdȊ. lIA"xg|@BWѭpp{KEԭc#PVQ'skZ&vt;q)?3@HJ JBt3Z(5eA6C*Q_ThH[{[Jh)b/eT4Mѫ0덥A VGA[wSC;<߆S#n51r\ 鶸Hum{d>>{#O#RGlqnv _n+M.1Wթ77䔸uJ!8aS[m"E-.*ASPڂ-8RPZ#5`@@K0p Sn%{``Tn_@<6SqAmGaPBVpW KB,p ;EehBd8JmVGeQ*8z9E{EzyE{Exh |i?:Tw4H8} }2tXΑ.q04)EEPQ@QED[5?~һ/~ ƔEPQ@߯ (߅M5ӧ~,|~4yXKJ?Ih( (*y^_:ּtQ@QEQEU?8|!ʧ/a߻?=( ((A{N?Cz(( (((( ((((;םĽ<-A袊(+V__?^ל>xO{_ӯQEyQERw#“ҋw#§ODȹ8qt G:wWb<_g*xQEA(? ~tI[g󦿸z\+ɞeQEQEEPDЩO}ھz#DЩO}ھz8gz9EWzEPxku"|i?:WpXaEV (((( ((bk߶qv_ջ[(( ()Ӄ^?Q kNxXF*h ;˿4^V'9wQ@QETּuGy((( N1~qRB?O*_#ÿv~z]Q@QEQE 飆A{NEPQ@QEQEEPQ@QEQEEPQ@xş|誫WO?}w;z5y<[ăEQEEWN#c;߸~8 3}x#^(,(G'#§ODȹ8qt G:wWb<_g*xQEA(? ~tI[g󦿸z\+ɞϺ_!eQ^Q@QE?DO 4ݫB?DO 4ݫc9 3]Q^( xk\pwƓGx;IWԊ' (QEEPQ@QETPt&&eo_@[]P%C;i $ JzI]o#9=&0jj[FSl K/P8k6qU]*4)8(HNH w—lH^kR' CAȽ͓SjGSAme\d:`::t';8H!*ht%23U a)KqW)ӖV):2rBB |#ф}/ /-?ax`)[jߗIW}5W;m,/e x7Gֲ<cW}4}k+S>h,/e x7N\) GٜM p(2+w>UUӿ~l?}"4VmZU9®-;gIVΝai7GfnP?͇IQ@J6u6X=WJG638MLB>#ʩ:7iLP_D`jM?vԚhwAlI(D`jM?vԚh| lLpvS*T@sZ\Xݛ:K12^uaBG2I3UU{G&[K0BDqJJTImKJRV).⮅"[xRː{4u\)KIPBB`@X(.\XeGtMlѤ Va+c,o).]vbJJqG B=p&hތp\pTGR]tGi@Vp:^ms;/BUM4gGZзsORu)uFQ=Zr)CJHdRFI53`4,\\yڍ+ZblH*JH\[ùca|+pM|pLnm!냋~n$I' ʸ#w>וjtjUϑq i-yT}_ģl?V*q i-Պ.'c>KE<>>erO]b-WxjjeA;uk飢5oO8T륒.fzExg~ uG uO=ja~h~iGZ#f֗~ u[pXYd]I8<[bgDO'$~!}4+, _}9!ŤTH蘭XA?5jgsXcξ1Mv\7?ÄՓsIVcqchOV<ǝgEோ#Vp^ҭ1'?П,yя:}Wŏo/?M>xN%`-rP2HJMqJ/kz51U+i.o-$HNwuN#b[l\*w*1^nKB xF6?;Ǖ i|WA>/QxF§xTa/*8^$¥-SU!Glx7pX]{s\KS%-};X("wTb_,^] Ց'~ѿN Sn|;X(6oRQyb ՉfKpHՌaYKne*s0͔Sn_- &DV8rKNG*}33i=gk8TJخm.#?&z-R$=9Qh NxN8M  ̋,eBn.9&y+l*[c+:9@bJYDi,BVtnッߊnGphەN6bJC9`o)ګ8E5c]L'!0}3](9PQ@`xQE`xQE>}^?~~mEPQ@_[HE4S~l?}"B^VΝpt$ ((֜Ͼ)Wubtoә?((6=TxTO~_=B~?*k'˿vEPQ@QE ?d}v4S`x 0<(0<(Š(ŒEF`x ( 0<P`x QE`xQ(0<(<:px=w\Ӈ|^>?e=mQ_6\QEQE?7^az/S|E|Т+- (+l_L(V?'e/=xEϻ?=aYϻ?=a_cS5QY Q@' ƒҨ/޿/*(B((z8/Mp_Wz:+)<+ QEW {)M&S_uS  0<W@0<Q@ ( ((((9mW;m ((~ z~E2)+aȠ:pt$wիi%QEEPX}O઻֜Ͼ)EPQ@QEʣ¦Lj QSY?]|(((  #OtSQEEPQ@QEQEEPQ@QEQEEP\Ӈ|*?e'^/Q)Chࢊ((-Xׯ?SDkX߁z8W/Q^9hQE[bgDVؿQ?8)y:.G} G} f(H(Q?@_ݧ4Dv׷~|Uo4EWQ@QEc)^oǬS:u _M]Q^(5xh0~Ji4R 8{fZpQE (((( ((>Ov?\?]zö߿ff;W/Mn z~E2(~\?;I)]nI@QEQEV'F9|S*3@?QEEPQ@mz?𩬟.ھzB=TxTO~_=( ((AS2p2>|@QEQEEPQ@QEQEEPQ@QEQEyWt.?>zsʸ#w>׋ƽ|"{(nER(-Xׯ?SDkX߁z8W4QB((M3~qZl_L(Ur[#w>g#w>~mO3\|QEd$QER/KJ~1o22i() ((ǬS:t=b믤^*4f2xk׵{)M%^U_wS (BEPQ@QEQEN'lW3Yv\n%6ivje/_hq) $륤4À8q;Gjf+"P( _Wy_ۂ+ecdp4\GHqBR22U=p2hq2QzVNJe,~Β}t1ÿ=߫/}T}t1ÿ=8wvEҟPZ>SQ( J;Cj$pE.!:m,dڲ0f?@LV/_[˦(/U >V/鶊m.U mxv6:~ vg&V$=12R]WV#§Ms@l/Uc$_P },~}4zX*i5K"E_M?rEME)Gz_=SmCd;:SɌ⣡.<KhR+pp3߃L 5?,924[ )um *J4 +إZijaߗ./!%@Hm ՗Ip̛̻<[D7(! \ϩ*yA%:O=Ho uǢ=HJ’OѰ5pݩ-~SGѭxBed,s{?82;jm T+I=Z7Tf_`-վ6#1 4ی4CqqĔ *-VRʞ[o/+jn;:q+e|?g4^ QUq%ndfZ5Gz?5Gz(oEYԱ5Gz?5Gz(Gyu,a/foi깢T`Կxw..WH|+8/Shm@]'PӁ"izO d{-C_DI{/sڻesR.ɖğZ?7$ GIEz?d8?_)2޸3ŸGğZ()OW?D??8q/(:EÿSߍsIeK1"*tr5*U7o|kl.TE*Z6в.q~miGƟlٗuZQ^?؟T~QWe7e]of_iE> QWe7e]of_iE> QWeMfAbͅ- v_yqzsB(i9hDbi/.x׉>|5XFM;+[[,jj߯8?ԫJ*W gԕ__GUUPGPgԕ__GUUPGPgԶ6ξSOTy|*eUBǯ8zx|LҊU^mW8jl*,r$}&jpJOg@cP/M\]{]ؖg/40۷rLD)㋴eMb3q:uH.5:AV3RDKWr]1U۾B[H@' s,b$8oŎqDG^`ƒLx-֔QC9+B*NC/E[Zï[y PD-n$d:I/}R|P2sVqnN$Lq'%-1RJA_kj'JRF@mw.8\b1kvv IZ]xh@SËY j4 7#J-1_qRPAQ'o:~ץ>۴u.FaM*SA jRRx$%eymG$tkxux;Q(ڒ}j!V:F#H Gpe/<*Zla HNJI&QEEPQ@QE~¶@$WWx ?\@QEQEO\ e}pXMwǿEKo߫/}T((?Y~UiV_Fٿ| Q@QEQEoSQ_9B7o((($ 5?'OEPQ@QEQEEPQ@QEQEEPQ@=}GTƟ}^ Q_LPQEP(PW't?j)RW't?j)_MYE_8(JŠ( YcZ GK,PUչ)GL⟿2 T3~29_RUF9nŠ(dB( &~aMUkM>4">pEWΚ( (?'|_Wg9sƨxߦQ?8?˟5O>=zqJ~\i ^EEP9~wOI &+~wOI &ŔU(d(?ը?[t]_1[d)/˨HQ8̿.?/_$c(D(_o$QVD߱?IG-QE|(( M3~qWv?ji/_3=5?䶞CEWL(( nw?cqз;j8'#U?4( Q@QEQEEPTyo. Ԧ a+0o%;υ.̯|[ E#8%;υ.̯|[<9|?՘?[W_|-ߋtwu|.B_A8E'eu G Qm,%d)/˨[}!]x24KwaN#L_'~]~8iZ7ʹ  7uF_BEO2N+`mF?2N+`mF4~(8O_@hI,ߗGI,ߗOC'/ 5kM>f8G~]Xty8n\IEх' irBhm| L*PG TdA}aڌUXw?^XO/gb/"Tgÿ}e" _EG-QKgj3T EA 4_\?_vрO>#rl3ݻu rP̤ݚ5άf81]5dvwݸ>n?*룾M[4QN[G𿵷ʨy5oQE;no [M[\>;սGdnw?c{tzYJj烷:WqiFx>H1qV )|3eA C"BP8)'''avMt +, l/Fd!8=$J褰.P'!LfNCiaCBP@ޘ%a&H[{Q2))͘|lP+ʽԟ+m)kZRDZ\`>-$6e6RT6 @((%(RJ9o q_|e 3lFa\XKou?he*XG590"7x}Y6Ryh#=vduiJH J %zПn$ qJZWRTPtǕJ<nT6'Z yU߿BEpQEEP>{߾ bޏ_;/S@_C={4\7?~T((.Y5VեO"wTEEPQ@(E]aL8W(ˣ¬)Q_95QEEPQ@Jx5>iĆÌ$KT?S X^'ە?eBP]g)ըh%gӟ;yzjP鑗wޓ,Aoeĕ)X= 7˼? :9wH(iDtEτj(N@'G~'V-e"8zO-TޝG WPQ@P]/GpLLZ:jCm `d*/(x_Ukǝ Z D(A޺yA Lh8z%"3$+C,l-c't2\G)ۆ /ɞY~qbuf -vsq!##lF+?Go&\H$W,IbZOP %HIԔӂ#|3l7;tvi׽1% 8Ci qʻTz%owXR0+Ƴcs@GzWqΉp-ns$&4%GCB)u%I;yS?J\k.<pwb hZJPyb 0<(JÜkw?vvsZ5P0x uĀ ;(_q+MUΌ IOcHe:ٔJBx P %؞Ƒ۷Yf.<) iEMPrNf׸wVTaZK\DrK-i\2:ʰPL/$͖ MQɍzאˮ)KdN~XlSa#3NFe0ZJIXqN77,FᯛT!}9T'}ᾑ 5@{3^Q@{3^Q]?="pOw"׳=_~,3Fh԰fE4txRjSjS?*3Y ,2ۋ_|"zM5Ux/4QWdQE,, ?N?ݨ=NxroW=#/oG QlxG<h_7c>?U8B'U|n'!#ǥQ^y(P+ @Kz:~:T?3OS ~!|zsJd\DPg\ٟt\َi+j:vM]p-|ebPd뒑*q *P gmU`xV#*>Ķ۽nN'Z+uBBY!В#Nj\kuSv%yn8 e;낳Jx@qwz@zpɇCM;l;-k} 1l RGh/\{C`ݎ橒-2Yeu!%ZmCQGigs]{|/U{߾  ߄U!C={4EPQ@itSȝ?.Y4( ((EJ/ gWjE]aL8( ((S}EQ/+R*(( (((( ((((<5_x=}(5_x=z<7?>^(d((,.R]?=O{#?QEzQERWOIMN'dg?ׅU4ӷ/_|" !G`OW(QET?Zw/As;z+=#}QƊ($B( (ћ.?Wjof| ꄟU񸟤zXx?OEWyAEP ގ4?L*ƙ㩅|ĿGq_KAEV# (((( ((?-<*Da _c" ((z=XM1SG/!pER]?׿C@QEQEVE?}Sj;@H袊(([T. ~E|o_Vӏ(((%<^WݏU|" (((( (((( ((_5Oٷ;҃_5Oٷ;ף}#=^e@袊O ((؞'E!#DȤ5Cg=aEWzEP)~]ڿT. F~k,3x^?ESM;q*k밾 } |(!EPNxroT< ӹ?7⾃޾h8ݿhO(([8B'U|Fo*иIU_9H?8ǥQEyQEPh-LS¡|i~:WK|wԽ$QEb<(( ((w/H#aM.͚ĸekZR0zW~4gn雎D;2^XYs$L>}}?g⏯G ;3P}ÿ}b4h{y^6&S 2ܣ8ؙdph C\7?~ToSpf<5)22-[=Α}vFdƠ}vFdƠ}vFdƠ;Udoo FOjz/3#漞G %[I{IuN{x|4%.ģᦿy-w%Q_Ez)GM~ZJ>kPJ/ gWj o6T59}!.v}.bD ?Ơ[=5bTzj?p+ tVMG~U1}]Q/_G _r*?y?v>jT{1$Zk #;M>KSȌ㶗J B!Jdh%xGE 5u.9H> hH([84<9WpPnQě5khc[ YH8+( W[Dkqm؋Pʽ(:4Ķ7OVjpU DjK!]@[n 6 @n\=+qSxxr32^aX #WJd% BѸ:qD-ŎrYfV].i9]Z N>{;lh 0 q ʊSV_xq])^%Cv&] [cI@ KZP*mٸ"08saEHu-iSJ :w섑7I~ nľۆ`ChV{X# P|vhTW$ޭ`'q[s/I+ng6[GQ=[EU//קK4}߼F*vvKk0=+Q>_z>_z.f #DȤ5hp44WXmxٓDhr7ڶ? {ƯS#NW/$pʲ.~򪢭^V/|u? {ƭZC[l?VҿR^V/|u? {Ƨ֐_gU)~D]fu? {ƭМzkOZdme 8~ 5)_^TWî^8qHpenDI Xa8Ҋ˧o"aoun^>>×̟/Rt|??=t|??=t~2DJҿR9O֕Rxg7ǿ.{viMdjR!+^gXxR5{JkF8{1}j{#Ƭ_,?QE'󾶧?3GZҿR#Ƭ_,?QE'}mO?O_]dxёV/Ohs"N~U>??Vԯ=Y$*DZls]&HqJ%dJ^f;F_>iEo3QLњ,P?pWX> pޒ/ԌfԟР~gޯBzyd}W\7 #& >}4z,#}%_s?u0.f;*a gI?OcgcR__QUwJ}\)-SZH"DżJ iR= t ma},LFiI eI(A #Q }qSQ Q+ip[+*dԔnU1 }*h ?\_T'*PQ@QEU tz:#aOPZ(((H"oʯ5[U!8o¬d*((%^_ݧ*) pyvQ3 [xf,..{jxm Te@I=2qOE-5Đd"dTMGW&; Tr ;(h8PI#V[.`8`Cr/WiZ+Byj1&"Yll-ă :[BBR2y-(##Q@VwΊR%[q/ St8Z{꒍ I S}]o8ڣz-6 rb-<1,`|ܢxâ|O{u]_OP*mHm:uIi wY5z;PYÓMvkn)zz,n3S( N/D\B[įN ,<Z39$,!zU9^qJCwݣ\۾-ǘA BmQt`yE^蛇~%B !ւUvpp0G Ap]D ʂEHSj**$߃S*( zEtnmqhW/1!(qkQ]R*q<%o$0liҖS#$,vq1k\Kps}m12SN*sĝ*:R2Fl60/GiQR]܄uQ⩄$c P+[D( h*D?]5*_BO}|c⯾N| 3~>? +iaEPQ@Y}~W1,]~W1-x_3|AEV (+tӱG+Mnz?fYKEyWKJ?9Ik٥GaEU@()#tutOv/Թˣد3ޏo}21UQXϤ ((~=J$~sQt|tQ#ÿv~zʼn^xEVs ((<7]짊ge*i;8s_¦u|H)~.ϟ"QEEP[O*c?%(( (QkT &sUR*țvG( (([?~jTgK& (((( (((( ((_=x=} =ُۧ9֜/(D&(ͅQ@QEetq^>tq^>|ys+QZO(OGUA=TxTe,p%Wy#~mO0* QEbK?d\lWG>|(gQ@QE>:~|(a߻?=ECD'_Cx3]QYl(A8oOx+\pŠ(OP((( (((ig&?+}g&?+QEEP?tw pXM0G}Tw~.ϟ"/O%U ((c?TltGŸ?$QEQEEP -7VDӲ?_jCpYNU95QEEPQ@KxORjyvEPQ@QEQEEPQ@QEQEEPQ@x{O}s篡'{t1W'>zӅEȄEͅQK)pY]~W1-}~W1,x_3|AEV (+tGiOGUl)yĽ/?9IiU^o?i-{4cS(QE=ؿR.)#tuu{_&*+aEPQ@z=J$~wQt|tQ#ÿv~zʼnnxEVsڸQE P7]짊fe<ו 8{aEU'QEQEEPQ@QEQEh'td  [Zo NV@\M#]}0:n's.Q@|s.:n':n'ۃ~m_fKD4u~҄N}[B%I$áM=)Khe*Y oH1cc?]E?Iʣ?6?3UPSt?1cc?]E?Iʫ3 ϳd9r%:98]'EC`g`MXh޻'zȟ_"~@1p PYMuek=s>EQEEPQ@QEQEEPQ@QEQEEPU,/E Z ~u=)I;dWdQSћ&*3pҿe??0)Wx`xQS~՜O*3U`xS$>՜O*3U`xS$>՜]n໕e7%Ih iԨ+ԟ})8ԷUoWSTFWl&&y)^ߡ'~*̓xK]_`}i|WrI߼ʣ$?RWWFƯD>`}i|WrI߼ʭz'JejO7z75_$v?CQiKBp댗-'Zw;?֍?M[zhZc%e%_Äթ*sm>ohѿ'oMk^:/į+IOG֍?M[zhOq?ʾTZ7_D4jiȘZB9ъN3^HՃ ^i ku[+.?M]r>1:.ח~' OV=TcOC.ח~' OV=TcOC.ח~~X>*$n*C77v O%-mrF G*Iw6HnWHqOUaHiD΄qWxvZAd6@ iKS`r4F?l|i<+ȵǵ 0#\6cTV 'zh#߸Q Xuq䛋E䜨98r80%4v;WZ` 9i8H$2I$&h( (((( (((( (((żi*1lVۍwOXPίsQ[G)xx>")T!k}ۉPP() HhwqH"Ė8er^9L +.v4tOg}s#x8&5A Zۏ,5+i լo+)o~ng݁=fi C4VXqAd)aD(9ޜ8_7{oKK$z:CR #b җJ<9"H􋌦i)`8R|D+O37l‹zum\t6'`#u)'#l՛s[R-&Gn1 Q[ZՀp{.,oyC'tya렽sXiŜZMξuJ[)Ũ̕(K\%lS6ӣ\#qhBZlYKv[N`ts!w2m2q-ΡֶyëJZD%(uiJTӚHJ4zE߮9c\RnwM!ǚʛBPp)nN9U8a&t2}ŒRG4) XFg5?Ύe:뛷84~9Ȯ-1!ZFG78![-aMp*'tt^f]FT{k/6q-z\NPJR5lSlAEՇem6RN4%JJ:2@RNTF;aLUJg:ۓ_-o$6D匎-vN6I.z p6R 8B qZGz-|WOp^Pu%K]l7VÁi J00|E!mJNHDwQӄ5Ԩ`90:͌SÓD9YQ^)Δอ>qdOHRT-G* 't0KRƃ.\jTaͰӛr10j;5TW1QkRCbZpT @|T"ل52S%G'8ƒ Q?cFalά*(( ((((?ippsample/examples/validate-job.test0000644000175000017500000000113313240604116016615 0ustar tilltill# Validate a test page using Validate-Job { # The name of the test... NAME "Validate file/ticket using Validate-Job" # The operation to use OPERATION Validate-Job # Attributes, starting in the operation group... GROUP operation-attributes-tag ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $uri ATTR name requesting-user-name $user ATTR mimeMediaType document-format $filetype GROUP job-attributes-tag ATTR integer copies 1 # What statuses are OK? STATUS successful-ok STATUS successful-ok-ignored-or-substituted-attributes } ippsample/examples/print-job-hold.test0000644000175000017500000000170513240604116017111 0ustar tilltill# Test print-job and job-hold-until attribute { # The name of the test... NAME "Print-Job w/job-hold-until=indefinite" # The operation to use OPERATION Print-Job # Attributes, starting in the operation group... GROUP operation-attributes-tag ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $uri ATTR name requesting-user-name $user ATTR keyword job-hold-until indefinite ATTR name job-name $filename FILE $filename # What statuses are OK? STATUS successful-ok STATUS successful-ok-ignored-or-substituted-attributes # What attributes do we expect? EXPECT job-id EXPECT job-uri } { NAME "Release-Job" OPERATION Release-Job GROUP operation-attributes-tag ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $uri ATTR integer job-id $job-id ATTR name requesting-user-name $user # What statuses are OK? STATUS successful-ok } ippsample/examples/testfile.txt0000644000175000017500000000734413240604116015745 0ustar tilltillAll work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. All work and no play makes Johhny a dull boy. ippsample/examples/identify-printer-display.test0000644000175000017500000000107313240604116021216 0ustar tilltill# Make the printer display a message { # The name of the test... NAME "Identify Printer with Message" # The operation to use OPERATION Identify-Printer # Attributes, starting in the operation group... GROUP operation-attributes-tag ATTR charset attributes-charset utf-8 ATTR language attributes-natural-language en ATTR uri printer-uri $uri ATTR name requesting-user-name $user ATTR keyword identify-actions display ATTR text message "Hello\, World!" # What statuses are OK? STATUS successful-ok STATUS successful-ok-ignored-or-substituted-attributes } ippsample/examples/heartgears.3mf0000644000175000017500000121266513240604116016126 0ustar tilltillPKF3D/PK F_ɏ&3D/3dmodel.model]ǎh5 #=CzA!Gosv` $9y߿_ӗ=ܓ>/?3/OyoO~|9_#'߽?|+??}œo?/?O}g}/?BЋ|E{O?'sO.~g|} +>kJ}IdLJ'?}ˏ䇔Bz?_y>_/`p\Za`tЖbk{'%̞zfxZAEhgPbPP_|kHkm32F֥?Ԛ/X:~,0[\*:s}*w֖|W*/vamԉL5\b)ކ[ .*~ʃ/!pc+(XF>,HTb7pM~;[Y\e)/] k!Đbn]n!ɁI*3߃+b~$3ľߝƇBfPUwZe~ZױEfL~CX 2))URyB/\f6taxk'd22qy^#dp.;~rPmr~X?/HA= )J)jEDl%~ef t%̖t]?gzy&(emNlYnH-秆$]_Sӕu[qk8JXKuWr}__I\mY=W(\Ԇ?̬֒9|>ҥ.tuH?: '}󏸸d P.]Kp.J 1O%-.O͓pVE1'=GŸ]g$=ꞑt32)TpK- H#]22/w~& {$[1l,lXdyMdVwJ3cԦ g#6# M9ai~"34om2Lu"˶p >LvBCShn-ea1apNMtٰ .+m]=tUH'Nm3Q4ѝtݸ ,"a[%=.$bwy8U86yp+M tgf; z7iWn1H˙~dV~toXbkh\ 6`3?ݳ@ƁY,]7%{g=zM&":RIߢTn%5&P7"a8il`=e"Z"/xߢN=AB#2pE@;値B773Ѥ2ĨS#pD&dm7p70"҇5?I"e]#pfiU~#[<޶)r< <ؚ0XrdUla$h('3 0Ϋy5̂-yIM&B3"e8Z%HrEeUot'$i,H|b$2\ pi(Ŭd~Deh{)g-/\Epz)/& b~oI>.a! 2Tb>!ǜ0Gd;:ԝ~2N`8\R -31i;,V"1Ao͌d$v~ 6`q6u!eR|F$ILN;;D)ʦ2)v2 !@U\F\UY~F6$"]H#j0;qn˚`}8QȈMk̎E&ܥV1ZHܛbxV28`5TJi7` ľS`7dkZ)lyl9-ʀ̡$Cؕ Ab #+`u-d ;f!;- b^D"<*y@N1zD80?GǶa[ˬL',0^) M0E$.l." &9 f%n^2"#\u[{bʊt,=9?+h<$GsFd\K{>Պ@Pt[6 -kZ2[̝}nԒpHB6~m%fyu0RY*\@1Y2b>nWɻ]@V$ZJDU歳"yJ1\R d#2N_S;H"`Z:*>:/S}Via+͏tT[y8EbӈXJT#(ItAtkY9EҘ+U[s0'B@f+BⷰoFT=960"W6:uZdwA\ag`H+=%eRDgPQb%"#+GXΊO4"]$~|f*8ur5+ӆpny*2 aE-.2]Hr bAxQ]Z`>̪S yCj9Qo!2ݐgFTd/7oI!26\z85 Тz]C M!L]$bʒlKNAu i#efn0YA$[YY^Vv%'b/q9g\c%o[,j$<]P&VL.C"6֛₫} 4eRՈ[ŝ+U&'_yDJ>Kd;B HmO[eM+ ˵9Yky(H ;tZ$s%H .Yȿ53Sҷ=,G2 D3 ^9G7Hj1934 ѮJNQt1,#~Q벖D;(H4g`/ $Q ҄-#3%Ѵ"-gp*m<=+I+L^x2,;|Ty!=\ Œvd3KTTG/\EPߎ&b^d8eF,.uŧt B@[?|eֱ(,\̥!]s[ed{!IcA hzAfP!HV%uNr;Dh~OF`_fi9: $ֱ(2М?).#;8Dk"B(]@+K$\.sѵ`T|W3/&ƺd2 . H FPE +*ad޿.F3g˥zJ%<2CbLEnun)%nܓtld-]%F{9Wʮj729*VY Q|3h5O.YfkHKH!/2u(V< 2#dU|~| )7PX"+B[VGSefM-Phچ /۽\E0 AqW`[` hMry8ոF>-v/t] Fc3(bڀ:Bg(Dw$S *Q:E&QGO5BѪii=1`coQ<,2ZaR"EeUa@)hl?ΰQ=( m]P5om ٌ0L5lM -c+w@D 6mG2J"* Ƌpy:,)Q/OVR/)r^GJܤ b$``],Jި(pš$."ƶ༳MAp1?q2j7VuU3SOe^i%&*1nhS#F%d׼SDse&ZL],} y%X;J%(6D٢bSnD oV9ȳդL/\vy\KA>H%J1,8eAE^.OG}:$h;M`I$WR\Cz^SF8;5p&5[ M^5%$$5o\}^%j e@ԺN_zYccaV5ZƉgŕ᭝9ٸ+j4afyGF۶\Enp& h v uU6_P+Y)$ezVA hcꍪj5Áʛ:¸jN j*0 x&v[{tw3ۛ]# (k~"d6,Bz !R7כHAQh1BddwBAqsk1UwYNWAc2F!"~͋)qJ. R`rEďhFw&ݍpѹ2m!hGrzT|!2HThnAVo58\[C9mizmbe\[@KfFփG[{F03}0*U2ȂpQ`'50WyfHeGmJMx# %~hU$\02>4zc$"vG(۽kY/ZCJQ-d/B֤[kgI!gը{WӚ a ˔ۅLl{-,Af/qj<kG[@^9; >r,ƺ-^k蟢{_R_Kjho AH-=#qAkԶo!i60㒐o0Q]ǙsRr#HdLI2;=l q¦/iic炧2Dqsq$O0.ӂlDFz ^0cQIuv'ÊĻ+f5o(0"#$]柾Pn#4B]0 {+ON& %EMߺ ]sG@_Mrͯ@O^Y[|I'AM2v2Ӗvg-BT`y.z=3T{iw9(tCX52Vx~O{'L,ncO,Pg~zl;?jiC{jަ2A'Y&"|4!\cJ0l ř0}}*H@8tvơU%2Vuy2ۣ6_#sŋ➦lskle0J}r]TYRleEț¼>YBo吀h8t1KdzfwlV 6Ÿ n\C0qǫ,@Jio=ł`bG̣g6ϙw̮Mc5nҎ^V%{|b”c)W n!2؛\`_ON͵mY\ IGe_5N$l}]QohE'q'rz:#OSْM$eRQ8[)w^Nk MT`:?^<5YkĊ= hGTܚ9rFCM Hi~ }trv@3AZǨyOW]̄]()~H 7C|[}]x9TgțΣ^s"g"G% =!H d[-oiςx ~?@ %ַB}}${kGό$ݥD):? fBr1#륌P$?_ wq C!ܐ5ahF"^Unl)W(=?VZ(s}1qF 8YABRڣDF&}mn8y Kؑ;A|Ur'4Uh%h2sXy/Uu5Jt8La8"3bRn$Df 7$dOZghGcYoF7D^_{(Euej4Կw}3t *Td.,Qٰ8^@"ª ;Iߚ/L}ZYMR 7`(}ohuP;鼸774`^ݚ\/;i߽#ѓ"$RH{CGfF_aiH_LWuoTith{KM[܀I `q?IևsYf Q;HE"3̀kU2+! c&k@"3PqK`^"l7uJ =#1VƊy9(]Ai*t0+yCjAsއ{Y>l͸|;VKэ 4Я h2ҥ(7Jŵo59HF ƞ.Emo-ĭe;n=ˍ"ZN_֤ޔݘˁJE)C8Y3dE0Zx`zTB It[/os !@s= cHeAU kc'+ ?w$4B/l)B߼0H%h;۶?=cKJl.F ҈U`=`a#)A+wi 6x}#_J&HٱNVv}ԓo%Y+Dz ]2e_|:-8*+7ܦBn'Ϟn_^GČv܁#;B;6-4mg%֫>c-o8b-o-fA_5fJ/%q8#9%"Dj`-U`1DjU @K(icʏ$jƮF*-,Te4Z3 %䋾oOp.elp\_/ʢ(i xQscWR*-!h}F(W­ޘU#We!I^ߦ7591z910bȇr~ذ{~{^b]#X/r{5i&lQ$fW q%Fifeb=Ew>(ӡ=w,niԚcٵvk+1]g%MI^sf;,X (E؉}a+u񎙑SbDG-:HV-m %bLz`gL I`IH+lsX9ouS3Հ hM&^͑n.ْjE왌73ħc`µ t!…ܸ60s'V aM=;ٰhB. ܟdaA"*lV~L8Ű#&_[% @DX(펔su{ {S4EdytM"I:<7Qtv% mҔ+,,B\oq )8aD:5Xqv(J!=ozoND:S`vytr4IM_Z9.ӗ nOCXK|yLĊ#]e=+gO=zgFGn˞Jo9ISLHuc~mӔ= ĭ6e ~WUXܖ?N:Omj>$3Z͇ ˢ]mlv GYB:jEJmJ!Ȱ<|mQ|^s1 Fv|ySۏtw.2]-G>f`\&=Uu{|y VE\WO-"Cnp^[ا]^$̠mkAR2L.OFledmod "ך4i!o/oMrShT~S`uibHAdjES2SV4hvRh_+"A^|]\/tZ$s%=DtM_&hM׮?6/ɦ AMyzKfAVIeV5*2o3INNjK?*yzI*7KԸdve3t[2躉ִH\2?'utvV7tkҁoHu,;:KsIpr}Hefoiee޾?iL % |t}i 5= Z6y[SxyݚjL y r˜.S~-pK&`M ,uiHakM7eo+dgė4n.PPӷ/ZӊQ]ɚka@{ ^".+˝@@PL&MО?Z!d-=Zڢ(ƾPѕC^YW]jrK/ _NUc)y0W^D{lŗ ݊K ف bR䪊-R\i/Cc_%^ _CLF8$5 ~ 1"&q%rHY\Vʞ&@>1'i$ H'Y #^|g5 JH ""]VBA&Dw2m3\}P< RYsr-Iu8ԩނLYV71 l^$aD\c*HO`nA&[|O 8P![D]B=2vE*~ܮJj`ٓ" Lv? 6C pUvo >ݥi/3X&oI'ti ݿ~v4)k ` eteL/{"4Ej>qxKqx,a%I>徣 "ۃh$MF6yϽ]-?;c({rGk H9={ & @%eMdj ɼ?>k_R-Do<ؒ)΋,f1E@_jiAuFQb>WbE.jO[{]PO0uiB ur?>1]I pPy(AOYQۇuN?dK2 ja&\R]ޯJܣ1~JaWԂv J%lAV"$f֓T r97N1j2PI>ˣOT=)qO6Orے+yHÜ6L8IW0b!2עx^W!a܋$ MqekeޢAHpwGn{,{R gig<7=5qR`4)Mu(#Pt^ݓγ0=gfq$:j`? ^O/S;V6$= =܀MHm}:&a,HSd] GD9~d6|HHpGއ7G~ѣۣ@´p@йBv)Kϲ\o}ǀdۏA@SF"x rH&YXoS?z}9!2 3nsTE0WZmHγeoϳ 3ڸ2p! =/R@#7HW`#|#$SvߡW~ѼO-P)gh /Ru/3PI'-$bMQA)C ԀxKYzd4 ,Q:D䖙82 A EgZd,L8Q[3pocK<tQ׭9&D/n5Cۭt+֗I< NiʾUtk[I &YI$1LR1)h["P\$vwHqKPV oI[YEA\ҽLJ–ٿi<5AZVA$D{:-lYg<E2Oӷd).!a3ۃyƴH6cm- r=W 賖ѓhRRiOF(zg${[;a[=g=VoǁtU֫I+YeO09-i\ Et:XN}9 ͛ϵIc"WMzJĎmb񋖡̴E"ϼk>'{B?If_V2['d/G泴٣ML߮Ggsٓ<ટ(d>~2%4y T{0 g[+oOM'dfK*z IR2 OcMqc82˝ 7uS?y:y.rK~߂Eہ*iܔ@"KEfID_CE|ٚUV^$puSp*{?}.ֱ$+[)!X"Udw7BvA|t{A0oWũ L8I+F rT"&d$!#$kSQ"LqTENv:,G?D|J_t^ʱ\@ɲ2ۃ(aC~3"k+|i2H{lCná%9ji!']H.2%٣@a>3KHbЋ\E 0kP4=Er2`x*3+ՂIP*UHMⳜѪ%9݅I!ȖxK"-ҸdF d"L"m{.egQO8Wzٵ~P@YG.#=OdzxHHے>#9+ɎV&LHQ8`"xT<‚4AL:9jD)2Cݓ"?Q2||ЬwC9,' ~d>E@dvܺD/2L7 M*@U-Eb}&49}\G:I2-RA':4$bt)t.8k9aeUEBIuӫXXg= Q(L"4PS+{Uj4RcF '}mJĨ)P<7TE4=)=/#iKLlLS5h2I4Ps=D&$esjyT{`$NPs&ѢI ޓ251DIۓhE );8V9;d?}N;18]YEizǽusf{} CR2ѡ;qp(5ԩpgC:<ǤDs^\u *bѫ8"ZW^.f i'1HP2)2xݫ`g!*6 +[SHʊ@< uUuҤI=%00q9Y{\uUq AȰ" a/qQ<T$Lh9}4\=^ i{{0 `!>-BNJd:{'~&x Eg!'ۓ^d!:y\Yi yLpJz9Dz2ް!"^=X"T&Ej٩+o(S}o&3 [EaG kQ"-D."lObI>2N-{©d{ФeR{QҢ/3ҏ tk,ZPtYcF,ԋH>%ĦsV0=LsU'hg~k-fST"[N&=w=ddق_Ef=ٓh$y:H?Atk-Է˶xnQ?2f HWIXS!kSbL4TVsp!:sgF<):Edʄ:}OJvp9.;GCM;+Oȏ.\G=O wos&׵z?rTLOE>dBH"5娜@4YG?mԬH9vUY-2ɥ3@HPlڤJ0ӭH6"T-[ALPi4 i4Izy1iʆI}o7I=!HD=, ېFEi4s{mH&2ѣ Sy+h044gԧj8[ d2^$')-3Xɖ0quۑ1M"mߋė3%2۩%ؓ.#IS7@+~볽ihML^+&]A=}CF08 6ƚ%oz.RFPmr~$tرZ2s {tǁm ~%`E#t*vZ9ڤؐa{M@t]Y#3X X;9EB^m=,-Y[=XbrMm*u$HTsܓa*=Zfid@5Q'Q_Xı`^$ ƞ\I Q$fdrHD` aiYkD{2okO"i"6I r>5*+{JۻT8lE>Or Dl8N`z9E >Qj$~r{23߮Qdy[p/S%XaϢ`{(vA\"oN?ԙ&6{DW,*SJ2tdzI"@ 3B̑Z"L>ySτHb=5T"ʺ/@J@dc St,xN6RMd&?i[є~1e<* -IWi!v1Ŝ5y5Y"=ыDv?+z<%|3˟ɿgܚkKMnҀ>_x?Q4Iv2ϩEq',2t 4֯iQX|>`tyyHc q4j?1o~>{U-q+n] [9m|6iE2ёi_+kHކMrKtEV;bs;h( վ>Y6>0L^̸j nό#t"#yy [$0d)E"㦿͉PQ_Z mɇA4O.m e!9Cnl+-3O- 2~+K>~MmuIL@)nR͛TRx7Ժu@v&5T$>Pt$Ig%giwoW!ʿI:"= IcKC*_('he;"]22y_&{@Рpj"4ڝ1GmlFj2!4Zbqy,ͺ2s$=>*uLʎߥ|$KO*ϰxwgXXux0K&fX>e|Ph^$3m2_!2x/-dOޔe*"1>I0zq!2j W+h c2%%SCOJ17q)D{IlJMEOMA>T,GH\l\6(~ q~"0< I5lMZ4?{4v<ޤ~b%dr)@̹!V`OljTn)m#GzrøAſh *?U/O"%מ)+|y<9xΏiMaޣd^8)#ﯦGioӼ&:by!饴4SDY (n7=$}&t"g)- \'m4}iI"&)]RG-x\T9`d Vg#Ff+嘣Ȑhnlfw'e6mRwX{QΊ΃^`1'A{Ԗ}t~0xVDPo{%,S:ozz:mV෥I"qSEߴ]iR-ӧ3# Ts{k40Nfq0=,m*̷ٯׯDJMRR3MԼ6`6>q{Xy"E$*с_I$)So/5bo0l$^2K@m>Hn&y<"6M[xߤTIܹZiO)")xtH@@v*4pTؽ>ϫdy:eMs+Yr_]smҎxmRԴǛ>]S_XjY{,x^ ίw~ 1}͢M0"/}d)x{\yv?i-u-[\t:S@U]߳TK&D*P*2#ͣWYFZ&]o?N͖n;V,51ݵZZdI(Ӕ^b霷4#Y~n2U:9_YmT~KkLzml5ܶ Vr^`|~=d¢a韼VKe a  qiri*Չef9KJZH ^Ugd[Xܼ%gL=fKbcb*_B4RR:mȈ Tcf%fKcDK/BK[ztsgq_LH3rS$2S&8Kg-Pp YRin<1͹cJHfOZFAR\kdy\ȼ !T-䲽6Oa-M"22bڮzNP=s,n4%"@cI:!\[BlL=,E{g %RaHC1dp˦& T]̆z9&3!4lV:KNΖ1MY* !ro )OF&ɞ?9&Ϣ q&Q_ -21|~9ɥ%FE Zn,hboOeS%떂=}V-eFniTi--od~Y%!-0>4*[SP䐉-$2A`WoFy',[t-,[LLL1Ӗk~)^E Z&)KL-C&}`ԸI b"%sK/G[˰ԓp猋jrPPX EC[xCN@2ⓤO9|SUk)V! B؎P4|Jᜐu9f'cШç2)j/"ds5}.luh Ճڠ^yAR"п0#dFHK2ZB -O-QK%Qִiu9}FacCʁ~ Uq. [34dΗ1G:X4$*:NXQKgAcT T;J1or[i'琪Cjab"o%,ɦD랻O‡rn6E>Rȏ1McCFB,(GJH%Zz4%=JtFR5(2R/g!DyB*ץu20ƍK~21IO,w5Jgܒ,%QYz.!Z~%1Њ!.K>ֱcra-ZR\hk.ؖBrז)-WU!>2j_돦˟)[Z lصzja;F%E2(eA4#bd%2 ( YDZzKזGVxn,5iYs6#HyR15/gI~_%9J9 ]-pYr䰳LɊ) ^OtݐIvL/c2P^)ϩ--1`#US| s63 -f-[ TpKߍ_v k1Ui#00NEu!~aLj*>|Ӳs6D+iJh7fr4 -N0b:HeY${ez66#ہ,sk ݚgKd-yu;w/r~a~*Zw&\NcNп'ٍkvRTeuqSY/>y^o/?vYd(x1+}M^"lR+iNͣTWwl_SÁdݕN cʆ~ iGK7+I'VgI31E[gȼsn7 jvjPRcܒ#.W`HHuõ!H40M z{!~xv_0}gY[2BGj#Ԧ![°%*LrI5,D-$Cہ kHHDzD٫\IvHN&vaKKQĺ!'(&fY_d`KJgi#}{!h(ha*[i7 9ܯw9UӌTTLsLV~P8aFLciL=8CcBHd ɨz )`JW򻞠gHD2G*Ȉ瘟gX-]&47 U"S[\@tHr}~)37K@IxnjFw߫1_`= }f˚k{qsKGz>_Gfז#g\gWȑ"4TɖGMB9Ϊ $맙{EH!-V#AO]m~@–\>o|zBWGBb:mI?5!Y;n[jW=]UKsMhMS]lHD♰j?LV35|}dHH秹L]WX_O{[Vs]e7)G;fyk{-=ttnK-Vu}i&ٔDشo$%?WgF޻J~:s[)e]Z$f/5|~ .kz=L}wdVLyDЎiϩ]ž[Z1Ӟ¿jW|#a}ngq.Jns.Xj7;$šFxYQ ^ RwZELV0ot`޸3_=y֪ǚ]e?M{'5gs̺9(yn0׋!Sslkjŧ ~"?/"s纾Is׺iߏk{^~|m>2tw@eޚJ?=u}A=]^\B{*#Y=DR_|/]_4gS7@ƿm nIys [D\~?NϲxN Bmn8a}B) 1C_̞kfusWy}({6WK;P>$8W wĹ'{(ӗ?7)iɊHksj'k'n䦽?,2l:PZ yChKE*&p`Kty&Z-EZYeZK^$5%Jr9'̸HtCKE5$ nߣ^k](Sc"UE3DFRYlWhI<ީRVD|W8|$r"B,9r6LW%֒&D(_̌-Vy>!KCނ jl1ҫΒ'fxd%&ANyye6X6 iT##.RvԑE|JҐ/u/eH9w $]h}vΖ-'ly@%H-;Kʖ!R#S.19Z&t"R:L~:6>^1%KjTˠNlE yKԑH4kd_$&aJZ1PBK--IZp^d  E$uf)m(N|Y Gr^ @Hras@9zOt$sL~l>c~"+rK!rґ[c1Tkil~v.zIkET^g)]>]vP"/vP'Ytf$gf͵Re>&ډUũ~j뷓qf1.Z :-,AZ#F?l. UgH6΃ۉխU_-cWKN.gihPkSovCYvqdL,:KjY%&T։q\#3kJh\$,Q5y᜘21#ψ}m⨖{'>\,-H rp#H˵%CHY*M̲i]&fzC29d7;P}XefYf AK 4$EJT7 HR 'JCuH,zF9Ҡ-!hk}e@瘠>T,8ZT sbκWub|U[Xr=Kp5LT(KP#I:b )[H̋-Q#.-PHD֙H+.u Sk)oo*u U-:'ęJPXdÊ-"}G~uTcR\La~ZkuۉV%ҍcdU}${YGs$fF>J,[d.HBzip@vjdq) ):ksϙ,q~q!$RDKHb )=yxw^Wѷqm\(54Ly"ij:^,-Zr,Ed'qYr .sh3X:d$tД+`J9]6i &UCUZ+c=;ũ-YKNR_OG??K4RH>66~MSr #9.!A1ђ\>kv4~Op$-3[VR٢%ŹS\EF`@7#x$kD>%$)cZN 9-C:g<[9B J&$j&33H#Y"yX&m lvLa,=FZrK<ռ -|lS4*e)t\!FmifF::No?7Q6#y*5#5,G6Dw)9~5[wT3Q9^9;KIH/gADvL.\bOȊquʠbn1[egGKa$YStd82Pjz3#h:5(g'"+/ROYGS2MǥdOgOmBPx,Ki'KwmiYPPR*D U -)Βt瑨ˆJ4mgNX.%$.RFJ.Ke*;n.-< oԈy%\zy`#J7YZՖR^^V,1g21k29CviDb-,!5h|9_njwjgJO^'e|1TP {q=;+I@ ,UU'r?Uw~5_k_ X4SG+;+_Tv-=u:+d`D5aFNWc*}X)vO  #_I "KCQϑz9i5RT\Ij_B$iIG_X킾$kB ?>LCVfLפ_~ܽ&)9!ݽSw]%@|{kWh v֕-b[<׆ɮv׎de~Tbod:ʤNS_G)Al)U;zHѦ?KxIN|y`MW%<4uIn"JX:y):]>]Pl9m pN}ZYJ*asZ5D E]2:DJ!^':5u N0-|d<d:8[oI&KJ}=[><1]rb&YOb} @V;7<2]GdPuj[ΒwZ' ]Ch/*s׶ODR.)r]jhy*#y%eKۄuٕS+^ծ 17L^_!CJB'N|N`mdmY1a,[YZ ꍽdIE_5Q-WoK[73=bCђ\uҡ5&C-em${[tD "#S[PZ]\+0S`3h %dX{P z'^-, fmނ.6oDhu:19wbj--/ m.@4cKiu]B~{9%d-=;G#"K:"2i, Tv^St?ep~^)X$i%BT:%`?P0ehCZ̿bײ_:$l"ixeh? m:= g UK`4,x݁d Z28&KY{%hxɒRnf}NßxKlN|܇ɤTnęJKuOFTƯ;֖םJ#%t}U+ϬsKNy>6/e-k0Rykު[*j׽ q1E% 둠 EL'dadgRbVP_%Xtֱfy<.z!GKK%}e\'*yP)cz5HR}> nia-U5޲̫.a>aMiHߦsK1O)|瑌۔>kȺ|RHC=G2%ܥɒ{(R 4¨Rв =gJ$ykU κ:U!9% ?)2鸼)"N/Kn,O=IW{YHni&WKyOۄv?>0e=S_uOL1Arbp(.rFor˞[AnOrKcH嘓?2IВԴez1mh_[oкL韏i1'璒rsʒƿdJcoΙPKZ"WgBcnWv*O_Zh #] d;m_-\>-NJe jNT.c nx~-cn<^(ZR([?0˴Nj,oǪf-53zݓ/;?9o;?HJl٨tԱEOoLȐͻ}M-VCҼ_J) ŢOMdS!erU,IR@4.,-Ka12LߋCUY  -EOX%PfhL #93/sX0Њ%!C+4)O5k1ۻ%IR)3O 2 <fj&9s/%-9! 5R.y !4D#&&*O{fxP4.@J wGBs>Ԓ~>TGaM>rVKJm~&҈qy2~{U|>, fiǣHb#Z.Ozp{ڗhR^<ȉY#5?{joCLP^rgT$ 9mg}-݀ӱ<X##>@iż:s?du;pMUGfi~WwG9 f+QiܟԢ?yqLUѐPȫ+5e͵}npayj>i#b_YV\"4/t] tuBo:.-#5xLy8 ] IR<3XᮎL~ϔ^Na0"x;jbV̫Ө?u[K㺗\W{s\R:tBu<|=Z gzHCvkHz} 3a cӢaLR_h[qy0f5v,P59Vvl)i{^:NAK9L@!ȥ%)N Dh)>HNeUFK.;YSpd;ҽcƬV'̚aearY>|-Y&Lxfi4#YTIS)Zz%C+Ɉ 3=3]QU{P*ҥ2^hY(qz~]1LwYγw%az.T{f-ŬR!&;y׻zn'VWi({3#BKdfK*dJ/{ Wnɦc3nL0@KyP%Ct'>D`-+P HTZ bI;Ȉٻ%L`ll-Cv̀Q`d;$kS+t/-Mۙ@Ю\V.Y-';^kk*phDdΩ)nv=%Dj$rbet/%]Z&J"^"VI ;*^jTN5{I2XXl<>#SmdF쥛HY;IMZ--E2M`3G`U*#Kp IZ! 2L82AIKw+Zk':)HPKNt%Yq?6(2'VL3Iu6hI$ELgkZ&OLO*[ fd Fޒj_ aeu%!o~ qή<.X)1E/Z0Ƿ )6DvM1 #&.{iVqC:f!jdR}$0`R--V${;o ӽTMi)ȐL-- M̖tDڒMNW+si28 84<ز!r/[%w"{ }SEy:ND/**d?^{#%|/["y6eKs-= I>1PB v/c&-Q#SPC\uu9Lcu6tG5t-]idT>f&qNHCiCIGI1 <ұ²f.6l#w So8 hȎv;Fa?-mF%kZ)TKI[( K/k2K$%)Pةg4N5P2]eef^4if-Q=ΩyHD$i)yR\E^Hґ`IyhD>9z3EC=ߟ%Nj.r 6U ,eaLptODk|L'Re@jS%IK^*j(Z352Ա3FLҒe/0It6% r$Gn$.IO,,4I--,-HĬS@Pb#W3^۬ޏna6iIaXqKR _?;]:<$WİFȵ1!ZAf;geĿG\cw|`GH{;|Ƽ|o[uY)galKmeX7S71Od_zczEO4R-} vf>$l+e@KIB;?3Iҝ?P*jTW\Z&7sǜPAV6$mDS Đ>ceK{VL<ޥT֎3EC$<̖)r5k/DiIK~-?{W;FyyMZ(PEC^3l > Z#<6@*h*9[>x8e%f-XґY-9+fjIVO:/}HWVG õ*@BipYtg}ɒj%kڒ}#mU9iwE {`v ͷs ֲ$ Ita"u0[h2ct;oK(ɽZ)9kZl-)ցMBw)ޥKDLneDt-Wm$|[{i.$"duL__zu+)ǖs%bz4ϾɲmDZڵaK~ҐAZP*ӡri.I[]MbsHSoӂWKs&!="!9({i0 *{Y,)6 D3^䰭$|=˚BD%HKVHC@6w^ʦRCZoe 4n.2KjHCzȐyXLpHXKὄs?<;$T0R8n eq]@V--JNG H끸tG˄^Zz bT2(4=/1[:Z٥#*5@7ᆉ1{R^Lヨf"CUq"*ӽkq>mDLUJ._~OLu뗟 ʖԎJ%-K0ɎIQT@"! d? wĀol+EAS(pVx4s`b->H2mb ]m\>i iK Fk,6L)oŵ B9hCXRXZl82qCvҬX"(X[Y/zl3-LuY!!C'$C4l._@&Oc?ִl8s;1!/32[{zE>_K[M#-";^<3ʈd=0]IМaTːTe~(.-&S5#"Sa|嚦KFF4DQXK𖒵p 9tW-IH&hHnJ_9 I.62ZmﲀU^[𑌯[--Z*E ZO~bx}&n})TϚ%g 惴 k駋ꡂ_?qFb73 ַjeuL}eIKI;t0y< C&3 +f +jW֒0&}w5s8hzUt$FcYԢ+ײ:H7}TKH "?-}iݼ=h`1^-JȀtp%UȤhYnyOiIs b]ۢɰɪ-%KFF^ȐIqút-Ҙg.dB:Z;حfӕ'f(l84{*10^2diNu$# J)W` PH[O;H&nik'I-#4H@bAB*7do$2qzˉ<jUCvѽ)-2_xhކ^s5,CW2믌5eI1Q]f {it0OH8T722u[4})2ֈmX]+vvub\KL ;|@|T  v2|/-[@ߘoLֽdL8IL1%^Zw%7tȉHct,֧P+aϧк7d~O.VT̗_|2o~rGQֈ.?VO&-+/j(u?Yo3oeY-LOm#6˵#߯ᨂD˰cVjI\udZ z%UXrHw=X^ӋLEDRRw!b~YhYŻLr n\oW{y'l+ɼ%yK8 unɮ1+Ls+)5Rjb/#G2{K5}f$ ˭|FvPhIRrz/RⷱF6RZeJ,((\dzJy3%+塀D (oiE{_-lZ!XT]R[ G *15L# p!?KlFKCGCӖ Tw[2dlH,Ev<ιrHo{כd(Ťe%'$ _o?v ٟeRۏ#Мi1[$RjUjto S8Q&ȰdDixBZ ~6nGfhÚq"n>J/.=h ٲ|G~/-={$kٻvi:[2-R]>(};Af{(ְů=)fḍkMwhS`mqc*nw:<3=](s˼GЕM?U8\xhd^[~eovà&oI(ҁYR}CF4\3ѬBL[z91Db:4c%0VHo% 5%!ND^c7 G<<v֟P=>$'&v##k5#_*\=ibv}NôAi|%S{JMRbJOȻ9x$[@{a.#3/s K# NqDisPOD0u*陋7$Ȗa{ΖremZ-hا'1HE{ɬURlxl ;tj)U$4Q4[Yk`Jԃ!=R>ETd` KWFv}&JV L'JD}jKÿP5~HJCLA}ΊvY U@b{JW&zȔK範H_x4) +e$tô/tJR=o={Sfx$No5KU0nZqN)_1xXGGzS qV~MnYV6,҃>&PhӴh$;4 !󡹃K^ xWh釨9F1ɶH7fҙkUػoLN3bhroxG:CU~e4-/4-GO'vG?L֖{ "NEk&]@F҄y/!Я*E4woEdJHM&0;Bc/-#1paM I4+6-$f;>Pd_e+0Ԟbʩ`CHSTN~N@"M-3ķT 5 gR*"n 'm^rБ^J}xzCR_,A6#H귀:ߘ-LWy㺵3KMih3PQ{Č?쿍$CȖML֝۞vMLVſ-A'AFo1+2Vd?mlCmV$d>4 ki$'VL\;M@6ϣQZB|$'(Cu߾%|zw>TzVm&!bZHꐑ$Ii{1mVU1$Zzh~']@EI?Ca{b,4=fB;>ioC.iLA9!<%dQ5ݙ_deTY|Gs-7/uO)o*8xXSoep$> Q}NSy-̝\[ _Zi- {)ș+H!d-A2O2 ʹ5YZyז<6alv^qw}đm#\ZչABeSHIDle$4~lH1ˎ$) ɐ $ kTGɵa`aȾ"ke#FeriOۧTb*|^?1+{mRsHliĖ鏔?Ҫe| )w"/ǀ+!#ӕs -{O1iCMNkIϯuȴ9y6^N[-.Yr䉩1"7zdT@\NB}b:yH[a  i1}`;)R| Ck\N>)Aq78%T;KGJ3}$kK溜8d4ٛN)3GW#m'u:5ffK.mZV:ˏ/&k7ǗG*nɢѲ!a-!̗ml^OEfoJ7f'mVWGR)Z^~[T3/ZgSߜ}zORCWFÐw!K^4KⶃkĘP9e!WCxW`tj!4N]>ʇ̖R-j;; smiɇb-mb:,'*}D wL&|\'2m/%3Zn < JNTH/mI辰Hcivhi)mAytE.qb|].Mc~e1/'x:ZcWn`5%Y/@k54Tj*94G٢N߅grmg \ ت}>^ojrKMT ms5 u4&2= _EJ1_.4~W3x?nl7wOs-#7;ǭ Ϫޟ]w\ku>@hB#uM=RJep=4yMI4dϓ̖,#_*&?.Bt1.gaLc"Pf5bf}KF.TVV]1!,]rחU]9+%]fguDw8g1sxL<~vb?~VX]m ~,];MZQ˖Zv]'/穈%YZzACZ -Ք`"رZ&-#-BFZ1L;Se&l?;q{ uJG0>ˍ3H] ?Օwid_->fjG#pwFLA,֛)+ծpTT^#Fjᕺup#b\!j~Y+Y;D{YHJ5_YBQkRn!ۘ3 K`ɣ@--&$2KRB>ǽΒem0% k7Dg('܇D0uKt,#KhYS W:2d-3=R'j`}^FW*e'亖1"cJ`+圷Ӓ rslْ6HB̯]D֌R!}%驽++\}2esVWZwEB~NKni- R}b2<֧=fF~ϵbJQ˘j9^k}Jo|TR;r$+Z;}Nm!gD֙e}X({u0x>EkY!5e}jw3/BMJ*J-u- 36@NMLyK*I _0$úRgHG&} (zel<\Y[/+dO!5ZGҁG_s:团-m5D544 2k >;o 5d4XCb}v5o 2b ^`֒Im5Y11)6e2_imyhl--}dwz,n'jzyޭv,#O=]61A13\'MJޘ9wI $FrdZK͟~A~6q*[f%M:ma_ߕwYj-]oְI%2!Ͱ67TZT~Ns^wz^=wtg_t'lWzX%<:L<|Lb?}~_:|qhUN%/Sog{%e-I ) ym+i qv~.a>2 e'p>q觖a"g]2MOMpvid~n-+aӖ&i[.BJ[ay¢eӿ|ؿRI\p?R};q2+;q% 4.?PqګGqF.bуHaEQl^ !OVf$\G)]n3nv:t˒1Rs%kX㹚,Ջ8͒riiTr:tK fͬG ~$yL 8ԏ4\L>Ptv?fgk1g-Y["3<~FrԿ:0kY fwof?l@s~ɊtpL=hgɲpǩ:|zeWǡxazJ'aᰆ?A7ӑߨy:?tS^F43@rX̦o}쬪xm>ۅC9O?Hs( P 'QLH& zx*ُi6t 9 sϛT!qxV-)gUۜ4ޝUҒ12;VA pil-E9`]r)Y/~G$!>g쿟3'#|3xITe|0/~~YjYhy| xԝ_t.ʈӔޓ?M{OFI2?Lb:yig6\?u7̪lbM;.Oh)`%XZ2y`?ͯ._:P!T?Lr}K%aU.䇯f𥉉뛣Z&eRrK ;ޟZfHVOL[OLxVB&k:. ~y7 +5 HvbWz֔, 2RJ5[Kײa2ַ8g8|J2pi#46P4w>c[y*_pxO(͵d#nɥ52Jeb:bIv ֣4~N3'x*z[sV,4O`)!gYRۂ>{j~mNJ=fmYN-I^i99|6ϦnPN#&$8q-̺ꓧӓ7҉0[Vd4̈F,hщ?cziT뗀9WQvQ嗢's K^jjsSBo,ecO%8݉O%zIXK@27G2;3Dx=eZRdʘ%^SF6oiRJges4,3`s[ypT5ٝi.K,{xdJUwTc!?iO`bR:$e)fT})=sN)˟iTnqyٻ[EGz2$E4KYA~ `SRx3ũZŌE.Uݺt+[&J.WYѡN˫up#Q#)K)Fm.KZoeȐ)va:Y'Jzf ))[Mp.aBg!?z3 N't]\kLiV()"Y\E+ᲔdSz+_K)5fZ˛RVUWI$da U@~z6-Y ɶPsՓ":$oBqv8'*Lpd-ybӎYCW׆ToA+>_i_ψ!M;iAPw3S:&.Y5d_mx=8 muS>=? ӳ@\5t?sT'(ƥ_4O3|4<]铁P>۸be%i9@m* ,!s+VXd2}VƂt)<2%u/'_slXL4G;|#ꥶ@7v)k"+(^I\T)cd\Ol)W f8=SVo)ߑ+"m-[A{"N@jA{wro,r 8O-x4Cz|~Txr)?;%QfKc-e$5i{(ZA7W[!I P@%黒UkiJ!k*51d$AL;i#Gй*Z)T#l#_)ej60}2kiDocDd$[b3)R=DԳcs-Mib*:Z@ZQML~:#-A$[FC$&$f~Z fU|c>Mx2KFU>C֒u$<7( jasb-}N2k!kqF1PKI6RL2YA5+M[fecRw*h.VE@Z4Rе dCd|8%EJKe@&kj)\l ߥdble df0,[";:^)d2yd oAC-- Hmx+A$q <{EKi IW揔ؾRܬ{ן-ɊG`̑olI|ZTP?ju~VH4,n* %=2[񗚞NϿԒ-Q*HkY,lҐ\l$"?ofJS%RX!K?mET=e)>WP` Av#iIElj-Z2KFByz_,'44!mFe2[{tȴ:ޒ㰣4 )md*Xc$[Cuy1DQ|~UIO6]r鐑-#dC-51MtZ sVB7=ֹ'Fkh֐ҋj-ŢFô5it;:+ I֎| (VJLDɌ' |Z9ZJ "4c%Vz%22e$EURD*u\Ȟ8ѴXG mhXl,=|ĹP5Sqm krUM=>N ӁRl?uBn\)TZ +)~9^DTYRkdYm'&l ̲Y !-䎩,]C`4tU-DZlɮ%#xdfd^KOxK!}e`S8W[;HajT._lHWii)YS" E{6d -Js`󵔤Yn 5h(n(#vW= z#c-A9%hID\-Y[` %(@҉e7AIiRIeFK&ߝҡ~@R2d#)-2=12l Kù?휂̆)شzMD:dUi*7kR3d2]K(IrφQ+(H~dtΑH&&ggZ:x6ˤvԒ)ZkiR 2^1ECQI0kH6b,drZvRɖ\kE1]UpH0l΢-};0a"d+)YGd:61Pukg)nd#b-CZ+3[CAґ",[@`>hHZL͆( ]zYXC ZʠJ4L^Ɍ2\RD@%ìC%YZ[%[D21016RC'f0,XPƺ 9O HeN~bc#ki1YS%ְ\sw-mz6L&;KS-c-](>#^1C Ѧ4k~=k'f.*RbBƺi-$됎|xxrdQʴ4Vic j dƄm&0[C*҆B--%Hb[fa6dgy Dx& J1J[HZ*e%RZepH45%9KRt-%-#.OC%dnvv&㐼ւXKpHZK<ϯTjY- #-}[>2 42Nl8ݥ߀leS>sKHH9%Ϻ?~^ *֒2tzZ/Z j.-EdʜPTmn_ 7FCA{yykK%]C[6d+t [ھ*-ٽcniI\3'nSfTk2ⴱ%F*Hx[<;DΛ -Y-V{ei&b-%#wL} }\h [CUD˟g |Ki/{&}/U{&sd=T?0eѷǁsŎMH+fR uس%y6)Fa]R%py ,p:C9}C9ZO}1!g,Ά%a<y3aVgck' İh7=[#p<G&%o@ߘg3Ke@WDuH rQĤdԙ%'3K_;ϵp }BߔP;@<O'[rxTr>A@I L}`O+Qy$?s>Mk ^[Bl Hz3td;$η.7tiQInBKdm^U;ң%;倖kv*jKȄeKOTKz8kp;ӰҪí叴?l-Gz5]S]cbD9 eْ%c[cX$)~x6-"g|vT!FC{>p]?Ĝ;ġg.vUuӺZ%Y4}^z?Nq Sua8\f]$ylX|}/Kq7= o*N5$eiml3JM#0y.Q*Z*kXV91=iRZfh$Y,xZ #x/M"ub^Y ph(%\j4XKMo0˲eAx}*J%dR3lRdkeM <%fK)[C9Tc\v@ d7t+w.񆬍Ԙ6P1rLTK|-Iلc]@s8v܊7?R:)VQ*!Eaʜ~G+!rbBl%iDKhfSFrqKI敔[wVX M 9cn)JJyz|35[&IgUM'mPierR0W~%nI.-Exd!%DZV,Td"c-\',+oj%kHNP+ST5)M:&ZVBZ %BfO% (nW/hWn ÿҞHmdՖ: knWv tT=!9w&^?$5u]f>RՙJRӲ%|RYlZ":GF&7^\Z= 4_.X 4tN*f,#ۛ XKqHHdKI|lJ.[֛%y\gQz!߇)wFˏJdk)TW[&iР0| "ZJmy&,. èO~ #Z"d"3/R.I= yg3[F:ͰKrX4Mb@k^2"%6[0,nY\?y&yAM3=˶jK0eSY~7s~Fwz7VHr V#&L@GK¦ξ%t̉{~ n*lk Ld)Vհ!aզx :k‹͵7tDM{nMϝ,D1ylrm yz8^ U Qmɞwa+v,#K|]JRQk9F|LN#ίȐ_TԮސ64)12+i}gC\]%} -ϑGs7ـӺ>i]t*fRH`#K޳O2,^uZUB_U%fiUW$}RRr{>%t S~Jo4>i<Jy('g$CtFޚ:nJvZ!0itY|!ѳ.ˈGyv`^/w"ۗ~CjWRooRG_}`*b25oI1GⲿqQwvπߏgfU+MoP3l@|!bbfMLQdx2_\$r;$-KFnף׌//1Y Ÿ`u-y-/㼝Z1;+ҝt)Lb5꾗s0%΀{zvd<1|/IU D>@;T[)=d a^l %%Z-SN46ALwRJLOMkv^3䅲AN"L-97>}[g.f 2rŬc *ۘ`ҧqgB?# L}R[fbΉ[r3RLR7VS%*.eKN,yy6";Ͳv-̭TW5(yy9Yb/<1&mhs &oa.IJ.h)!k˟Mf5 `K)H9 EZz 9A8=9Y-%$e-W!H-IaXi[11KEۄo/y*_}%-CԳhŒLJ /LL^[(iӍ lgRP#V>S9񕤹XNy Q|cCM!VVX3J d/doH^BtO)ݦFZ}e-gV_#Z#ą/-kE9#WR-2g4[ei *Z2/ޏ,˺'U--~"1|L9s)e,#e,ѐK oX[RM0vB)E=XƖkRrޙ+4|?Q]wH~*tL7D>1cn){)ob}E0`zDZg%eyK-ax0k䄴fj-=Lei),ԕ*Lϝ;(0AY ˃zsV#(v#˵%LO3T3Q- zzFs3 "R:>SjKDds$ OLcK%@ZA|(m鲗--m%l&%jUWe\wYb,yG>] eC-m{UvRK\V]ϗF(gZt݌Z.ت߶\X6;c!<5NBc(. )}'k2'߿ijl|{/ Y WX$ݟW Ā.t~%LegکL[Z¢BGjp\/^tvub5'XG )r9@*TD)zėfv9nbu;n1+|3̇Ra21=sޙɎ{.蘄ten)Kt.ǥgjyqXKAY.dZ#ډzF&uX҂%J>gҤr[S~m Z;ҩR-RmKEp"|ž׮vFzFj1{TlG}cfG9:ua"_JxP-f8J"qK֚7*mhg\T w,piK9+L:ibkK(V,%3ȶ<{P݌8Љ4&N4WcjRԇ4Ct$r÷=жWOFFg*ZuAi%$dAS B+Y_`κʄ/T񴮱8l@4_WIw H.Kdf&E@t%KQ"9aR%vP+MCBl g 9mvbSDvĔ>gms}eۘpyiS[҉+"c %:SXND8D@^S&|ز|% C1A> @7NC*ixQadvYM$I+͍*~8 I %dG-$LuN\Tȡ3ZА=h8̟6EC:%ĵeI(y!e)-Y=MP3*=-ґ<5)TS7" Man\~>T>TUCE(ZxtiY%MEQK(iSM}Jbk :({hMPt%3'j*4瑋CLjp=ma IS4MpwXŸ| d-SfA{ lJʖ57(x OTeSz/g{G2;ȑY-eBwzZ\2Ozmk*H =U4j)JЖ6R*V=Ag{^R`2"?d8// y|C8y-/U<<}"LPs¼-(]x-\I$M2+-lZZh5U{9[X e:~C*'qZB%l !*Bg8#4#fV %;P 5 {j4A M=LC5-“'GdܴĚ*Siu,YcD(97L͡%iL2JA%:(Nu09咺4%Xr v̡yS%-b3%9IYz=nlͻL;21TcfvKK+=(r<%obB=LT~a8 1ߴEcbEӚGy/X$HtBW":gkq㤪 _ĬWtB9H:\ {)nA-*{ߕ%1.]Tį(RKcԻ ز*t/v!AZ;#UZ")1t/ve3Fo =TbŠqZ0y7Su/M_iFU3#R2lbfHfKNLVOvۜ q=~])LCe$WhKx>;!ˉj`"Qu؏,D šҨHjU//r˚gX,zY?R&|} W&ȹ(. iFvt}$1.ˏ$cn)$vD-' s{ ԍrPR9]8?9Rp6^\j},5>Ls>⶛XX9kB3@bn-S5(SIRO?ebQ޲.>SBvƯ)Ϫ.,}1mLY0?ecaw)EܯGXTu\O(cB5å"]&[_>a yQPJKM}LĻ!i<4AopGBv+hNI-.: +щ`ip?=b%tuHSTC$[$T~d!)o̞#>[6CrjLҎ)~Xl)t/3eVVt6I]lڇH%}'e%Aldy>DWFr- Μ2'cX%dd1|:Cs΢$c~$ MĺPYK1ഓџj[qYƝ?2%epdbhǢLCb5:Tګ%.<;N,: ].f~H1ҜK<R-@>@/ zRe?[Ւ![hzT<}fuyzFECx!˨&$!%ҠbN+$,B7c w0g*DQvsBEK6уБ:;ϖZצD;L^ⵛJe!:1+f'dCp yAd$ei6g!',ղcBϸs>$t Zj4$TQ G 73eXfKs-Ysb!΂H=X SXڕ"\dL\"U>@(c%8RڒxrCV;U)Ԯ=RNc9obdAEtϑCť5Ӵs\1kḙ{d2- IY}$kdԈ Ɠ5.ZV.XV6ٱ-%[&R!91ɪeAU){h U#·?X[FT˧G[hS#8˓01S"ld#%YcVQT#?HGHW9IHNYܵY^-v.-=̨ cүWB {ɖ2)ʉհX3mRq2j`!dlZLJjOZмg27,O}UۇD(ZEC3=~BZ}qA,L/:WHߜ±*H9Kyx$^FA[RLSqzgj4K!_ZNOޚx%sKdEK甽,/dZ9?*%ur +7۹)! "& *&#TZzl-5}at.nY241#\ZzVeF|cBNGz)1=;ߚ҉Cfh)4e/bdP4{ک quY ҖY@~ R-:dO)'b7sG<{ $e/BFH:+nյΖ}Hh(sͳG%>"^W{Bڭm}lIܷ>--etz:(vc~ b:ffVK+} r} *$Vդ%[#%-KEtFN7|,u7|, .{k\p[SAdHJ3Q-WܟWL> ^(bPI!А4YϠD􈙳b}Fݎr;q8s3wKK3@#z?wNGbL̸F~9["i2xdt>IGZUKfÄT~@qI*;dMF>GpY1sUAμz B(!3yC^ZHei8@ {.:2-ZN0c&9l2@HCK߄HjPN\eTHKV>$ֈ_Z{)2$ )SKbǓR#TZ5JLZ+Α ,8u"V4ld5 9kKJ;iKPe>}aNҕfs$j/͈[!-)T 2\\к I'!;n4EľAīhuJ>P#f^[d3#Yl23OI3 mӌT^T9!!Ag5@7.I)6Ҳt/fVԽa(׬a<#Yi{Y9-; H L ?o%guL_᰽,ʆ K?(Җ6eCH7C |XkAO1c2 9RӉ;fNC SgU<_ue+EL09KFܩ͈:61*^sDT[tט}dIÏJrl}EK< t^z@1,,V}3ڲ̭jE]EK*T$4PܾX o0_Ǚn 5췯i[I=dЯ< #;b#dfvd>2;2<;B=^]h"}* E%yDuHx/?Roж}b* ZzX^>Ҝv }c5H˱G nR3Υ?]֑!9]R Ksf Grz0Y_7*"y"yߘ:L攑L|;xdUHHKTc[BYJL{X +~Z̔$v Zz 2Vqǀqђ#ddsV4Ȟ>0YZQZ4x֡{N2P-WDA !̧h!_glVȯTw!I3Rq+C}'N+=HJՈ@  RGQ;1dOwc hٻA cvt#ڴ[qb  KLĒaʘWZMqim>*OƂBΎ5kuTS :3g0= -}|ҊKQ~e9혜Ravj$R/UۼPYj'{4S*15[^,gS$H,,[ۯqE<璝ϰ TNЭťc)|$l*ӳH;&GYJ6LrOEĶ8[cK1?K.NlY'V꒵Mjir0.b{v9]b&?M;ybTT1|,1 +ͅ$&J$|)-9jKuijdgȚPi7#vL_&dO| 2p-]2BIuF=zR4\٭řQՉe,Hb#:OuE"H򮵉BaTvHdgɆ'-U/7KGBT|9mVڵV;*p5iBwXnleޤk@S@6IZ Ҋfi--F",R-ϲ$ZRfȞ3z^$⬑doǚg@Kw(%`Vr>3KEHfO9Bde Ǧڍi"#ŋRnPEIUP dW͠.yK-҂2m2UK2 &2 Hn,S̝C.4$\gi"rwKD.i闈uOLқ4Ζ*h(8X(Ob z-xKV9K# n3̌}beXYF|,Ynn#F9|GߍQ_eK&UF1[E`z6Tjh~ˠ.q^-2!4ϒ9T?K(h,- ѝr}8v (e:Hp̤8KSX bmiB]4g^33 ,,=CDs괲8琩>$?TJY($hܒZ%0,y} 2 նL׮VxE#}.:pi,+-2VZ+:(|}GGEuDqJdX5PV /oɋL%J'5fKTK43눈I_-#,3mx*Y">.Mg?4u =뗕ꯓ]B)߫"P,pEY-HZ:,gaSJ,e5]x]UҥQՖy[.E[Cwkgv,F/# ZEj"ɽP [k޽Bߒ%WZbe&mY2$lYzܐ1}oH/K2M}ǵW, n0JKV:K o(ް`KfY௛}*H~J"ټec6ꏬHmTqn{P}xˁΖv ^*^wANA68ZX^Ux4L>Ǭ$I-OGS(q:[:g\μ)L5Px|XGڦqKS2k>{%z͗)H҆Rɏ~+>2,CМ Rd={?s_1'&_nG4&s_cyi/%%3z(UwCxl$ߏ*'Gt̰{L69> Wm`Y_ǷxT!x`_,iyb"N!b}?/nhi'M8!e\ǘ~B=_{n< V8qDD -SJ?`N%%q(rEDtH*Y!i)_} =%2"Җ`~.۩44 Qy]Z J;\ ~>ʋUcztjfZUVW7bAɆR:P;LuY娯E$KdqqNHt@W37(OQ+l4Oe]& ho',m:mҲH5T.1$'w̠dI-9ZZfgib҈́DYz&Z"Z2 ݎӄTji 2YČ)/2Აg"6{"+o:2F*6!׫XcKW׌$R^dw܏A\N(2nG<ݞ[aD5_2J C_牱,Sڻr'm)LZhz/uB {mj1euy:\ ђI 1E?YƋT?PVi[3f̵Hg^,eqN @c.:RE9 NM~A0u:ċLc`*U<_YkJq)xw`X"߫D߫{ŭoi>z/׿"FsMh)KЖ A2!je>/u 鋨km.Y"KM$}1.D$"ZeUKg9H೬,niVR䜵lN4+! Gv`K†g nʬejK#s (j΋$6d&˄e0 iYyY#YZuL^e'KcbG̳$f-U913,M#%&LgiDv11UK#IꢽȜ'ȫ$GZd5R̢9RzSZ%&,&-Y"3IZZ $ ;Kť-)B22:֚ ir$:R-&%;WKK@P*.2-)*[egR\eXY%T}X@oGq#x. Rq )KUd9OʎN^/-X9(eV3L-)[G&i4YYRR}\qXld̑2J)VYj-n99ZV옹C/$28vipkXdr)L͓$;Z]k1˿Җ94Hd[Y>,3F1N}іL/65CR`2n +!1#a7,9I媳dl-5alGҎheIs175#ه-a11?8*HoɗaW$mbzP\FLҠe9`pVe%D;_a3|T?˖n ;K%ji#O.0Ej:.v-<9Uڸ,sĄODgl$[]d)$ೌ/2",]äѐ%b^A6/YzTB إfƀ2c&Qe10kKLPdwjU.4[JtdRezx0LuKONCY8;3FKF-{4dBWC,! Hgnɑܩ2k)T9&ҽ%S`RkgIQRcڂ/2@KH&R-5@C]&y{3&b nxfyHE*ˑrI.#ΒԤ{scIٰB/*eg~;R-P-`#nҪH,N0ivU-!-ʮ1yDŽ1]ERqHOTҺ) uj)ZGbUjCjub}Uvq}[ ,Ӑ[tE>] ޒnS"1 #,IGzxV2"ddERF- >b~ H"%dpH3,bo(g8ˬoYޒY,*[p=۱"r TEqy+*G ˕9޽ /L 딥ȭ:yKNIkEGV _JFYk#8K}䁩~Lt *8[-!-i62T?KR,%][ZEߩ-ՉY˵U91IY +S(r#1kPHvⳄwN* ,&u9Ҍ[)Ҍ4]Y.xB)D<]$4FRČ  N闈<+ՒHYGNͣ|TЉ 8ZiJSegh o|_ l12SٰӅ'.R"iu"@H@ʞKI'ܾT4|:D&-+wQ,r.]\mf{n!ӏ+Ⱦ ?I^-%ZZQHHQi0옒g)֒B15RZ'dunrq37B'))-U!)2WYPa'h_KX%djzUPNH:컧(Ly,\iZDgy_QhDGdy $Щγj V * i_;>@,!I;dX`>I}/n)&"#:(iZ4mZL8!#4?$v~L (>2p.J/Fe M 8KtPجoOnivDyLX#rsl+Ɗ >I5ӏ ɽHX$EcZuT.%箤,OZYH#}y?lyPtHrB#>2%4Z^'Y˒;`jᴭ*e G*R,K{vxD-.yk9Kbז>Z&q[<&3k4[S#>Љ RkCKM-$NZz^FCqX%3|QĻ0/=\!k]˅eJKpVGJ992մe~Nb, oi# g\_1P%}%[$ tr Im֥³kK7drYxlj.VY;,J7KD?d)բ ^YH/_25u^8.oVᏌ>l9S=9e*fr}XEG3˹@ɐs^taNQIKcv6M0Apt5g oh1*HeGKߎ9wʸƁ췔.r2o>gXy#s~gmЗ@(2=$֋m2VTcI2-"e.:C S% I[#VU\f-,1PB3Rcjva,: :' U8"Ap'mZTu/ `?oe%*e.㳬pt'f-#=Uh#_i'xUB.sVOB$k`͵P_ U BeKK:^2%"2٪R&0.JIb,<1$}cZcR1e)%KHKw:XL$kJ%$sJv=$Z"+OVrXW=C p7q?^\<\,-Xbq̭%{B8v߯Iy*Ĭctj!uRm]-nga6/&9Y%{Hg;K)2I"sKK0?,YyŠqn\ vF?"R֒%,~h&َRqKd;مcl^b'{U!R$}-KHHb=ȹi+}$erPzYDԈ2AzY%# USNj ZJe>`&򹐈 ,j4,Sb`wH3=>&'+,z9$U {(Ihr[|%ǐ l/]?f!+=9o$7zPkwq%/-D{dz!Ƒ#;'ɥ!F4$/0{dZ ewOȮl]tmہ༓nbd6/#mNbbҌ#Eɳlr`@Z: 1x.+(:1t?J]AČI8KRݷZ]N eL6b}H6,#$ 82=qYwu ?A_Vmf3DI*~'竕2b z -t U_ ݟb> }X-XG"\gʏt}##̏ul9¾Ya]k{02:{|Fg|xO3DS?*嬯dk[KVmIןFHү<[R?6GʏMR*h}o;w4jD?6K:k1R[0ҩoXM%kDVsڍŏ=[ nOOs{3b0u V,c*ZGF+%udhHu4K#"e1?A} ^֯Crh#I: h#=`~9u՗P%.bikgIم^4r0m~ K\Xx|scXx,aDU9ShMZwN,+* ~r2w6kt9˿=ܿy|%̾:m93NjUўOY߳DV2_1ˎt@kO!1.D}pSGhN[#$"|lT<ˮ(=8A_Uóҗzwü8кt~ߦj,3H%f:* "o1B+ Y;F%&fV>M8q^?k45> ? j2l\lUׇjk|eRo(dlx-f-j,CȽyNl$2x/Նys5}iiPgI{(7 ١q#%+& x 31efU3x;!ImsE[g%~]OqGH=N51C+g .R2z_c~nJp ͡CT~,ðs@J}[*;?cg{l;^'f;91(RfEHI+#ov(fwe#K{oR->;/EB=ܶ}sd+-rN"IZ]iE 7}7rhu[HYf[1 }4ޮlE 3עVӕ' 0͑:E^m }.sBf]kgb>[Ug?ʳ{ٜ&{9sQ&ӽG2ji0Cr%:+GD%##e ;]G]n]G]]sH- Og>zuyj; 0 *h{_qJpˏfnm[ Wޓn?t1sC14{,4:']qdvivHp{ j+B4%jz)w9=pspdDRsEI[wˑm>R;cd9FJfB}~){#ɺ]wSVQudK-HnMuĻMEcKMS{9g{Pb/_ VȕR=KOiU@Dǻ/4/kr,LmfFzԥ?A>=ϩ =/2ie=dhˁW"2%.1B۳v^#Eo-VHOQJs%Vt%_MKy3,B%瘎J͑TN[M͏XWrf/V^yGs%K R):ZkE#ߢMb3~zYĻڛm\2я2(~z ^K}R옪62. ELȨ _R\kߋNFO?Vwhtr ?~ak?Kܾ0}nMGzwd7,[:1Ub*nc@&֝N:^ ^_+zypyA芛a Bv~eVHg੺@ Y,yJQ$+RRMfyJIŲXtLHYZX&{_-ݘ-K'cSd _Hjqwzїdc.4,$΅YCK2;T@ƾ^Z4BB8!+8A_4ՇfE#SZ~e] Cx]ߓRG`M}.e(pf3"ίHo󓺪LPʖaR#=N3gu6 J!] R%Ą8̯ij[>M5ߖ4Rs * m<7IK3!^aI ɑ*u@[2a_JYf[+{r|^|)W6?^]zKЅKOfD,ɯrC7DC2a tK8Kd3DIEZaq֬E 2k~,F%e;DBȚ=wߖ*ewy0.KDaa-q_u&輑9w]|!fhПOJ}]+8}]-+zd0 l5D :0ˎVYHFBCzck,oYW}$/;3"!# !vb%>gdWN2**Zj*fNL҉KՕ]-w]rIَo*?Xhѯd,GjNL[)xZj{~<{;g2 y#gٶe"qZn&60gI"sUe=%ϰ? IeQ1)2&C4FJsyֺwHyѲK gY;R]Ԟ?1 |;nYXѢQ:I_i??qXtĤV40]߹%nUY#v>DPדuE':*7FJ=S\(-RyqYP7z*A=p^ Kw^T(3{eu4oCfV^e܊ЫI|!R ]jY.нeq-UvqI} <*Փ^^;i!T\RK!ގRK("ICR*>S -0  5z~+{,lx/ P%jYyT FJT^bs)dsD\~j1Hyj7G蔎T;S{p5M"yF>$أ3 T*?J YJAXqBMsdYƎ] RJ5306,ea'q[qS,bbBJOY&ggY tj톡2 mG)Rea61kuc?e/HQ&doĪd%ڲ eɛ?a qeU[Ɩ>JzbY5M-g-G d22Rn#ou9Y8Kᗐ;d]2Rx? ̓_GxFgTRkp3G ߯OHUR#෿n^^Ym$J-7¯X?@(]*/U [HsFH9C5iߤunpo{Kh{F*> ee(F-C]Rxmc,׏K,ܣ.,GSRVIb,jWf>9T&[DLf=ޯ EtRuB"4kK̛BTWHc>թ#ŜIbrHw݅I`*N˫r6;D/[G㕪v`Hp$ĢvZ3!tYw];]  }eT^b)gH>0;vg ?:HYsK$r.bGHIY:Z yj>RrKE25ʰsuB ôN+{CWj i QB,G`l8'֓:.߲N/-G,Tdl"z?*m*i!z{_:&[gV{]KW~oED ]LUv h?!`M[2{KteՖV,z )_ IO!/=rr6B&d_OJ' ilv^j9<, !3;ΰ$FR3,;[wWg5qJXY"=GV^}֡##[Z8^uU=q8D$a3|#gzw :Gvhg).~SdDmgi!HtOD;A[AvYܵlJmvKkj2z_Di bqU6ΐ?EsZ#ְ=e[R[ωu2wgAYv˴|\%F^2bg,#]`wTFՄ4KH+|M o \#Tq[ǖIlڭJh I h!z *HKGEx(@],G%h^Jq/ !ߥzǹ9(~خLDyޡ)Jh#Qw)e91,-TwL+I=KUՉɔ7&VWrzIl11T]0t#sgR=@5"浞mb$ڠ cl[ {GZ+fM I//E)xd{ĥeIi"{Jb Zs^gwe-RHk YI^R˴/X]]z%(UgID=2K!/ ^  *#,5c$+5Gfβ3&!|6v/ХG‘gY926ҀHZsgȈyNJʖszY4I]f)DtYf=:BBEȲWf1/tlGFb0MKeXLjv+G?|g52mEW<լU:Tx[h5,ܒ0NdcFusHxѲ {O7jH`HKPL/۵J^ҶudxV#K ## IOݡ1<3OPWNHmX@K1`lcfML-Kx3:sU̐}MqdYG*,o4k(l*iuΡ }V-!!Ъ;ڏj+'*RwPTNM$)$6,}VY)sdzݖɖU3TXԁv٨䖰xfڝ8.3BfZ_rIrhUeOmhSFzȎ\hܶ'#uUeHaxLzq/VDߖА[zchH;ϳʥ1fy^}&G38o&"6󤦺I ](ӗQx(7Hl d"G' ~OAYF1Β]7`^Y3KoARBRl).M;!XݢN/ vX7ycӪ]׸ЗEm~׳3z(ŝCE*s&ڗ︽z#w2v5sJc87PA6U~F=n*sr҅OMT&6TC{R`J֙\ք_.KĞ2[1TiTɸD u*RTKu{`.|d48ˢ^V:qK,!R4HA_qYHM6e!nWH gՌuYӸ4snY6MGNLgZI^wB|O'R$)-w*]ɷqQֳo_$BVId_^ӧ9iq Pb?MuY=Bj$q d{3n|爪e.حDe)!b ~HgquH =CJ#m/^t$$x{r[]wfyNk} LRӦęgF=T;G⁵mBZQbYȬFُdI|b,d-K,CF޻\DO`:RѹS[^瘦##Eqy)elP$iqm)g!6^z Q6udd/z?x`$!;95Iu˯ _ LJWp~7ʥ1)}nFsGOR磊[£1i# ³TG$'v)?hKHV~{)!n#7f7RLt$=~WHFV_^f ?̹u&ܵ.9VR9dn%KNpS?;@޻s`M_kRW}7Dl//_SF:G0~,vK qIt_EFFX_]c-y#3->yO=;J{= п$W!dAt>'g IsI-Q=0c9P8R*v*tEXd-K#FfYRYԎ[jG KcLpY#%̾>O5oeuGj#sv/撃6{I|7lv$&[?˜d!z!ːDIC>DY c*'Vu|$ J=CvJR`qaV}5.D_B`; VR6J}SK)-K^?-/y=!א_gɹJ<ɹ)טa:_}:\xu>S'`J:Wz\zQTVSTUn\.}$Ykn7xM: s9% e ia~Ca}&dE+]53oGvvB  @Djo.ĵs>wߨj%cбeGe",Kc0O&:3}gRvF԰t,»j-M҈lڒ%H?K^,}ey]I\<>R;$RXGrgkJ]xLro(&g-]^/#aR-2#Xurn-G%_^0S{f:,!CuBZ9cmw erG:i˴KmH\8gҵVgHwlU?@nPYR8>T.cN>Jɺ|jå1Gg)E--2joEjP~$S`g'ʳDJcFƥ0E%Vd+Zbk*-ղZ%ls_ @bKgF5v)eAgy7gӕ<0p$<]k3RNJ?Rb`zE^FJ.R9v` ;H>2Bg$c.iIHtV\'i<#A92OR\d8Б-d$<#(oE{c11%$yf|ZFeGFD%IJVU<[h/Q;\Ka ;feà8F%5 MեMU N-)0=I]yofU{*R-q *dq%ZXNWxq?Rk ;IZyPC,j)۪,>KZ[HATZc2.g64>\iU&-5!g՛z*# ~ZB#IЖ"-$> 3>Fh Wˤ:w@z=%理l}da8$cVje^&dIE<5`@_ 4yl.hƦ"hes0enl9uY^ _"ĒK-ӾEA2,$}Y$X,=ƌk\Z ex_ZI%7DZjZo ]P--+7^zK^s{ٰHrn?ߨs cYtBLcLY-e? 0%)_1(ҽ^(",reQ.b\+D R\5*_R/23[,Z쥪.TKoDx\Jyc /W+ KG-^wtB[`JEaAuV0tFbŢ/i#ۦZۦ})#Kv Qг~Rm1:ǝZՕS 20HGC"ŵ8oX6s\aN@UWj{cEtKףYyť($e~D`x,Xb.Q-ϵR -/O,af[ٛq^JY-RJb$ZI=%?5/ihIRSn/ EwB0c5s/#Ӂ=[:D*D4֔R1Re wǦpK%ғrwmi"/+ɓ0˒/]>]e֭Z?-(]225tCǔk.Hcmɜ~Mc&-Uΐ6 -oY^J!}epCJ FfLVִ%#1)1AeFL̸ʰY-\2ReüL22%ҖLTC"gIRSm"zFCx_fS%յk5#lRj]{-S-EβT%Nj䴋DyKʑJyi wk.2-%l$eꭵ:L~"%}k-#kYZhRXѼZEu)-8 q>Th7#;,CCu-dCəqu@ :Csh%ҲRrY`n)Ez˄륱> ZsucE8K Αr⁨q[Lm,}-瘢13 X'9KUdaZp%ٞ zR-EX[2DՒFR2_!G"j$AnߗJِd miy-Yj>,֙i|;#jl~5[BH./5̊]/$$NgYi !!Z2K,2FBe,ȑ)y0az$mZfuҴaBi[,5tpzBEH-5q[F͘E*HRi K>ˀ{KH]vnЁ5,ZBy(g7nz\-Zr2_$#%y\^yKw'|/\HL+IZyKkg U&j זv:[z_f9FGbhYxt7 o2oS,m9gL0rj[ <*_1 -Yq9^ۈ"0R FPe m)ڭHVO5l1Y2i\A&[m B 6$+$B:LIK"}2ArF[*9$kpTqȖ-Moj;IZ?j $ ϳt/EZ%_)K-%D" 2ep"~Θ RɨJS0y ư@z˴,B.ߊJ,T"AZ&J.In{Rl!Yϒ=ZtJx}tY0Z,!˲*+'oKk~^N35 IA/}xRtUޛVz DKY-)B$RGFJvddqepPYɗ:- u*iÈfIx+4%Jj𪢘1<\Tk K>%h|s"@^^(/=+JD?x$o*(/xR8+dJ{[ӵr_`YIKV諆rְ ĪfT1X R vA)bQ~(!:d|!$%_R+kP>$*\%`oɿCeZQWbΦr/orTr@$ҤKkdzVy5l엁Za,n+Q^"([r̋DgiϴXVj!epG,k`kͰj![܀Zr8j11#k9$k #se;'" }}j 闷C|*T鯼Ր152Z3sKnڪY*|{dνps[d㳲(jI죤)ZKD,X[G|Y}ND["Rag^P)`URki,-uy.R[eqѼ̱$'kpg!~ۋ5w*xdr9mI07TbU~3HZp]b*UKY ; i jJgqH$eK-T')E:$/p2|b l ӚI/SnBZrŘHѐR#`vL@KW]WfKR䭵#ayM;Z ItQ|$+oU<5G:tsLiɯ,!TKύU ZJb/m87߾Tҳ\B羋oNd X&"^d:Ԉ9Dudk Á (ҐYpْmPaq-ҧVyɂZ#FZe,pϖLDT%ޭti) } ȂJ lIO/rK [[yH— =I^.iW¦\q+Ѳ`%I[}uK'kFQR$Ii*dP3s` VvD]ZcDYU['j$ǥƠ0V&Pjq _)JNҗ.B;38"P%U :ԺC[C4VLb_pORgbۤVqU;y?VE[3tMEC1dUA=a_ehLIKTudK˥BvH[jy$HjIY៘hv%*Y'ZH.v 1wYZ cbCXU-)!-r"o%߳Y+aizRg/܁ 6D˨E}6Tp(!3BЇ \߲PyS D05glrU~A̷fҩP+Il~RCZk>vm >G>IR{>PY3}d=ay_ъ~/bkX_6w<^6_\?w${ޑ]wA}aw^=uwtl]Š~3_ ye]H~s";\>6397W>Y+RZR^"?>6eSp"Vozs͔W;is@+}i[E3+?OOgf8a^6/YYr̖^*SXR2Sy2JU$jY$6W >IZUb#髄"kܜr-fxTer6s7Q׾eptHYg)j##]~K,ՒHV7r*Q[ꊢtcniOk}1ϲ@il,:9Y8{r%{b)#i1$Fz ~K^z;ƌ~7rC:Ks'i %?lԈ3,Z2wc).э IBN2UTKt-uYFδ'ӗ 2QnOccVd-Xdny(8,[r, E$De.?Eɶ_:W-i)e(JmuH aFu$RORWrrˤd/&"-[p]7lIP ,j:g^h+?I~RE[0BߗW'&n  g B9UXKE4^v.%;A/Ǚ2s0lكJ:dXY O<Ȗ"!Giq* 9(zn^3hSXeA$bdg+Fie̷6_O Yl~[j@e\'CrhC&ϋTR[Rݞ(T(+3.`#Yydjy,9[D G]Fl3TCZlh&##!6dtϑ>giҤ!"ea ߞ^0=gҫԁEmVzH酛k /izfRuoK.P d$R[UvLY)#KrIk)<CKCXGB02??9;lkV % `k;^K-E (j,im/yeݻ"Ψ%%+oJ%q/ΗL%Odp_l X2#TۍO]~Ԃ v%3en!/M,xn"~]Rڝ ѾwgU:2ᴇ-׉qy:~O DH"8B2#_̶&=pRֵXSj_O{fR.bu}xeAH`3dKlɈ\aS0l%C"=:~^U2dѿ ɒ)Y 19~Ddmȑqr̮~ɐ%qXM:M9>n]\sqQ?ȣ^?,y($pKCioREbP!q}䡿ST^VX6cr_\d@ 2n ewex|9od!bɖ_\fO>%3i5*z'(jH BmF ǐ)C.)F&RzGoKcH!5nb*"*6G(:nD]7 v7%T1ICF5O7,$o_:B)%m[ҲkH8ĐQ2JoY/!6`AlHtBFbT骢!9d73;PG~H%dn26,>ZTȒu#PaHq€1 9vL 2AȈQ6dU6ti˵!+ƦJ䲽jac%'ϽK,)]*sIX8eKo$t.+Rq m@hBp5-<`K)!F4O'$=o2#פTIɨsEe#> jRDZiTf1dl P*mܗTȆ5ٕcJNZd)S<1J`?Y\ҙ,)K&Aءcf J=EJdHy5PYBfsMF.Ol[=srix;tb l>diԊTj7YP_CB=|CVo8.Y OaCF8,3&EY4G̢ZVپoAm% &CJ7PK}]o0V=BW[ؾ 56چ̌CQ}S`ȂǸ_dLuCav۶_)lz _MI:{&dJwx gp#Cy=,Oq=HڀYmNpڅS#u(Vʍ$rT}qFȇ7,/ON)r{5 _nduB~Xq*@=cb}ScHA`bA!?ؙ)Ql'6@n?"Nᡸo>Rz''dɵ*LRAS׃uOP0.mo' q@Q8o\-95h-S'zudZі_QgCZ_.&5Ee^(2hĪEFЅ#"\8>*-aL(E)\(*g%Y=ciW%eH]uXFbNcHmK$_^r>Cj^^eDen*,؀i}Hh?{)|Ș{}>)T/44o$i~r'iTwLԌ0BbV^[[I{-)2P}ilBP}礒9Gɨd o2?I%nbHIՔyP$=?JES(!Cl4:(Bb7P'"qsg["Cﳙ!L,'E|[O$tǤ#{V#HD^ :UYT8. z RڅMpd{2L[ _Շ4͜l:kSS7-m'9$=. :0R#3o]]^cSR l)4JqC; [;ҩ@ERdY9pZ'Ȗ!5! IR@!' & Aq*oբ ڄϕy"Z?#`k+m$a3r,tMMLC:yT=d?m5J>-٘n56TB,7HߦjĂaMfFɒvVvE#XQ_r/a?r(g boyvun| z:U,˝I~023U>JoI%`5vƦ.r *%tbh^?2ygSezW ېVENX%J.g v9ydL Є2ҾHʇՙEo;!&mލ'6nL&$LzHVimMf8xx C6 rUfRk$~M/2g8юA*T<&%Bw3oCj&-;P]s]*74EORA^LsKH[!ЭNJD]Yf@VM)}RC6[n=!k[{,(Z>) ;sE)K>]}FX>آrdh% DՃJFJȒA'؇ ]O:E$mm{DM{ 1<SBQi)}J*)0yPMI8pHcjsp-ځjbPޝTKK*%s47?c5j*$8 NwjZEi;AXѯ=j:h%WN4}ۛ&R iNÄnyHkq[:"'QMKĻu$l/\4@ Ԑi65i~^XdtkǿH!cSz e{LVaUfġ!#0d8o6#BdȊCxxHuh ){ar7&rϐ`;/w̘^1od<2e;Д!+ſm"߷Crg i#Z*| imyC֐jz M2d#j_G̨rl&2H 2勌W. ӷ]lߤ;CXdHu/2TK1$WY$T KʾACcE;(M&rf+Dɹ ]$OQ!IC'וּhܫhXe7i^R4ll 27yOLE0K RDڐX m?u7ȱ)}]dUU~, ;tYLI&9& }z@dI8 c Mf? 6ftͱ,DNs}< ,O3k i߈_|"c{xH(lDU&Vy'bsqi-{ t}Scz yZ)PIM!C682'ޣ_Iñ c8u{Y=ЪR`M PM)=dtT"T--x/:qBዦT8([U+!y W]X0LN&d@lIN"p QCgIgȇӈZP=Ҿ$ %4IzٵNGN}D斄T1fc!ÿg|!=unYAq;#O]>Ll} [Y~Π!O"6rȰ>M,^^uijŤ;Ø:i<:5$H! rxɐjǙ'LROX⽡ßlBk<=g8^rƄE-z&{ ]4"ϔ8]i ͞?Xa5/{&1YS:#gUf֬VɘH?..!ބ*8F%ql '.QAH߫8nQ8 "Z4hHؑzP;Ktb>ȪC*wź&dljgPp<X:|Pރ@E}k/dZNn?)1$Ŭ!.ߤjCۮ IK`X *"t!jbpjXp?w43"e>vGԎG |N]B?L/<`wfآx C'V+ƦA nrhYZߤtCƛaՇukpߤCBkl%ESm:_dͱdi{zqdYY:oz]y/20W#Q Z&Ƽ+/(&Xwgp I#blioyȡkslJ[UUE@kiUmc]HMc벵)=3+|H8WD_ӤHګ7o2zIZj:RLwGY1dA2 ]M½]0#,G-mmX-G l%rL4Uo&1ѤL1I![M]%;k=CK~(ޔ:<Ҕ 7U#}*l=s!SR!$dwk%tIZKEl%dؐC|/mɤz%uH˶zzwPC.'P0Ǩ!5K6kSBnҥ/A!u|;G7-6ne;=PRCyAc}g j5v!Ko:`ZlԾ;r7qj|sm./)ʽ{o~S9z8vI:Ɯ&9WxA ƀɈu['y/ V\{񣃂lN`9s7^.9=$&[kHM؀Utlfwm>dawGȞvjƁTA Y>J!EC~')/ɴWsQb8eCLgO79%N{ODr~I5OE"L|t/2(!k2r.Jq=U \^)V'&4i 6;/S[Ө[XoխFk-ؽW..vHSXo忘3j4 \C/!3V|nf;/]|[_钰.!KsZ4Q2oBDܪB5'lŵe 6dTڷTaz?$>-}+jqG^9[*Ke[W%!KniOy+Q.6dԽOVIY(mDC/6^%XCI”HI^J"Z~+2eǽEg`Ha\P@SɭzY"/{6/u/Vf ͊{)=` ɞgJNk4ZhuۼQZe].e,?z_xe _>)C2.SD]iŷM%Νl6$mc鿑mLf Ðo?Tb bzĝ=QךFe|gLGqm(lwH u!pn-Ad-^>6PA YQ Kŀ(Tk޵>D_sy?=ҷ_TJiO45^!0d^"CCJ ]Xy6$W7 ?{Hf/VLV`)ir0I?.swo1о1K0JPo_Gd7ԏLq~Ĝ/YZMNld٭>^tx/'{[[ar)1fIַ cJ)C!RO9F`F`ɮ24w"lh R ь2o@ _3+:e#a=ߦf؝\KBA"RM/YPւ&YNmE/iWs0p"- sEmK2V؀"q:vI^S1R9/k9&A/YX[xĐfbX^ \P^X婲Ő3 ,X$V>uڔ/b#o)2dAsIe?Kbܗ3R*Ơ$ߜؒE אk*)u[ kRK&TblKߖH JJ\V< ҪR;j϶,!kJZv[BV!_uệ@! ~Vb_P:zxts~`32~֥Ր+2;uk L*^Cv MgM +?dS@f>fHt<,n[Ȁ1Vr46Dǐ)BߤM-/@:-nKɦ&զ `7ovt!ٿIϪ!C5Yl2,$MZ&Tjs;ɦHyt_c@>H+ YڿII!= ClrKYke' l67h1^*@S = DCQC:[.89!"7{A&ŷDWt'cZ~@%|4 F95*ȠoTUeB-0t;me)e6pp!=dM+֪ؐ6CKfF)/(w L)75`&/"ҥwwy)mk3 m / _R.U~MTٚ$g 蚶>?pKroUYKB2Z=:1dGP"tŐRǯs{uZ_NC=EHr UI:죸UԐ!CZ2mAٷtRrɐaKZ7r"uڱ_0Z &Źj29rفz.o}&!ӭxCqja_d@ƥǤyQ`NYPx8%{?3lIz^|~(C䴼ٽ`%0~=o,39f=|+/d~߅׀Th|d8Hi-)@8t`B2~(Ry?&͉a~?PK"li jHEebGm%;-#n,OJc}JJ11]01njbI?}MJבi#PH^B|R)Gڊl w{ExeVmZ]Ɋ$֒2-*nҺ"t$H01MTubkt)>MRo4=ZsFš w Ei;}2+^2,ΖZuRR3%:Ȃ R$:.DqTK'͖l{) q; ;ȜC$H ՒŢAYKQpAcd@ryXP#N?DT#^ k-GyKʿ>>Gok,E}̆n?<^ҐR3[I P]>lXFqRbQܷ -!,ɔwIL++: f5ti5yppf ,n&'Ȫ =s#e^:|B;,pC63Zf4X쥚5L)9Hj 4#b'Vqlڴ hZ=5DeMeF ),)CK{*h*ԥATFּav M qSH̗䇑XehSG9}!]n/Q2"MH&AUqHofgMoJ&:k:kA+Hs L,J7+:Db\gxI7hqmWRe3&s)im) $iR>]-n.?a NҢmS2osK\R_ ES%"?L h$dPN&" K,!yo5b ӡS+H i#EKari-U&SZg f*pٻ:&QCa--uȗyLK)-ճLj-x24&62ZFiKj$l2Aˤ&Sj:.X)zdoĂ2y%e-Q-!ysReBjqE,"[o{3J[ /{3ӬC{KCXK^ xA;Z<7B:&y֨+mqHnj/zU᷽6 6֢vA|;{к4Ʋl) QN~Z`5R<'de:Gb}:g2H brOT[YESnj) ҄d/*-]SxKeHA ^%ZktQ62-F2BsC1F~4q uqiCwnR?\kNHwh~3eX[+` 0`y\g,o ]I1RDDrC9OrCGCi%kDWpB&{if#-2̫eEK--y푈,$ E{b-)$ҩ(~ )#S&q[.`d#F:̎m$'lQfD%)p|h^$FbOoa-5ͯ[Z.ƽ__ ܲ0}+JPwzWnt$eO~7gv@CkK4۱B.f:=*Z*Ga(%u;yQy\ƿ^?̧Cj3CTa>ͷg^%\OE+p^ei-)ibfW |A[X}kI]\Č%qbI[:;KAZ͡}S@8l}ekRQfixCb=i~CwL9n%1%R1;HliphlA9 XbGebKA:eK6؜ЬxVTԴXTO2 dZ;ܳZ{p^RDd΁-%T).uL{ɉi wRWˢf}HȆD5MHl':$ro)P2[wF-Mdf?؄4-wʾ*k3+7)[$-&:KڲBb'yEdhK7Yu24P}2z-}r uGJWkގ+s<?Wp\e) B>C[>gFYx=K2zYNDX d':\IgZY~"kC9U@IH/8<[L5NW@ح boRyeB9wPCf![YbP}Đ2qזޯus\@6,~(TZ5p-eE&~ǘgoBZ"&dVz{6Z~Pȸ*U˒84`C^f/+f]%xQ0F8YgY$F^F>/.UN/.YgւI5\6(cb/;4o2c ^Bz($9EiHjf 3t Nɿt*ҿtb^gKHGBI$-Q*AY[葢c/+(!=8du,&.OLq[E*Ηo>ϖt^L{]Qeq<99ZwG"⑶\YOiM-XOTzv.2>.ӳ*1'k'BIq%Tz$/0.yH+/RʥpzY$s/aˤ,D'u3tw_pA #5_ ˴7&]QK#r /0b ƕ t U| bI,3GgK+Lr{޹1\NK"aiI]pǥ?(t/ O25f<:mv= G:L{R"2+w?*k2N\ҼaLjr Ig"/VKq9.5ϏCbzI`$nK<#Vˠ:L9w=4~GS~X=D 52=/9DWQB6$-ˆF\-- ߳ I;0=86Dz;1 ɖfi{Y2u\`is<Ȓdq%xfTu%P'):JcLW [ UzTђ0S8Ȍ@Lا=XHЖҽT6"O%k [-U)2m2-SǙ͵+Տ}| 7ڣJE&d^ :8,CKcNjV)ai2Bp lYurR8re4ƙ/gZ9W  [6of):٥ jˋ<,AKӼp[*V2Q~ >Rת%I-5\5d19\P~09J׽1t-,*A[ZT# :@.dCZɄXP{'bTwmyN& Qf m{HE{Y }$HIAY3 IGdƔkpF-s*$pYc=1yfh;Ɩ~-Kxű6,ز$ũ6Sm8[$Z/)ҥz2 Yi #,2RtV'Do$U=YGRٝR9T=B{;brbww$RlF o.dᖮe#N:0 Xn)+Oa*i*Ӣ!kYCGh0//>@zCt#F$T\eoo*\'rYS@{)1UZӡWvHO!9:bi!鎆{"fRC҉RfyH 4*gnmi NrN~ˁ6J_߲۲wZ/ J_W PKWS2qY]p ]?%B캾 R=:$pIRVstdTuM*"ucU\rIK &-[lSmMbB*6zm;i{=URo{AUjm`qXt򵙷WnR+m}52>MlvH#ꏒNRen5Ҝq r-]ܠ֍:eKLk\k"Yq&k<4Zq>єDs^r~؂ fˇAtN\nQ "|dj&nռbѼ5k5쉙fbGJaH.נ[PtgbLuYى ys-M ۥi ӖշdST\mrIeu`'"'X$=kh8Kv^+!z@u2):~Yk[Ӕg4o[5S˕&zN5& ' mI:doRv֔Вjsti:3뮑kA \vdɾ]d+"MB_AR%gi5o?-~6>0#Upɑ̼19TBgLA_naN^ln$L7#IV$!~ѷ[8qsݶ(19go-o?Xޚl+>r-dޮm(y2kQ@$~eׇ4Օ1>eH+ߖ]E#%|Јm6R=һ_wk#q{Oswm!;JF\$`A۝`'/So;rCT XUz~18#GHD$kT$}q-E#x~=Z2RxS͛|wC2r{n'JQoY9^]3}%v:*\ ۓPRgȌtb`{G* g9,eկ xf2IB(Ge+GvHQl \gyg(@7i5PF#9+$?Rէqẻ?]]S9|-ydjLʏ(̗ s9P .Gdnۗj8IhNHM*udk0Fׁr3t41}=–xMo+zz*GT~[?sUn_甠Ix2-AERX~Y#~[ޛ2G6gDv}T"vqBȭ|#z@aĂ qY!_=ܑ~ulER#.pm <jqӔ1' ]O/CY?$CGDmeOk2JGX0јkm]y=00} zRY0CGZ@_>ǓhL#%f#خ A:5m bɂRrw? a#=!9F"yY)auHNGqY6'Ff<-'22dFY%X|Ŗ I͏. ϑOvSv e|hי)O]i!gj:B,rɺ2n]g޶:Q-)h>S+[ݏDfeZrZ1U5E-3ZYC]L]͇j?ԫ2+V`F=CjL-C,S 9hH㑢1eܥ#^Yj,ҼmrRCR8LHl:2C$A ב<1SKqbDYiDȶD !Yg|Y|\!"#n9yU /)e6}D+H^ߣ8o:'wR֜/Pې]NMc$pY :ļW[S.Sr[>N]o~CIږBP1?tdgח$&׿]Lv--Om6 Ɓ:H?hx l4P嶁:MY,lK,V1ۡl125ezwxz,C-Z-}O&t`;BF ;]$g?º""nͿcA.1 cqߑ$ۑььA-~E=lpH;:Tv?:Ŝ92"rDL߽"sgh l3 a+',GVz{o{T|@օ'[vʶhe6RXwJE>`!Yf_G"VLZL?ULwI,6dnH C;F\NXrtjE`HnHdtYdE#,(o2CC1![ϲKW=$lB&tBgXhOD%7s~`ɐ'$(9,Ln?Ҩ<#ySK *?0_ (džlK !J3,蚘!LB)s>Vӑ"\lIXΊ?_9Y5|~ VF?dCfuԘUl<2SiQ琭bsBzG.1!'g~@rj+g1j$$q!#%ΒsB eH~i#K([cYDv+:FFoqo512t)nt ZWZ8Ve}ZNi_ mMdq[( Q6jq.V`-5p} *SMe&጑Qwr#=GzGi甁o)\z%T)iސ,#s,b3 tV41Wki8KwʜmYG̖%Y^V1LU5`=#1j|c"&%Kje)Mse,#UVTA| צHqۻ/ ya.X!#EGVs,Z3BGp.\YNT9SfЁV1|PmJ R8VL.ŖznHKב!5&#bYgX->PUmGtBdLcL#65d7eLchO^2o3rBvgCr sِ(tR 2Som]z G3Q6R=}d*Y&vxP .jg{#+p iͥU#]"V,f)s|Dtm[q[&1+ cOVM7[cׇ%dSg|$/Kk_i<[e0m(!sem HH٭el#^#"-?YVݶ3 CzdSE5UŹon]|oI#->q2Pt4 Yuه"֪>JPKJ9@JԴ~~SsCvwv@p;;3jf7ìF|=;fcVcVTUA9/9 q;۷M E62udFؽ{"一?.H3 wSHOrWo*b$vg%#\?J;LI4=x73_jb7+Rϐ΅IcTKn6_ܰյٚ@}cvs@Q$¶źl?&qk!M_h>'6/ Bw,NB}Xi1|>Lq; jV +]1 1SdWEMUYG=ҝcYH%6&M8?f;>Kn@:I#ޫtJӰ0ix}8Aqeu}ds$[9:Yw?xTr 'F  Y;j琒@ѝ^PҨ>w-3 ` ,pai;noL>JPv :F&G942G+YĬ:W1Ҿ\U;o|lB*JN.r`.iw9ǐJɢٌ%-Š^##+ULOG*E@ ^)-1Y-U&D_e`hþҹXFʎ9p.jUM;qdޭ62/OI EHMTh<j]7~IoҖ==,㲏V|`Nԯ- $e CF#kdcBkL->^pbsZq /ˡ?4:/O@ɱsD2pISۣ;3_2QC˷K<2Ul;OG@v.c9یm4?()}dDݏ(k=CǃfJI8`J +?/i_5ìvh/:zwɠFn!>|t]#K(ܺn38,z #62818%}r?ܱ~HBv^B+O Ϗi-kTN$ ~I* L3}:.4_遾^Aİyj=I'WGzeVSUweFl~4Y|s궷Yܧ=<'gdQ /כ.8z={$KYJ$ۘAPS ^ET jd(fJYAW,I6! N?;OSOC)*aQG=\HauY)z<ŎdHzjY|Q']r=Z%W.mSX6`߫c|d#SϷɝ%Gi4-'iԈz.yqR}&Vi$Hm[]3 iR 90>;?:InK8V*֭d=Ȑ<_cQSQ*f{ ;(|Sr8ѷZ0@/; Uݐ<&+*ZSo ۈkQvYB5:j${$bBPn8_" mP)öm"Gg)HTG946"80GDmӎ*D2ttEM1p<$}`JIOU`WNɫmchQ%G R3-V9BRcޭHYr`Q[FzzDޥr4Mxkd!Q XcNpm.}Cukib31LpyhPHMC(CЃ)CYݗG_gb Gckl#/xHl/h Kk_J;r?tN2V?N2Gmnv(#Q9o3?Qcc*NUP[;g:3͵de6L&o"-Vg3ڙ-PPdS qZekZH3?O;-O19&fT$!M]GF#Q33-@ j}; Yu. =SBCN-JfMiMW| f8FIhYd3~cβ2eFaYGOV-Je%HniYX5z!j>C`g`{/O$eOI`qDUѺPMҡ6 Q{}y@IwW>#rTO0;{@:;:*QٔJ#=WHbd*sGFR]ASuQQ}@ZnG耳aBߵ 9'k0L*vYqƁݞecf7 [Rgzu\~QqK!]J'6(@Hد w%O%R5me.8JԴi%#OR(19Y#5C?<ȁ:f|k?.3|bVtOȌވme+T?Dadbj6n9# :9+ GzcAc}2=R+Ga|=DX@hOOyG^iQ=3N#KNI#!Ѕ;ϥ4Y>2$º2$l%#m'"ہi8IpԖƹMЌ4ʪG*)$GZG$ AD(R:DvH~E#Fvd쮷[6{/1Y)p '/91IbLeMf )d=prʕл4-g۶e7bx+kAT|%ٮK_i_ATJzמiy ,UN !;y-Ȅe͔LHc-zjԧgH8n;IɊ<"6?&1\jrDU>Yl*X]Y<6u9R06C^I˔ d]<4ѸvuuhmfCI:񻓟ʏO/@Wy%Zg Rlgɕ}g){2{&j*cB&$K]D,8軄%3R+mғ_7WjMMnS*~\֩T.S q&淙L^P2ҥo3;͉2I`ƸM`m2i*r4[*6Ou3o94ygA/ӑ-H6* qT ḏR6'Ӝ.iN eno_fZμ*v^/$jwMY&]>P,^Gbcپ,÷12rA˩Im8eOjD:En'g~69O꟡eܥ vjě#'ɤ1OVۆqy֖Ym8V6H+lqbG&Yz?8c: 0N+Trٝl `ޥ m Zq9A)1\BPׁ"_ޣo#&:N2Ҙ?W]|儂 }Oǵe1V$]b#!=$e/×)|!{1V|X ĖDhk ˘pAuL/ _["dkfL`5[{egĽEr`O91!Y&j%L[ JICH}G @WB s{IGYktq’;oDRGeʞi[N}$V=?Zɰf9EF#ОSC=9E CDӴQD#-:eNR,7GzGZY3g lY<9СK-Y, y1.̧y oޥ B牒m@qbJeZR}dMm-xr[dpme/Yj?>ꟁ{E|I) 4<7AVET:Dd~ˌ)vejL역5\oir`du!r;ʨ } \-;ẅ́JySn9zA} z:^#o;^N^tMD>12M,1;.KqrBEʧD HDhHT#,2;K&igeumU~vrxJvnsUZYPg>ϧ1RV*er N2]l.!Eudo4veUAos$ sle*9KNV/_m.Wկ=2%,Rl%t36M馈s8KPMӥ!GZ.ۇN $dCs$7oY kqYSbJY%!6Q9%6ΌD݌EbRg@-#@GzxT%|lfvɧHJ?J%CHՐsg@s[42"÷H7pjՁi9蒐` ǃ̐"˦jgZ]pe m<*Z]%e’zH,5ELd2iN(m@`]#N~PI2{hnhi'6AYY*1/vڄXiAq-\FE7b$crAe#C=$X~D̽?uL? !!PLT.6|R <Ѵ/ȑh)#S|2+cÏb]j]2"Gj$dL Ђ|&q)2&( >oN loCZ/,)C ¬}>P3BWB}d°gЅSY"F:mB22Ȕ62WTqmΚ N(WF۶{Yr@G ف_1E\f#d\A-ԒIӍ:$)Ҩgr.ȓ Җ9t)[\&jT WLb`xβ'51}=gLG&ypn= ,_T->2ld2H㕎OЬDϺdnKt,XJ~S/d׃𲑍G|sPi0id^&Ib.m6%ͦ.D^6;$Mly!G&9}zOX% ׮EtYj`lGvυY1:"yS 6&@%Մlex$R"/ڈZUAfp Y ZA%Ynm;SGxg '$ " +㑑bp?~t#r%gDG5v tbrZχV9_Z}n;@?R`Dְ| FP N 'd{nm6. y93:AU;C.M */LLO2d&!ZY0$i}A< Ew(Ƣ'iTRJwR^/% nPk`w݃),>b:Vw%oCdMAQ]_ q[mI!HpYbDu(Βc$G<~n[f`'RYYqVYyTw(/LDU$ # O:su)Z% A,nK,x#˿nFqg+7,}%Ia+[bPߒEt$2Iլev|[VIJj`2GIm՝w~a N9qE'ErK22}kJP&=X#lW''(S砖4VlCqaho6jT6)D}ǪҥgiSfx,Z/@C("@i/PY! T]5R6īc aމz)f:QC!}- Pl!n9Ҥiň(6r4IN$Mb>O6 }yPgGee̐^[ܺ/OX6ur PU 3d7KcwXTCf2-PG! {޶;/R2n_O$ORDtI*稘 l=A!G*zG 1O>XG&GQ<5#z;>5+㨵P1#O0 63YՓ Ҁ-Pi=?j2աgib{⠋H˃ߥ)Vrv0-+z{~:vxխ32k^S8:'TVrd~ކܾM.5`k4C躭?__ uE4"0RFقn|`mK=&#c[gnL*=aHבqE{x5 D#LSxu4tPȀPEmB)]z${ޗc*+tLHtiv ean"Q̖{W?zz K,LTtf1 e!Kʄ c1n exގQ)$THfۑ`ژ!wEb3B-@I~Lсaȁ˥p3*c\ Iir™sYC@TP15C55mpl' Jڿud Ed1ϔ5]nf2Y򙘟V| ߋ\ =@a*dL9-β5md vL iJxw!]-FFԔs].a([v r%&,3G&nk(.Q]b,rĎ+)-zA/0\?vfHc+b폻'Ђ{0 ZVt $VH/XFo)X´%e_otYAfWJ`0Hq8hׇ lȨ\5 K )bW9VVe09Jʛ2:$^RcLݜ=WzN$[ߝ}t|;Τk\VvpeHv/- Ii2R"gɑf+r3aMg13-'ܞ&,wiR.1o&=rimڿJzLa2SaSf̝tN"-$\#?Uļhת!} 3D;jO,]7G8r2D7QL+a|0yۻ%2βɖ5,3dݥY`U9HHeӇFnpo|fՎ*[YLBM[hGT\MT,u70?}^~FQ4)SMc`G tTG̷FȊ?l)a9V,5r9Lg'6[/fuTxn4;^f47ˌ?uTu`n]БLB#W #>ϡ  ߳+ef4J-SfVLJȑv6.w ꮾmۍa#\JGFd@ΑM.Ͽry OLw Gs3mm SmCCBnzf~{[K#XP7\l3$FHbq# SI\ cű> ;H¸?DJ#FZoy{F,G w}d O\H q]lMmr}BP}*oJeO>uU4V\o$Jcpz#*6cSe+Q#E<ϲ}:O"2T46{ddʲu~[?%HNZvd߷#)5 d g''ԥyZC[E?T!63/mmfm[&t=?]-*OWBKn?]/m*+CK26E^^^dvz;3K: VeNNiUSy;zG #`|rKa0E.kQZԞwy$п̫$va^ER9nU~珂J$nfFfRngdLH.iB9d:CmH.)#'", +4!ʲa)<$Yguf6W*nÞ8rs\FhRI=E` APX4=-g&E0;.{P1j>VvʖYe`qŶ\fU!+FZHjʖ}B3Qj(#t&,znBSbd4z$wI# t#>g>RyN7YYsB%JLɻ6_o2""օ)GpI}%мlz&\c$ Fm{`r{Y"l`w#4xWQzgoN]udn&S֟` DTp}@?rC*9{!]jm\j(  uCR:k dz 0$Ffm6[.LTj=RMJ^q.42Pg(bf}\#A횛"#oC,r .ddAMJWsR|we+=ϲ10+?3F#K'YZfVoR5=aF,ytV]6l 62?jNPi管b$`r±GZ<eU6'*yXX3/i 9RIRIJZUoSId,ˌٿ aHZ?q$BZ)Kh~sYN@1n}ʾ[eJx.&Cc؎HFYE-w~+.2In( 7}tnCwGDF~ly$ڲz$m:7,vw?2PLreȡt-<.G'L]z9: IHva]{٩8sJQu9ub~ J|Z*|fFS qJͅGuHmi!6=J&=rbIjNΫr^MGlcyAskLBkP9OH톨l~Gem|a%9=MbnR$c-M*vNy$Tweh>ҫ]B!8kWdGr#D)2>Vdݓ", 3,M%2rB0\LӑU1cb| 2(=̫/.2Kۃbw>B8mog_!~Zf\ҥOd*jID}+,Vd}e;.2kJN5sN/r졲;ItFluekd%05LU G&Ku[(ikX9:XJ%QzN\''+Yq+LN7w'( ywѤT-Jw`b?ԻU!ĭv[?Lo߯; k;4#lu\6#zC޶\Nm,A`,i1nkbϕ14j\^v¯Tl?ee|GmIk6k H1RNmuLtꋢ,r2:fdJQdKA&k_+wFV{?zدީl]dݸMI6v2`Eu^ *OO^6fbqiKThA?$* mB8[Co39*1 #}ȒiN™92gZ68N[EM+Y+/[3_O?ғ岍R;Il:&fu-AL)"kI:#$DL}xwHI^*LƔ]ȨizuH2swCc =[&2%Ф٥Qr6ReI*Xʒ.dD-Y!2VIĬk|&.> fUCEDw0R6r]8?D> NVHX?.eR W*6ӓ Ol겠(2seDb$1ʾVK rjTF*䳗ё^l/]$hYXaCR{`xm&}&ɝ{) xXi3r W& ㌝%L9l+EEFFSۦnoZNL6,yC쬃W?Bj|-8h_gdב!:cTv>1dMhw j#w2 7Vuv{;B/S!}> (5C'1b%A yd}>(E>R> U}*r0%@kd6Go1b&df ,T2nY4s0  {^N*W:vT)u^\wRHuمh!v_Yl) ,̹q97 c;"WB^fȄX=jN!RoA ,;7ʜ˶w"o M tox~$}Hmt5\< z@oQYp(4Ӹ a!AQ+?ȓqd=!sۇbU+t*fɻLfHPM,̵E%~k=֌bAal% %WFztCBڍ5)Z VZg+7f+D v9[F"L$;dẖLL{'a釅^vSK<|}iZ {V2\]I#Mާ=6C cB i%dy<䝏^C*%w"XѸ=Y\Ӆnh[ՎZݖ똪@j{ϕrϳI>ҵ= <˔Vq{ pB]jIg&u2IĺKeP#ޕMqةTĔow9^QBnxTWLյ(چ=Wc.P6} 5fxv:u6:U*:tdc0rP77z/ #- _Maa{mxۓU{ݞ⺽Abuy_?Aȸ6HdmwiyQa/ݸFz-SvЃ:^bA!{P=Ҥ}'rJKFA銛Y᱓FZXnՑْ; [E*O % >RYDoe,6PUkSGXdJ[hy ,,]νxޖr_D!ӼuKToo)JSTIjۊT#:=V%WCt G31, } gk@;KG-A+n)Gtadxe:e$rgT-3<}e%(G"нda u$䑢}kB{ Ev8X21lAS/HqI2I8 [yخȞz6N  SULФ0G0-bE6'hjMj-j2P78lE^&vm@"qQw!p'A"oWzQ.{ɝV4}j'Pky,?Hսַ#5NVe#%J#7k$glR=B{ɘ|G~7cI c{>Oc2)J#cNqow((Pv{>E*eU-*jyThy2ھްg/ [o­o!!]02^IL`22밌>WὓMX!AU9Fhؒ1X{'EPŒιJБUKM|֘TF s`W/;O=9 #V=c =}f-Gv.YZFҖ%O#啧_\kL؂Ŏyn,)m;i(\RCv? hX[47~nW0mqm2Ma\HtmO9$sfcDPn1prY5*ͺXLq;;+vN &!Tr9i1q<I1)֑>;mm.]GSe-pF{qm+D?7AGjTϊЧ0 Wuѣ$MLwmAY?j[Pݢ,Oj]o*JKtadGFlog(N[O̚#z+\#FSG0V}y&q$،Cj`2&S&OIYCD=ҹI`RL69O)20{mAy[C MuXS<0X $n- dj<#9] ХC.Jޥ'KZB(CB r_B\v-g1Y<{ To"쇱"뇱"Z3~+BH};V $}93hQI>ϠMn<6Uye]}2=@PT tnی,ԬڷY|:3Nh3 ovM}w>{j{1]BLנ IgT#S}+T 5u_24DP\ue&{M-2eKF+J5 G:Iqe[ Ʃtܖ(/Q䛟r$_ sB4]zPhl{sIl9W۶!dx"{@>W$s,@ZH-kh^.oSC _BKM0;G*Im_YJ!R΢]SDYUc+zݺ-0bA}F̩ >!{2Bx*ީfԁ;ikh" ʓ; 5AFV| I%]G(1;(r ZdΘvYrW*kZ_b_lCk/=e%}`I xW{A F>Љ?5z~[2n T/F!2!"ozҤq(?G-j5ĬJ*kXQ`A0LɭL \KF"AN*CN4:JӶޕK:NAI`G4wRȺG³$$v H \RG9GXPJ1$Ie"5尚폴뒻\+#6'Cgk݆{*pbBISfmTm$ & Y߈!dv1dLϠ,o$ELヒŵrdoe;|z\!sB~U7KELRiK2SrUL=hRȬ"HGzY^V-)#wDc燭2b/;l>dar%e[V Ek<2j5w7HYf{-Пk-"HTtFspc/G.;gd:;HDeAւЫs+I'zvԑU{يi>az-#"u =̖q%=w0VBKzd^vX8mm- i0 *FfXD8w$XIKZ22MudHGd&@K^,[2nK4B KLSY:w֭bdi5(ȤvlJ'I$([VTݾK~hI쇦K2?4]ZnYCA~|)J`\?|3qZgC'J̭@(y0.;1,,KgJ?tfdCgJ?tfM~G5j.002 u[cTu0F1*c L.AgC:[~&4>ǡMY?qIBr;Ep"L;iwNZ䖸vR5u [Q8BNkLJ-#U爕R' <=e(e*~1T⊼Oŏ%3%ѭtpHq!vΝ4 )L2$)3EѱSdKlS!u[PuZ}yqAe\0~C, >@Vvm5˚9YTC IS MÄ6̿Z$)XsVz #nR/Jeޅ葸>.M*GؿE \9ǥg&ǥ: X!{[ˮ%N2Y/dP_cppɝLW"{X2La̸=Uzy>֝f~i*URw(] K2F#M; B#"G:OɄ PH ^2;$)Gf;dZ%%ܖL];P@z/CQo<]w.W $raIKX:y|^eA(Έo `T%("&{/1Nnbr_ y{2Yݞ4?vyvl ==2I[kQ\&nElvo&mvmeoϲM>?=7]o23Xn;M/ .OBٓKٓ12]e~RXo{ Tz`PPְm(jv+Ŷy j}wCLe[nm0Ap?Eb\e厘ل3#M8۾Q}?I)L>&g9+j$U" 9(#rZSFaTH YdGFqVγz3BT*Uk],C3SLsAF!SedYm2KkIk %4B:S{Lz$I#Y@L+n[ۖv0A+n[_sDP}^-m/\ECo{i㶷,2ZbkR;&ב9?҉Xβ,ddQ%IueY F,)'wYiש!Kv- ͓ CiR%;.hj &CF5#>FCV%G-vݲd\cIF,'[WT 0R4d8"y_Qv;/ xBVfjzY )6v[*m+φpmy"&9X'2n1]$,ocG842vA%y٪U<_ңikL3oX{& ݞq/H%K,MGW,Vg"k} $wZd_~-G UE,t*{ 4B m#RmdeЈLϷvT?;+,%:Bo*22^h=J2vI%z tdL!5PM2ӑ#%yik3@v:Rk/F:βX#P醑Y}#5Q`u- sH :PG0pHgUgYKdd>&t/칦$,KiHZ̐rHpf LƙG{Ke%ػI$Aư&,[\FFz;qF)12gYYK³uELm,>t]ݴ#cWr>_Ă\vY4w;JGd-ٚH ֌k$Brߒ4t<ˎ#}?,%TbɒufH%QȆY:BGFC{#AK6YגeK^pEG,u/;nygߧ$}4%t:q݂V¸mϛDM{޿f#ӵn{;L0 S]~0IsnBI3&R~nB(&?|7yP2"~@AQv9ʹa$ #i?a$ HzRADRA)<)*2R&q;wa !f*0C vuBB,ZX"!mj)!&X6IJ4:6qg{PZj@eěNLJQ;ˆn{^Q(Xk¥œ#[/7_BB.N(*bdH *$#SAsI2΁%I*UGl8Kz1 NRȌ45mT)Q #._ދZ0Z$}Bk^,uaH|m9B%q^GjW;T_ ^e9+*_BQ"L!wv{r4$E-hYhrGߦ,liMq&fmjƖRtFr\lœB2V< ۊB@O-mOieRHfe-H˔-? !a[NZQ4mypM.}5!z{5e6oK1&CX0=LJ]fR>ɛ#[p93|"z$(|*g}d[%+j+)#>Y lA f i E^RqSc}6^zNLd3ԊUR1R]>$O%E$AmJRgYԒ F@| qk;;?$)!Mmok`m;{_ke޾ӓ̉ ۞dD^[ #\E)## l敽 Ƚǒ-#uPֽ5ǒ,Q4_2 Y=_@#<&g 4Fr^_Ym#.awՒvHW%]>(Z$_Yj' R/)22$>UqžWE}(dfe{(P jH)%_i[;גrB_ǻ2ǹXܖJl [cV*䁸-$E=adfq"EXFZ. (e@6ȊΉ묺4LV\3 sȳa}]#,7ymD́6 nQ/ `.YiZ1P[1WrB7MRN`r-U$kPV f͝+ӯ :R&'m=\pvKK#/UFZ29KkngYyl#c=:gi=2xAe3Aےr5\7KTBuZbkZҤ>dښ&xA^ys~{E# WT > ݓܛNP6Z'.u ZĉDs`qNN70nyzl=3D3CH=3"?`ʸ홷3@j-렛i5m  &rKX[o3aN.@˵jS:1K@Fg.k ę=(zfٜK,cn *4wƶT*?\Bi1ּ"o*>f(MZv$8)]6ߖDr~ (rGmfPl8aR4nn"n!n5Sqde=HzΒ\0-ma۴'~^mW N2ʫn,a\` uˤ-LTo̘Q#3m{:(6IrWXKGžjwi#]V߲|IW^eԞ@Sq%b=R?7`#Y.!}fl8Cխ8#(/nf#LϵHV;x(X h[m+pr g޶Sz~wzwzG,w=!vwm%@.4FKvYv 8## :o$:Fv.YVO])#edirobGdX\RfCh)dՠVi]N?B2҄c$}DItD-X.D12!{]UGIf&GlH6]1%nMyvY3dq^L6?dH%Vb5wL—HiWQ&9:NZ2JO%wt1 !ᴦ@g] *4/.<FJVzB0∺ q*@۠ƅsmwBS6t WkQi֓da[ rAl zaG@ ,XkUF"fQι`8ҋ{b1*_nKߞׂ]5H2T&Y_j7.%<3\2#Qgik:%3RTbdgcI| 7L`zu `zZ{ 2#2>ӷuꑚFg(efHGI:ֶl,uA,,#CֲrueH$eQ_;#%}$#U,m K#:qEQ+(#rb.Xy~en䂕5%,3_Xkݟ*ydr}qa=qU֟ĽFI YzbZ{9.uUG$ fxe&ܿjqH!g ꂝЏJ=Th32MφtՏ#r` -}}#3βkdүm> MZK,e#KJY"r=RYҒ/43\ /dtҁ##ER t}Y:+@K')oSYXez]62KŮD-oɼS5zm V&n;&9(L> PGB?| $rQXcgXalPC퇱@ c(5S 0rn} 0TFy9Ug0cR#@Y?ađ};c2{BU?_PJ 0m|dhQ2mDfiV}}dymivX2堮5fG;ÐagkRu8_PɹcDld0>Z"̐3 12?x[9f +:{pZR%]RzD qV͞2YPHJSHkS(m;7Bl@PFq{x4[i1WpZݒ.9Clۂǒ)],nTfv'O2no$I"> M~-7]-6Q`M(*-("["-X+p"yO],ZE!u[ p˩ihۜ-ɂox̡neM1*G"n@,#3:'k= y`B#ns϶|7QR.ݞو=O@.y}\H{nr5|l|i֑e#zk]S;Cw z# }#; #Q+*zn}uD:KsJ([5=$GJѷHq/_$] C֑]OeM*m fP+yM- B%kqݾOWn&"v{m=&@ʰ)=Jo F#˿#G.]ҿOYGO;ZN͕ˆvLi,HcYR|SHSHclȈ޵?MtX,%rE1qڬdU )jgX@uɬM1Ju]crȁP;>&T̽H1.YORK6>ȁn!E IzeK|,e{y9"CRC/KJF.]|WMˈXM.#zOمfeR0-<l yQV(FY;FJTv`2vLkv")5q-mdr/Utu!:ggi1R^E2h)-v%+#1rgԪiq{kZ[Mȕd#+nJ䗇CѤTEbBx3qSR9e$M*˒7ˢ1K?Vje#1겠@ ]+iYq HXc$ }xs[#+þNH\,D$F`7J*q%#鎈LmgF r>UF*PlDH((Xbyeb5xAI L[|xsUe{]'w' n_Uv >8f0ː4=mX= I@O]*0NYGp= ӕY#-pEj#2GzeO-Q5G&'賴GA#2vHmyˇ8xTvyn#b St;l)gYڱbYl5Y\\R#˖+yK'ÿLQ-vg߇mm?I(CY-V8.[<,JmݿܺdmO>`p>[!{zGFW G@""~ AI u"p.a, "0XF迏EjUCR80$u߇p2aH '-!>5QB RI:S8?LMdy;5?QJ ~HX9* !s-<!cϻ縆P2!jma倩\2״u_k*vG`T9oYN/I*5{ɒӕ m_75I.gi\6Rj$kSIlwz`_.vg[]%grui[vV{Yvm[.u;|Th,'D" (UVzdt$mo@uIBgitJ3ty1>cۮ;fz{E+RMOQu=J&Z4Iy\}<4n𷤁&ϪMPHx:QAH Ό&u$IeH7m`WTjy5ʳNTl꡷CF"#)KF#CoӤ,ҲMRrgr6hPu& ,}e H2YqݧM 5?fQJ!s{&m#+5cB BF"[ϒ9lm}dvG\O];F.;K)[kʊ *G6(31qցg)w%#dh#xXqKh} $`qLJC < o:mm]%o~zGsݾ[?!~d9Kpw5yLLV5R0u`[@d$Q#M!TܮgYno)#E(A.#]387S}HkfzYr' ?|`zSpI!#5GGE#ѯ4W k4ĒZXk#n#abs̀I*1uMw󳬌H:IPj/%=2#Z{\ʎ 0(e=,[{QCQm)2G*.EJ%#&#YgowŒAD2 '@Z*- %O ؅Pm`W*m$6r$C` /u-V/JQ#gUoKCFB Jj4>6eDGQI{$[N;K+nY׸*}$FR<t#iZT~AΉ_fZS:]xZ|=;9G_yv-4rᑐ~k2tɏa{ʣڤI*TdƇ|OOe'rt qq_eB=Z,9FrЏ{H#aquUd?R#c$9Jֳ%(<#Tσd50#msHl YFVa7QdBF}.j H*7YVYUGi_Ũ5 k9Vϑf#c|+c/2ҲzIaja^R{S!=λ͗t$#a#=2V2}eY~fSk黕c Yf#`%j&"=2g61е,WǢCz 69Ŗd,#k9+W_NH|l@joJ 1l@["@{2)al /zjݗ슸V7~׽BI嶧MJv۷o>r郑>"~,rVNa'@pRi}ֻ>F q0"#H8A\}F'fDpB0#S ~<ÌA61L퇉1@]1;n'oBZ'62.c#Yv .qأ*`Lp2<6 ĈɹR-XibBԜclw@Kc9z9[?$$֡kt61\nٗx}3JRRDH3Rֻz&BmճY0킝r]/k”RkΑ蒻U&}@Ϛ#KfL2iydyi%SW%+T9m8Brb~{EpŔ U!AOII#M|zL z)e'4pmv–KєnuKkp2xOɾ˒}yM\Yo궾S#LƑ95A#:ǩ}Ґԡ-YIDPJ+AjJmedmR֖&Jjڷ`Jg[›nޘYG&8n춼>1^qZ௔mg&^W<;ӎK1P?T/{TdRi䎑^g"h/ kdzt|>'~GMuмNq^KX:]c\u-뒊^[Jå. .^X/?RYؚ &sndG L) Lqy|iOME2k $̿=K>=(nM\r&"8z[ܱ22e-1H$HWW,g@w.g&[˽y#Rp)@aedpA&3Jjɹ]yS˨3K^!_!%e&28jKl e"\ZpE Yn/_LY,eiqT~̫ uUD:N9_y:p+HE]R9ef2, YcRHʒ19ho iΟ?}$ɧޢ /o)eђ\,+FK|EVt-lDWh.e?-EE7ZkUcu}ONcu-QqƦ<绥|*[oR. 83={q``iLs]Q#P4wmXZl+u,e.K Ս C+- W@fEs }E X>7ϭˬ3dBB;LR9(&;Yw;d)t|!6wU|JDŶ{*n8jZI *. Sב|w~./+3ϟ 骄 *}\vND!̓ޥDӑ5!5ޥ.tP/7yOvϓ _Ɍk9t2wlR>SUdW& U Sֵl܋!I %:\ _݇k^f7tV.].JDVV\߷ZkjE/Պ^LZӭo}/G"6}Įd{k:;O*2-oW\*GJeK ~]ieRKֿT3si]ZK, EҧOYU$a/x ( 0@6-O=HZmʺ$];6w՟o?|??_F__GKc1WֿWc58F9j5QcZ&5zZWui'Roy6]7kyu4=6Q7/ @6 aX |٭sP^Q\;nڝaio=1%@{{.K^w{i>+ v)5+vudžs7y}>wl^7LWS"{}›׏]4uޚ@h}4sݾ7wsgr^nW^oiA{oi1/,~6?װOY{ݾ_G=w_zf|V9xl|fٟϑt۰~Nu';_{'ga$ivzTӦώm*gn;[dxh wBgg-T ;ó,, 9hJ)!1!waôgw@1RՉƠuو7Ak)6h[7b"7hc-b,K>^nivavM)?rۮlj!nA8>@)(1߅tBMC!f b'@#y8!6d ّЩ LC@\7!]2dz$|!qu<;]ۂ!1wa'@v!6T bC.746Nw@**BLcHޅ `{łN8hKn ؂ǰwDFu! ,Ud4"L xUW0 7A&BC@&7Ѿ2 C̾sADDb\݀|/ TдSG!  X44pa  E@T' b"\!qCc]P#ˁ2!b.t0 QBH!8>*]PTSW̦YBT(8AT8ؠzwAd'bk8@5`:ATqBp#K𱰻NM_i]`@+бFкN]P'.z oAomk0vD@|J(A$b(lȚOriMscLJLDG$6>/iQ韙TDQje\EMԙqr]NDSyBH#pn21U1: N}&b1tDA ;rq."3Mv_ qy8.Vnx;'geO &m ,R 崺|xl9-{?Wʘh!MsqX1vE Bk94C dN]P'.zo]]X'.yIn]d#rE5b_/1ܰ5Ր|nX;O8=!MM+1y<#1q@|_GpPp:Ht$п8sr֩#-F!H-"1mH-d?.,\d$A#y'QjՃ;:BDŽAdLDDA ё8dX/p^(BډtD; 1&bCG$DMEM'E&BHKAdLDD7i3*ȘEN`AY6KW'& D AhJ@>7ioօTfi/:bL#v${[A# [RMDŽAdLdڱX d F8A!,/!g11 ٣K1r*B pPCAD; ;b >DHmr꫽ !jH&> MtA WC27IQNt*k!|r~@?+"_T2Og %: 6%ɧ*Xm&TgmNW3;ѵ6Eg袎ȃS8HILs:[b!gٟ@xSx ?$@ڂ91aĪ!^DC 1H$HJnkJQ#( 21w|]CE:,#tS{ s~9H↰o†(mMkE&"<% DD;b" !R0ak&su /H)d&e(H[0Ed|Imt#~m~;Q梪 6&c 1%T L!Lg+k&6635%gDIp5 5!)-Lf*5݅$H;&ͦ$j<\qC 4ؘII1 J9tBCQexbtg1llJl}z5=[ȣ%'\>WQ‡–$H[)&4qqԖF ! ؘI eGA!^ <A# :& bcbӲnl@ހ@|!b*""!j&,P䂠 ~ "<,b8 aSa9Oy&ęhHɎН?uD6)$kJ>QZ))1d9Dg2A_ 1&صfBE[A# H$ xGAjLjZ t^@SI "c" :%C +Վ!oBёxMB? TPm«!4b0#la2AN]vs)Md cȂ XEB=t:_+Cb82IDWCt=M%sG*S1$TGqy.,:0[ ';XuDA !Sa:Cw` ưuNY_Nv ጸl&"7 7i zHuFu'Ǡ;~q.-{ hn< b: n9HI$HImkHΓb8\|k4d z*Ĵ|"# ޑzvE$~DX#jmrq"x*xh;%܃E,b(a{'U{rzcMUT z+! q*dq܌͠ZS5$^5 &"QR &$ ڱ+L_0|8x 2uD:b ~2LQ#d%vF E!J #ꢬ;ꈀH6DqA#yqrhCǍFIڎHXGil=H8&IְcD'H2!͐HGFB$dm5%\aB!&NCQ!K" m#a.! Eю8pGqP}sbc "A&!!MBƤ%$QhLA k{"uF$+a(Dƹ(?d@rlW!MLe;BCB k+9@xH(0 :$/7 6$}R\F(!u0 eMsAS0 ]'!B.#O1 s!R!$9ɾ*yMϕ(|0 /=/5 U#; ^ ;b(z8:ƫͅA; =c~0 /yr ·T|sQFCO# ȸc^jLH [Y#:$a b1wAbL$ǤWCĪ#|'gwisiI!`$;[.Tn#jH6ȐHGA# ֑TFn1&C|jl!iv7<ӎ%Ș蝤u-zoHc#A#q#~/'Zψ%R((:r&=q~l+zHt$e\0H!(GNi؃xG$QdIsK=dCh=HuVGAٷᆐ8vD:Hdi7C6"Q=*1JlqYp->׸""duȇPzLzɸM=1"6&VċĘtYN{l( %-@h]hx$O|:$Z1"RYL@[X0 %fE|&/cErL]D`;e3(TQ"4eH(>&^$$d=%7gD`z\47.`' +Y`"H\&$14i4ٺPbJ-JEa[D"zCVb(^$Q18J0qhL"j'áܚN6"Ub^$d=&_*R3 -t1Ӕ0cq/~\QC3 SE">&Q$ċĘ专!QX*J(* qqtLUb>&^$$䔸ޖ}HCFiBE"2&RmG%+1zE1DC^-Rm"{LHNɮ4%)Te>*"bŧCHV߄Vuz^>طjPY+/_.E (E Ԓڥ}wϓ EZj\Ju5x9(/eEb*EK@1W~mwgBg)r^JQb+RMI swj:ŪݜD="!Dy!qܤ. V6Wj5We8.kUƓ52ACC+79Bs$^΄Y7tFtz#൅>fIT%Vc[%jnMz_b"#e+xګUڰ/6=X| {p˭6<ť B.C^~GD$HE+oRgpȾh^MFt_xcLZi)HNf28پglq(^q \xLNnB~)6u!ekGgzu`A8#1x=fHia ϼ[DH3l?*@arO cmbeytvjHAPW$=6:[ 9-h5J|hUOEhl} 1AP~j:3g9ڍrd5YnQ!Y@x<4a bFr|[c恬QU8|) 7MK\>K69ڍ$Mq ]tEazbc:њ!bJNX/C:G:NQ'pbx y8_( @*N :\YA%Q!5ѩ_ xbbFZq  Lod xxh%ll}\xF_C? :^ I}Xb%v@{i:O1@H bFU+(Gv1 Doghp8CmA$q^fV`MA 7J2EEzqjm4Q1|cO/SgYAĉn?@lEF3͍:[C/ }2p7#AQ dtoo^ejGFN{ 7.,iĕ1n17FzmD7jN|"yFq`*S,j׭2?hmxבg)xboH? .\'lw,·X"8^[zoe`2JP6о ,AwcVc) >"ʷr+z+VFCXľf01&ԿT [)95o7iDvR V Vɭ ֭ n ֆŭ Q 8;پu+x8 nljȭޚ8b '7ۭ=J~+q+*wY[9 ڈu VpVo$V3[$VpRKEb.nJo}&#\(e}T-.4H0n;Hk,2$Ⱔ4۫ԦRp+e3[e)2UR񺤕2UJv)Zte|b6t݇pIf3ߖ%qCRV,Uyb*ŌQ)ZXZjb<\YuZY[<֒VYjXj>RB .!H+-t.'Y9KϕD,NP݅J)r׊$H(7L1/lQ\wRVQ f;VCy;\QVwL\PRLse5PI9 A ᢩJv R] 49񥉤J/d:C_%PvAV[E ^K)eQ dVYj^ ތ2V^PKZi ޢ52Yu{uEROpݿKgԬ2{)GW< Kr6.%ʃk'dAց |.Vg ݧUR o%*[i)h2RF+xiDŋzBMo}ѐMӻl:JOD^' *t5ir5ڕ^Kz4hW9m[I5cPɕ]ZqE2{dFn8σ"k־59JElhσRK%Z"c~Է S5DE[>jrǚn=JDCE8ܑG[MJ$oH}d,ӋxUO$o}zHw1TwT?}5U"Z'Gt߈lQV_JZÃ!א-xn{OPL;ul} ق'B|Jv!3s#z3pLg$Z21###i4$V%d8Ѓ#Ć{iZl} y!q7.&_CF9GF}b5djȨ/x}C1;AD0~`"h#c_C:G1B^Vr#.5dp텢e#AHrאU_ /ądT? ^?!i4 D&Z7@.1negs+y@ $sc(ll|BLLtqm|L+θ9d|ĭ΍6+qRx&hITwץ*|LK2ds4Kv(S"5r -9F7.:ϑ7!R4w ;B^_vn4hGR^Mfh֝OjAq"3i?(meh:?!?:awv4k VރMB}א959Bmnt*'a_C:GHȳѩ7VSxm25pE]?V%nt*Gb} 9 ~!n$s$ int*5I2pQQ;/s/ SyP5pn74F H!ZLF(i( ]ì& FphIn+/iSpXxbwoCu!}\f5$yÆh7!L6k%~FY),<|D{zE*@qF+$אût_cV V|$} Elh7RQWR`=z#)7:_d(i_Cn? +7^ +$Q6SyՑn1Ոq!!~w@:1sCv#x~#(n;o;bc^DPp![ZZo+TGڕ ܓVC,/V3Ş܊汒Z\EJ-9W]*L )V xڥYjyhzLJ+w4<ԖyU*dޮܥRPJmAQz>Km.?xEއD:A/pT]6uJ5TZSDK[:a5R267)DR*NpT8vv9Ek*}GkMQR"AQu<oÝN·T1@Q4y5it8(>𛤃ӤJe߈`(VFd / FVm)PRF: ƈ.wTUΕP+/r*>7^ Op+)%pFp+ľJA$664rvwٶ0rG@~H`իMaCe=JZ|c-$R|Z}}eqw+Ew]R]$U·;(M LCzO3=o7 f9/ZA>7  HE|eM__C)0O|ȲG6Qd-]c=ǔENz!>B >iw}4~(xe% V-w~@_#@=, .nȢ{k*3'(=kd3ADm|D? yo)9}@t= ]t1e2]$+FRt{}+独B^ e0ѧ gPz7B}LzۤA]95"/WBbATJ)BȊuWiGu@GB}@]/u^ FlA/c! ubSYIA h.F$} q9Wu AZnU -z0QC_~ h*D+dD׵+jRe+?.Z4>h'ZR>F쓕~#"(C[RtsUj /biT?ЧhWf)>[e)N@ѭ 幛穷YBaeUW_5r!E܃|c./S'=UA1H8~P?(? ]ۀYu5C(ԂDy{|FjAߖZTUl~}I—ѷsH GHxKjWŧc.w'RtG g}OCk}bKZ#(W[]HGiS 6Yߓp׹Ŷ]IFO[Vou9&9fVd_I{z1oS:eI~@f ?(E~,%O+M}v)}eJ~PR>V Eg9ԄD]먿5$hQݬ9F j O*2(0yoDv)tԼ~9vYy!O6N0"63~P Zڍ;=b{ ˯=] F61:UPȀhIE] ?hRЮ.7%bI$R(ƃ1 "ALռ)5$#h-BIw;oX@|I'BA9DՏڝJ=P y]ҝi_i :ZRg, zF޿i4w^?Tj Ǵ"t+].]5ngAVfSp*EBlB=L/ Mɍ~ZB i!zBVhC T 27q ZGGAB}Z@ 3pbF9 ;/$B Y!B^(Y9ax=fb߈q/3aoW=COZr#zy!de,a-+4"!iu!a0gʻx.dZz!=1e6[ zhV\9WǞ@?$ōdBt{1s1 D^4o#|Y]c_H`Au"3:AG d}d@GޯՖ v ?( _(a:h A꺕Xr\F!BR)L/tF=?/D1Bx(D7^( MZ辙.D7Qg> #>2 #/$]41Bo[| zYnxP%BB_tnK=b[+=hL4fT9AMjB.G)RT٭|P巢@(hTQT[ѭ}+)݄-G# Rr\6Κ&4:.!hBt/bZL mBt9 /uA.HLD-(pU!H=(s1A1 =ݾB!VhъP]$ѓvj7#~+Ftb}s~'R 7NLb[ Ȼ{#iĹ$4Zhѳ`I.UʪC20bIkZ7F3)F RYz'B,x]8M +D~T܈fV-4]BtݾGANq#Xn$m,tDCI)S#{CָզKhS/`܈Aqz )$LAk0Qݨn%tMZrJh9ڬK~ ]\ʛ:htDB8:僢*v }ӟ *r!KME?heefџ*v!{Z?h.:`FRԑ:85tgVyoԭ܆^(}*]5*1ctTN*Ay^}2 R(9ߩ]U4G%]4Gڝq#2HxK:)}8NmE5n`- E~[[kȜ<]@ ͅt|Ф@_Gnct](+EwVAb5W}݈iܑͣIscAS$N-4QIi!]SGAN Gu<ݎ[ ͤw:וDo@~8Uh.-CG1R1-4.As1 0(r IDߡ@fW(4&(ѥɺ@Lƥ&}FcJIDʭNRtbUhf>)LOtL]?hݡ@'U+?ٯŃ&L0xFm A`&kTPZcfgmE DHe!!藭Pš4In ksTo2λ $%3yL;.>ΚO蚿AЮ~yT?*b_>c{ڂmּ 4IaqL7HuDm@^Q؃6Kk]z7,d?DVN&+օi?(/Sίq#H>(mޗRjRt;ֆoFw>c#кYnLȣOYq6|<Ľ:Dwm g+.%Z$n½кAA̪ &Rn#Zne2u4V3(\9(luGLMN?(f2*U;~&~!~ڜP͊5۽Y ҭBh3d"mP:>[PtUy{R Jl|xB|-D'] e?(;UA9f1}E⥺YvPwGAyk܆_]ZEy }sba(H-0XR9*JP e}UՈVЇ ,l/nvZƭSyTSЩeNЧE,HZk@W ՙ>a coI;i. }]"%/玗.jo5v_f fVe7' ky`AqLqjYYnӡX4.r-nR&Y1kϤʫ u)k2 5Zh6B[Fe }ض.3c7}9Ym{ub%LKOO(X&^)ˆ|؄!MR#"H|H,md$/2KD*C+,_k4&Rۅ| A> Gy@h}'6d2i;hIAQ|Pе͇A%@GqPO2.DYFFӨ\_M)K(]C e:}酼: dPu =+.EE18UɗI@]qL;Pv !Y^W.DԼS}#:oR1|8(QqjA33vA)@m67th~UJ3F]Fmhu:D1J瑮;hSSW^|Z?T)ÖHʱ6~чR%MmCBlUf&fVunU%mhu ѷCPRcCti>>(Mx7(nM58ro/JsJL (-C7HAGҲofGK047$L6 ѡ:>us|U9ZfQr!:`m2tx V)U!(x ¤CDjOE (_Ȫu7ո2Y Btg.Dr7Zz'&1CW. !@?$D{'HOW'l<#KW' C݈>%?3l>@rU[0.|:}So<~Sۧ4uݣ?D}sB}s4oD-L]G } KAwD LZ$/;0p4aB?@ݤ2y ]WV,D-~H7oYN} (\:jkQi2 #Or=QpvoW0@{IH7:8Ǒo{2``,Dʣ2'p& F%&ƕ Pa:}9i}YH7Vt7_:ZP4}Xa;JK t2t;,Dw챁>D-B|Q;2tyeo@H"7JƼݸ4Ѝ[H#XGwhDpCetP eAPAe)VX/PtxK\[ԄQ/^zGu/ԫ:} cCNzF!G巢/5#G #G)oGM(jUx7^. |n(C]ZGy)VQ+5J-髙ZݾBvR]~EKm(6^ʠU~)/EWZ*E|y,H (ڢ^JhzG~=oEWʠhz)-ꥢ]<{,E$^F)Vҿ^*2ޢR(z_juoJڥ6Rt|[Aŭ^a.ڠ 7cc{@.?eO0T~IwRXڡPU-ղſd㨪^^xW~F zg~Lw z~Y Ӫ+sCU,U9)W guƸz'Ry,2>9S-wR|+nWXtd)Egl(&Vƒq+&ɂPF٠&v+Nˎ@7RtY`#V<4IJ1]$Ki)\ 5E?aXx(PĢ_.E_E[}LQ3&Q 'iTU J7""U+SԔGoֈ J)|lkȊE.μG,W~ېl mf]e>y2߿:Q/^巚l:Td6jjlA*!ؗ-=%ybU AրҾ:wڣ JQB뮷&|PCRT/kS٠Z'ӞJي PBJ+K8+RPFSi{\~UQ) =}~Wg>ʖۂ^<E?n}͈o s؞Ԛ9Ur7'>ϣrߝ9ʶcgr\(!Bi{++Emzщ|v)t«o9^ShS#F PpBti~G‰ٸ=t4D>B&}4At lԏM֎0$э@n߁M @J= f E?e.3\56yS)~?,?|"~Ҵ"~HeBܥ{25hw#AOV})zۭ؞'u" HJר_Ńj?snW$zZڡ?B/0Qcbb@~=^W-#".DZ7-Vˬ2}衱j)@"x9j~=CQ-Htq_2C~J@PK/#f2v%P\H1~f٫Ύ@{ѡ#>Pa{)@)+"M‡^_W?J:݃4DU{~yPR1m&OӳAACj?*ufCB< r]h ,jlf2CjHuYPՄ N .^Mu ѓ`UZ]i|GbOV Cʛ&N 6=T]hwttK"ymuB6T3Pu5f uH#>D DH7h/@! ?H}h?~ÀPxX'RNBt)P(.'Pb0>1~1DK7/o3b1P\ќ ~ Uf(?׀G3 ]Gs*Nqp{]g"z.nHm7MH lcځlB!<Xۨ/F@C$;*PUhBtGo\k&~AkGBƏg)d"aZn}P;> Bt[%|$"u2ԩib[F"wUDKg)eIqCluۈd'_PC!Aw!<Ø`Cꮥ,HG[^.-ek}"Qwwu Hmevרx(zRaջ*Dר;rTrT?Qfjtw1 ٣9{ zcqoYXGCm ˀ ;PeR~}:F>nrAb@@(>IHi :qP7zo7 f=蒼z>*}G⩧>dib*8Nb" ss᭘(U)vh A* }+ӅGWbѩFbeh(N1 E1K@*]?Ӑq+KKQfrteuRx B:ox~v)Cg<4__tw+]eѳV!*kH}d7 V%4Ha4f ɃĚ TQCUÒ WeCjB(3?] unX6S% z>A(::ФaBH12l3w! Ly!Pu!zBh"z/u0X)9_ES_R&by zUN+ O%PG i˯Z.:}Ck4]?P|5FcGO,AtX UUK}R|(E"8  5䙋9 htѻxE9`cDV)NBW]fu>9GY Ⱥw"e[gnLjw&z0YfHE(ǃ"?A WYk/vm :D.a(:] )ehgD 4 vBQɧMo{zT?U%z@ht2|RGirӰnQ2'+^ΓpӏPV:sz@]?9~╡/MvG5KHyx*CfũUszLcG'}F# DFsBR#Y># Έ5 x){] DR zRo6%Pt)mhBU\oM g+P7RʾJf֏RY(m. ѵ!ҸSf0ȃK dYC CAc{"Y!&@Hw̠+&f"߱w&h}]OCÛӠ15-PD E˸&F3]Ds S>DF,bEBtHƺUZ;T5r:ϣHQ6UsiPsXo:%TGĶ:Ie bل"o1ƚc,4 'Tm]$T`P7=rF2ҭ>Z& dHĢPA9bEw$ÐRsbя@izrMf.aaʐ Sj5TU]# šh : i݈bo(F t]'yϘLV ]@t8wrT|PTRS+i9|p: Dt;n$ݎK.nŽD&"jA{ԆRB)\i|N8 _DsBW@У9樚.ssL>RGG9>M>lσ5弄j|h{MdcMki@G/j|f|ޜT2$κ3Т} n4>Qڼ@ oYhћ 6~ڠi;e7kc߈ :6ovQ,]3_^ޗP ? eAPH||TxYjҋ5筌6l@窗(G^J8jt7X<UI.J2V,]GVVaT@'_AxN0~!QsieF &mI1Q.:,fp/h;z)J~yr@Ge}dtQAlvԣ2& DZ}{#ke$<]nؿf CtG "s$Fl#ef#tY6C+4>Jf 4LAODUYit\<*э9fD`*2h g]#cNDR(RK-QXv#>)cBT@:iw+P@-ᔡ5J* K !Gc jU!xO їnĚ5+Mڬ^oE9K"vn!t~E)ڡP㻒[C%\PP*ʠ-OqK ݝ!㭾:%db%b{1膒n)sRj;Vt5f)uEwz^Awur(|CU2\+6D, %@!tUE䏔"tMP4Gcצ*R:ҧJ%|׹R/e }ԇXn'Z]~g+dqT7֩[l ^,5GŚEXYJU}ԇXSKM^e諞XG=I^Pa %R(g@}o5y }=RƞJ US"Q3ƣ[m2lխuz}P鯚h_j⫛/eP_JN]oc09 %ԕG2a(w1u TKOn=T(-{GucU~mQ;~ f۠bхwT#VՍuV||Qi&>IJQ,붣>ĺ 6Vj<9,>_% (R|yԇXrEGl[`ndL jCzՏey+>^XȘv)zT_PQ{|>f^+zjCZF)%@,=%n÷+PY.G,}9QXScPQB2QA'[5ķRto.Bol䄑:xJ^QlEE| '(i_.J Cy=V2?dhh?ӑa]G~I65>԰}hWG5gLߕ4QsmPVmkR y/%ʬڵ~%لJZْfP ԇX՜*;U粠]Q—`UF"V_^Tc@孒6:XWZK~n1iʬS Eځڪ!t9]W_Dʎv٭2_Йb / Ȗ}i8S 2%Td,#>J}痢vK{lT*iXΛ̥r,LV>ʩ[z*>Gy*K *oKŏrNjFXfZ ]L.TRb~kqCVJp.y} #L[efVo (}Q (:*3sd⭄/\U ]z?JVޔr*3맢jUfB,:ڄ?Z/OW4y]AFqDZQF*is"V.E ԼU&j(Ȑ>s0wKQQC~*\OR5.j5Nߞ5?Uׯ]tXR]R]ͥToՠ(T~pvERj&*ϯMRxEWѪJ% (:D+ˣ=ծqHTe,j.E".o*^"JupWV=EZo%|B~;Te(*ldSy+k*X2o Ca}aWX(Q\ו/ ("o8]J!ZtDd~ϰv 5nտq*z~?Jb"PEg+v2PkKj,XoHy bio9KBDΜ;SRot+/)bnciqĢKnj_2?dP|Į3ZPVe Î 2ǩJ\UCWU 8_Jt$0'Ը5e?% %P2m,S%KQ/q*Pp՗Y6֪K>o/Mf=7[ޢԇXTۨ?VC |ՑaR>RKMDʼAgEz ]ݔf8OEG6E5(;k(Moa.[QC,+u7K,q*ctd8+]m5,u}KI- N!b2W b7Z(:S*ҥNj_SJ}ehת<];?ŗ#fߥhC oT߸UP2\;ԗjRtqWȐp,ů:K}pVKy]ݗު8 get]\J!ݔC_vG EϯDlX P|!sY6.omEQ6W iePtv-u[{Dj,4VRoej< @0QtyR̃+֟bѕEKaUo%tW(}_ÎA\*VX!:{@dGхE"KϯJ}Ux_cʶ9oHWK{tU"ݡ=+9?ʛʥ.*P}{)-şʉ ]JR/%K] >@,]Z5'xWd+օ{T_{DD3*EwըD?Jm5C5FR"}>@j}{_jː/(uݍ9_ÖṙjYѡQ|Q6V9U ~菢;kGG5$[UVQF5ejłS|IX|8BkʘP~GoT%*>q(dG,?E)ّ!mU-5ѣ;0>XTU*)PV!.ʷTުծW\ڭB6%| 5ҟbad+NV,4U͠V|+{.ZbAgj5nlo%t QKSbUtR (w h͵ͥuC]ǩ> JP3 G.ԣ} 0(G,:F|+sH=C:nĀG53K~fH4PtV_KgP[| ?#g?EW9J-XK /@4R]o2WnP~gT)֣+!uة:=+?Zh :PC<;85EWGXˢə!kё*\c9(  s|M?b5EMiP(hz&/.=DSK!Rv%WrO#ȰҧKX9WM%hN(%:uG5N%Jv{ D|oؔA叢;mj@%U5QF32\~}c|W[tzG5ERtv JIź󢈕Kё͚D3l~ܰ6 1%P|u~Y(E/3VLq(7ad,%L+ :׶˖WY}.R+E::l*B:=ʥ>U"_dB%2w):Ks)WRڠ舽)ڥ]󭄮Zo] kVY/uKί_R 5TW7#b|KNĢ[RKЄZNj2PS 6P\[YЙ]mūy_] 탲˻rƔ(Tv](Xtd ՟Xtd) RtrW EKy[nf9]{ m, ?cѯ-\.C5(W6EPAux_UK}5m, ORpxj)y"eZveP>RC,+O#N(G?UަAv%@>IJS/@].Aѻ宥>IJSu:8Uw)q}/Z,b)RtqW>,'];?5LĚ\rnjXeE 3|u CY :V G)ڣ6Kuz.Aj}}ZRXM2zuxIX22(ƄJJ9ՠW1NEaʡQNU|5H=3Lm,@5=k T7>gQ9NEߺPzXt<\"s)ktW 0Ҿ;Rr[e1u,)P ϔRv{-&XLVBתZGѷwysbS9EwVFRu\tVWܔĒ[e ~P eA{6h׺~}9{}ޢm,qKIC 5JTPIcͣ]|.ԇXTtۄ]籋TO:S*]Z\䭬]}Cb<C\oJbg(5_zS_YWEd)K}jR3ʐV^k]{wBWZڬkE{R2RIŮp57+ݪT]&;Pt;2#=SNEn[ _%lSuFF[,E+wաhԀWMRt]ͥ诛MyW&|)Jhr+uK5ڴB[%:jXmrn00K!nS*75-EKGwPB R ş\Tj zhW>Y푥càR6R8螭tdHre8WA]gh} C>o!VצPAmŲCo2e=]JlK/v ߨNYIgЮR/tAp5'}:7%v'A{|):X]uA\[O;*O]Cl5Rp},̍ҽ 禮cyRp9ߩa69'5PP(Se}3=j@*ƣbJ}55Z! co"֠gJ)\Q)24(OE+w2,%ՀA[٠ml}q{Fv`EG]ͥ)A}߀']%̺B}5,eC[ʠh׮b)Zc/}_5ܔ ϰTB)>ѮjƽRT^ee4C5A9}P%s):+=dyzBj]qlhB,RuyncJE -!oRN/|U튥Fvl ƘPA [%m}PlUs((~/lǎv̡.>Ko4(WS%~m;A9KjS<o%Q9Ѯ|oG/u+$XK٠W;҈)U\5-Xx*BPY]1K==)fu6RlL=cw4(Baq16CS+>(Tf ԸXşc<[[J'PO|+viWI痳)24(J3~ƭlj@ZxgncYOu{b'| o%NwPiu.Z>u@5ET*p~P+>(xG ] Uc)VVl%,V ҮMXҤN=JnA!C^ʮGtp{'Fl\.~zvkZ͚OWsR8Aŧ@O.5}>j!J ̈C%]RωXyK|zrgB}1P ~(QdW(U ݵ$!ƲKƣN^1J>TvIdC5=[I٣WlJ"Q|W'jHuVȎX5\J"Ժg;^Y5nlKM6%t1>P(OĴRJILE,Q|OܮzVI5oePy$f\қ]t+ڔ%] ,n+G;E;̑ |%A6/ RVtlX\~K250.}Pƃo,%K0.bKѓp o=D">=dJ:5!KorA,2}2GkR/?W2E]LՆoLA5 9є5ncp/uK+C%S JoUeXJorWoOߓB_*ūĸVԪa<*ѐ'UJfǺS@WxvdvEIE/5ŸVO_B_*q魒O_BU2-e^{# ^_6kUNLRdV(eJ2S ݩث煮CV߮⿓%Ӗ %sjd\_C|c u9bU5h@PlJfrf{Pƃ.Eِ߫)q =R2gC,zƑ %@d/*FjWTSd(u;.=Ckh {@&Ժ}5TzW@PAJl &P թjbbC,CՇJRaK@k,E_N\t1_?0(T>)iKڕ,EbaWfTrVb yW=e)D=[Bb5+P/BoJR R9_R 3sm=ՠ=Cڽ:kBYրKm2C0.!KuFAʮbM0.9P ]o"n[_'2RШ2PtT.et(em)U z}A핧u2dHg&Tz2:>Nŷm|y˯=GBWsRCӲe]_ >֦mLCc)&. 'M]ϲ*:D'UJ6ҥ苄Kxٕ=Ɵ݀jؤR߲rqEG5R1sxnPr)ob{5緆BYCWC~ri5|sSWEJPrh*b]KfR(n/ŏ6eP/=?w3|)7jBO (aSTT6q@*Kу ?-gک^9Ni9˳j"l5(_jf(3e.e _J j96j|=|*km9UU\JUvjXXrDA)RP ~}A d DtKKӞ?{CRJPR*P7$*ÇX}Rdk˩Pt m)߻)T EM]ϲʡhGvְզ˩^]OiG~N;۩:]ĸtXCYRJ lQUJ!ae3(Z2(Z PK=ĊS}r<TF+?T>TLO5^ ,P EWMu(l)\j@Y.5{~8TpR-5鵼e^MCك2V&ȰteyIW)tvb>TAɽrCكzޫ׊qt(kTZV1B>n5PAM(PEϥ*j)PA5惚PKrnRN7RO4JiKe]{X*V*'C|,矒֮%Jj}PXO M6NՔy*K,OEwST.EXt'PoJRtWD~DfY:=(C{B?쪪!l_%ۭ@{CWɤϽ"%BS R$NCNEErKicJ۩TS S}lQ;FƩ>LRn̉P'X 龨Guϰ b{*"þTaSѝ] ( :TU)V궣LRʎX9t)-9K=S%]2NE%Tkg?=R^e}~V*E~KT}Gʹ ͰC[Tʟfڤ2U2P T_)pSah,2PyB ҇FBU UT$cA201{>m͡gߪ 5˛V[er:&Jڽ *oßznWѿY*m*nUYAO9]Eu(U痢+Ynهt=UVUcXoUyb*k>dhg,CiPv*/%{W[e*jBюb<(3LfX⧢G2N3Ty*Cq (]+*R•yCJTB/bR\*q^}8=Tݡjj7uk EJU4nVo)S>˪P vC5AN! S=8=lǸ~VX㢳j<(KcsE XՇ_=Vo{ =y_%NQßWVU[e~fhteR~*C`b]+kKJԼU/[U~*֭gyCyǀ[e۩KE{cRLj+eB'Jƪ_*}wiP= K=SC3T`_m^Wôw(;c)oK#=|P5_V{5B AYCzX?&b]RQb djW*0U>54JW,h?8}B{0_ab92̥!b\?CWn} V}8;ڃ2Bo_%N1U5QCIē>9rl/5_JVyԐIJ$$hϏq魪jHԉ*TU:u, Ey% V ѫJpѿJ CAU s)z} ָU{{]ԨXv*CȐ>R,ԄS}vNJkP2~*驌VW^R0 P<8f *Wҟ)gH- /7p2TX_owq;l!Kצpף(SJ!RF҇XU7Fqָ>k8\ŘPyLg*I?Ö5.zU@,R2dJ5ĢO)s|ER+B}XǚPUc2X>'&zBy)Ģ63aUǪ63KoR<}rb5(FyBo\T#JC3ۗ]ה_Qp_:_!0 PJWET6>p̥)gEtT%B}r^JUӻ!?rew(}k\PZ-+1.zq*gdȯ,uka|WIbK2dHWJuSelEMU|Uw_XE5b}M_,_}fCֺAW8d4V oa)n^: PR9l~FPT/a7K/ݕ^tXWnJR,[v\"e*hDŽKQ ʠUqlzb]E%O)uT+(uiPk*Ka\,=ePyWD)dgB Υ ^ jt2R]WCXC4iv[eTY461_+)uK#F+XɡO(t/=_NRE_j\D5aн;1r|{ʦ*o4Y6C+___Rsʮޗ30D5z@,g|U)/Z+@oZ)zQ xR,;ʐ!Wn5P*5n)a)Iz޼UJҮPMngYrWIҷTc*?hWYoKx,+ *:   =ѿ:;:a Ʋ +Ocj85J!Cz-?ߩjHNjLP{Bn>qڊE%-ʗ?\g8˨gY'o-Kr\{<̲9QutRRtwϰC+%p==!]B&/=)_/g詜lKEG,Hw:/0ʺ<0.^>Vʩac*,': gmcG"lb2DؑPvoVo ++K!)|&{)ĢՇXR&V oMV[kKE ”zJ[S믣5JJVTUCKS2%z*aZyS]ʖkD j2P)_e]yo )3Cw"SiwBC,?uCTJ;l(U֕W^XzaoKuZ.KUyN)E5 UGXV,ztB,^Î R|ehx5⫬_aKaUڌ6P35+)Xt2!ÉX6ޡ㢳lv*zw>_Tm510c@5Z5s\a{PV~ةP!VB9e-'==CZgS ڇC,jgR!?yyf8|M=դb)kPN4WYe=CO?3D&7<դ1r;դ+S@S9(zVJhzPm,frN{}BR_)Y!C?> 9S9ROOF{>򴆞c9w󠕏UyV>FXU⪗B,z-G+=UDbMbsJ bgRE)%R!VC,B,Z RT"ô?Ipf)-?A{p*4fjdUCI_CJiM=dP=Q&n3>X~TM~K:A *o=ɔ!?TQDNEDxTsS%?u\R(KsXCY8U>3S%AzC0 E5}O5KWcWI:jl[%{@5^T.EPK}•vrƚ7P %Cw)Q+P6/p,Ejey/{[Uezv̛Aa7TaU#h,GeFU!@,{PAͥz[ҧ߻Kѧ߻BM5qUKޣQ.5qv/7WkȰyJJPC5AB ?/EX>wS.Tt/ۮ~\ѢἋ#ÀJTUj@MR3T/W|t^ 3>T;B%OqL(^<uR:<]pkR~TFodB (:ŢGٴC,;>4?ю8ް<}6NE7Sэ=~*pޭASGVBv*kS}P!í*J:}B>3̥tv*}*zaKؒg1W2 mW EwS% E{cSŏr~-Pɕ@ĂQj﨤4dPU.EzU{5WIہ|3֠3ېS>Ta.@G <ncI/PQ(3FG(~\ n8ȆEkխ~v2UD t+M{XX|ҾTR7뽘z7UJ隹eLtgĦs#͐.EW{|n!C #*nP~S9õbRTEźU1@ւ+ 8դKbDU3J: ]Q~`{5JjDǸ䯪QjX|η+A_I?Gm*^"ƭ2^lW .Fk_%=T&P EE@,}Pr,|t&Z?c/CX3J!]@!ÁXk.5:E̯_ĸ>9j,茆qC نMzX 㚈+_eRCC*z4qa\T,X<{}c@%2W1KW~ աh١VYUѮ0NiP~f_>^=)5;"igEoPsQD5ƣD\+iTBR)ŸDY)͡tVt9UW+ƭZ ѡT)\zCF}EoPŽW( uzRU"Oʗ{vUKϯ>A%T*SHj* =d}^!W+b J  RE8&T>[e!RՐZAU {v5 m)sWUgޠfBE7JyzE.Pu.ӧ!W ETX=mR_%BwʿEhK_t|*lWŻ 8j̿OdHaP3^ (o/3C~XP%Y!WV,޽U6;20WY6 1@dXʂ@jTo[eR q~џW4(i8^Pq_%2QPyK$*n՞KOCɭG)TE_%B`WE[]Q_%26XqPc)'-5Q_D膻m\UbM2 {k_%BwU*;q_e$wY~.]kPUo) EG[su:* +tRR-6?^b92@VIXi_%Jo@)NCmPr,Pʿ> 踴j8ǵ:j"ָ%>/k=}j^S0.Y>ޕ"à*N\*E?J{weڭpWVG:C2K~je5=}۸jz|зr +mȻª4}'jkR^aKa yWuգߓ _%-jP586e혣gV=hrh_{їTv6o䦐ᵲED>k}#?Jf(7^B^Yghq tkEuUB_+|Nj^SCsyԸUbtYwPP *q59fPT9BUʠ5 G_SJ(zj0=q俲67zCk)ўjBp~m+_տ=p{~ }z_u(}q~~M bg ߙ6R nE,yWb["Xz6eJ O3cf[e)q*VYJJuYT+\$bWeHE2ƻ+Emkt) mJO>Ubz%OEwJ1.:B,z.k@٭T?hP~,}+ޕ&=+3(1KoII\~,uwj>(=5)UbAlcy)Ģ3W=fTFgK(U2z5Ttل[eiy*3m@5nS9yPAɩ3jW p1.K]Kƃ;*b%Δw)ޡoTz*hUG~jsjJ,Om ? 0.%"Їz{yb@MdHKY?kX)RR%J,ArvvңC, (zӠ6gX5T@ռy2{E\R6K yPjy~ÆzF)5b+јC9jy~!CK!ٶ qu@?Vz5ne]k}y+o3{X?]PUCzuT@ѳrָ!VzeDH[eUNj^޸U)uT54q3%̈́k ~{.V#ߪ_kVsyAL*q[,3Pt?ux?ʨaݫސXkYJRte?sRݫk*7>Y z-{a> dj_ĸ~^I_eIwEw9o;b3e`fE#J=SyQ zGWYj,ElD;W@DS6SKv)t\ ( RvԸUPtː΢sz{Gk.5ZBU*#CU6@R({Pu=.͡ATR5j}Rk~7JPCo9ĠVT|梨{GҎX{vTSuQʇ KT#!:z^Rto~*)ϰTX!W78tGøĩgX }*5o Z&2$JB1k'®~30YuƀRک0PCrhY!J}/zC8uB36.A5d.e:@ю2)uK˩3g|XX~ ~hj)݋#㢿R!V~ `8=v*07=S"EXJcWgIRknPUZ! |ϗCEG/ѣCRyF&xPj>hj4:2%P$::ӋP0yWMP(~ +_WPWQ~mtMW٘t&R6ަUWa"V)zڡlLQBGuMT>WMƸ.Km6އ^F5YIf+*RFAswoCILQ _jଵQӥjlY6:^Ea\c)8#-EfoncUwEWogq }R*]PN+E;dPnc3"vw>.2D_,=*փJ(<}6-%^mRtr@D o͞P]TC:Jh)ĊuJ*P㏢%>2e5 (6yjHLRljf(uӖRt/}<Ր_ڔYոWE?;ĸ蹬_F%Jx*ㅕIW!ְ 4-NE+]O9&SCQX~KzFX7>Qwt\NR2zAi:b!CQCtv,ukR[]jPXJbOb_3JƲဢ5U(m5Ϗk%>צrB (烞ѡ^b+z3@ةj ?] z#OEWfSE!V@5)ρg_?u+j})&5c"V“v:EgK5ęm,ic\쀪7ƻv͜K&q]?yViq7 Ăo]Pl͡kewV]ʦPV OUiKsy5ĸ5򫄾-wS^7Ր!UAmfXP>å{`<T`\5j,şL+O5i8դwD3O56ǩ&=S<ռ]/.]ySˡHm_ u? b)ͰSPױ+\4V^<:QG9鸪{;Ԥj۩`ɩ:(9UV ;Taՠ*+Oi8#Oa?U '*?l *{X>d((GYTBge`)qP\Cqސ(PRa`\0+!5J=0x 'bRڽJ҆ 6rdHeνWE,CCq9JPy]Ҧ~NԀ3v;R֠צ:ؔw(E,QPMBV{øxvj&b% WvoeXޡA ԼwEqۄPyzPKq9{m@6:xPrw_g+zEO,j[2L(~Ʃ1bކ_ΔRZ%_{Jݏ+C5oXMQ z`Aqe{P:1.e~gb Po{ 5V6r^oJ;>D7 Ie)dH@5rtc= %]Ut>L)9k+X/E+ &_wcVPPU¡Q^Gm=6{_ʠhϿsXt+kjgnծ)E{a\.2(~+Pq{o+((T;CPH,]^Gn*}Q9km.ա.֯! _C| uˡ}AV,X|{ (z|w`^jWKɀ_JK)ՇtC,t]C|+Z0]RXjPz㊮rBG)u|J_):A_j+/6*j_Tog{u/<z$Z˽rE܈5j!VEz/"ֆJ |hnjX\Jto,u~?*UX)A,T7Êyz!fJ^U l*sTE_JKy+t/[JvZwE]9}Wռx|_YzgDj`vn,]^<]+JB ޹r[ ]K!Ce**CGʅ>E%EYj@95g80q9dҵԤj#rZ"V}6(*+eQXwX7jUРh:beW@W)];. z4սhχBcC\ 2,+h8*5G_|cWus뫜l8VKWV5;ʄs)]+ϣ*?wBҕ ۱/'=:#նqmkGʺJБ!t;!tp]+7ծ9j_0Cw{ ]!'Ơj@cx@Mv,3틾׶.u| new7*JwƢz1Qk+Q=OF׀ZG5İ͐$K z]\o*z5"PqK 0GUePUp^Tѽ eTbQ||*URPXt~ 5/a\BMdhJ 5(PսqBo, W< 0>Md8ea4;>Gj >J_!E{cTů=K3\Ua *?)K^fEZV~Ub\Qb\j QW#lRE;*JD~U3t Y4E [ ؿJQ PFs/ÈRȐ5vYJ7C_t\/eEψ^JJ#kqi:~]?i.2B,_zDE7JU5x=(.Gga)G׸V۠ҽrK Z[ (ڽ{}զ[y/T}{cOX\xG"s\΁]?*oeqP *)X*E w{\9 "8JdHxPEg z7/Jc@zExʑ_%BGg_Eg6d貱j`]K n5(/kA%bWU2;.MNd /+fQ۫XR/Mw5hrV^TjF@q,j}k+WiեT؆ޠo\]5]bKT\(]:&ƥPtQ"CM(z/uw朥C ]*:%]Ut1=(BnuнTUϯ+*x뫜᫆]Ut.OURڈ6Tvﯢ땹W-o5*WirM(%J2U5w{)*UJ>9k:J3n vlaP^ *IXȘPe+Ct/]k˔koGLeE׿2΢2(R9Jkjvc]ʜ_EW|2jEW3W'/Ƶ;_t>GѕU ոQȐov_nQva"*.T CPycC!C~k/(tkPU5wctUAKQ·ȐUN6AE,)qѳʗ 5,5O,ʹǂʋXt3 dHAm 6.+As6U(cӯZ)T{ՎG-E j^Ě_E(+\:;Ce3*:aro a1Ԑ_.bo6·6k#=@r]dgz^F@ E K GX_]ec2:c^y=GU6f@-ld5 z"@r EVByW=(~_tmU6tȅߨƤԯ ѽNkX E.bU1KZ/Tw{TQ.W 5퍥.b2K-(z$ *nPUG{_l@yWV(~.Rƙyu*ZmU?Z&TV<ޱjsTRȐ/VF5P~W&R9 ZGP RX6b`\rl}+]e#&_5{Ś]D2(z jB7YZ)5R mAiWfw\6"*WuldUasAaJZW WWUxϧ@r&=#qԦs.bԂǯPUQ Mg]vWU C@ lTO.SvV{ecy;uj({S%ԛwtB_(5.B9PePzQXy7 ]N,+U W_ B#V(*ƼPkPDerݎX~ycB,ZnO BUތk}]P(^)Jc~#쎯oeED^"VeP,e'< ŷWU:ߗ7T@>**DXFC3v,dEۼPv}쭤&9۠Gss u3y+P^Ěvbg ݆ǚqa{|]'2BIW؆ZP;7v7۰R&jHg_5=(&q'lxn,G"Fm_f?* =UNGU3%]e FWUPCڇ^=bŅX(&k@?F|eh 24w!mnc=TndtG_6Yu&Juc~*( &kW}QhMfP1pEEjƣ.bV>KnXy*+î2j .+*︌*_)k{"`\Շ,ET7IVn, B)TAZ2_LBGMjuɮY4Mo,7~,7be_ o,㿓e? o35?jvcRXi>k\L L-KikWlAyW5wԂBu=/ՍVBGdpujB (*iPy&]žB 4+]e̽{DX>kR^"ֆ?x'w~W5(^i+'bUG9NGXl5:]Z*oZ+ʔ,y5p&VePGѷݦA P~_C<LHytN5{vn,ٍq{wS1.w62*pPFrtOGm.(*{kB/(*(!0JucƆ:}HߔwUGՊ*b=P{雒n3LsB |:}߅=J]P(QRXU=zs#VviV5jj*eJC4(~[=6;J]Ī .BM(z܉ Vo.wa*wqWD,Qnj'͆e>}'bE@6Vl,ٍVoOZ}FM2*Qwij@Q*/L66bt]F~Buz>5Lϛ.Սe&Q/k/u>FtZ(z4*zT ]wse_Y-z]UOE{c2*3IҁXy&*Ow)w.^V_y@mޮ:"Cc^֞BgeG׉ePk/u b]r>.z)Ģ:=WF̢}Q޲¾\9wSmk+)G{z6kV5=jA 5N6VBͮ2jHjf&fǚ|E:ڬjD7PXʻt>WvW]+2Uՠ}0j = Uf |+ۯ2ٚк]y-7Q^Yӳ:«jAŅ (*s(]UX֘_±~_"KucRy g3W<*BJ]Ī>Ğs|:6fac=(#jx(zL /ՍQgڥ5WG"}U<rJźPJWY Kb%=s*GxGRjv̥PG 흡wc傪>g_{@aƦWZFn,LXtxʾڨGJ] =5ᨙ~Q3(t/_5{)*lw7*byczCqyONte߶AiVv&Wˡks;2< WX~{=HW>95(ҎRab\q}n(ՍesLdݭls8uUF)ꪪM|FUMK* W9h+)l*GlPh zoedڗwlbvϡʦҎREUhl TSgnvOu}{jV]X{E0&P(TRߜK& )rآڐmx@`b er(*PTy] ])ƽJTE~]D5+j jJ~yoʴkrWgƲ׸%?CR:t8tTTtn~glQPzL{@ Qu,:.ơ~}jS@œhD#YtSKԳC œ@0K{#06Z/9!ޠƃP1]mE9nGoRFMkq\woUj2h@=K;bXKI%j@+E*Ee@C"]W?K/1w%=0wwįOD28|Q*oeRV}G*ѤODЬ1?F"]~/xW{*Tj+׀R߱PZQ9%b BkyX(zUV b<23XD.]aTbjV_6Ut?f3ћTRVU9E kXSC~ (:oXG^6D!@t};v)F‡X% -ļa<*Q5~9F/]֡ZP/-L(PhZ|PjPq J_eoC RˠXJG,czw% ^Ps)e}Z@ |)Яߪ3_Ap[%۩:}[%<_t- G@Rb2V bbޠ5#s)6Rʡ/ƃ2(}PJVu+Xt/6Z['XFk_9hE(ej>(| C/G3Pr(PV(/S!oa|oPb (gl-~l_e6ڭ2]K!F@u(JK>}Ew;d_J >QO ϽVelR!m6^%חoq-VUf͆(C2$RHZJ%W ^[e6WI5]2!^/C[e6m%Ġ6rPq̆* Ka]~h6WI(| bH_~}B jPrF? 3 t%+TJǒ_v5/@Ka_ep!]y M]5 1(UPJ/Wߪ/bJ@3(T>,cҽ^!EA] bZPK*v$aQ,Xt1-%82_JRU X|n%PahbxUR*owA߫J"=%|l*%XGּkdOuhPT9:˼HvZg>Rzh!~ !NZ!v5|XJ诛Ml9T<}5|MlHq{dQm%Kuԥk1:Zg9ոμ5(BqdS}>ZvB,R=b)*c~<.j0p*3툅y(u/Ɂ;e#~ eQcAo,3gAmb VW*LJpܫz2W(2VE@ nN+&}g ʰCъIbF*3Pt8bQ]IbYJqvbJ[ԭf2˥,ԾT^g3~*FTP& {PX! %P XfQV$3ˊU٠3>(lcgEP~2CyC'T*Pj0<,9@ʌ~ Vca *Rۊ4G,Q]ٯ2_X@忱Rzo{,VM;GdnS7KޠA٩ ǵ?/%g6][Cŭ2*TCoiG,^0= ^/AaƦkbۊ so1=#Vq zDTA~PY4=(e`8UЙ-;1nsXpWRr#NE+ eJ2u)Z& w"Z6S!V)~͡pwU3KXf++RtQf|PxUy& Ej6(<]t?o/::xWx"5Z5fkjʭ2X_FyEr)<jf#J= D*9]<])ؠBlUgUtvWk긳 T_euSwPZ.U.Pt qv(Z|Rha3[y̥*/)KɸUha/Žyj֓]ytQnclzyzQZ5?%B*5JlA\PrduگޠpOFUG m %K2B5TPfblhm ԸU2G[yqՐ56hZsS9ڡhCz/m,=)Obnm/ϗa A?փ(+EsNEE{W3=Ja #鈲2"Q6+^xv/lЫ/%UdKѵ6,KK_t̻-%ZE;TtfW E_Z֞vQO wRCtp_0TA[)-,eKC,iyەlW~156V#J_)<F+mAGo1o*r>٠y*?jWRGo)>_iKM%x>qy2VqKYUmW/ײWh]Ͷs@Ƀꇢ`mW EGl)WdSXunw^{vW Er)쩠k7qX*=˥@kڮK QNWݕ]?D+ױ|PkDj+,*ºe+ӣLmWr}ZtWXk]-ʥ/5ƃjv͡df,EDP/Pk/^Erչ{>Kb b 7d@Ew-dq _rAikE3)]9k!bƦ_!֮ ®VhU|iײvGژhBX,Z:r)3_A+4Z@_lZH\"{6x=m1G 阷ZZpi= ZHz*ZXVƳpZ9uY ֜{=Qn>ЁX~FG,>F(EI_P]cg9ydpGui=V6􋞯,Oo3< ȁV\-[e}_kf;blUclhaD'4?aޞ]%}9m)N/Rk,EOVL71ݫB^k1{UonyMŀjQ|)vS}ǯ5,R!iY4b zUBʤoSv{9[G Fɑ ^2TIߦR~ҥnmD2_twm~߶Ge۹N9ϱAxHźVKb8KURR>mjŢU-[ozJ~(?2j\fMt@ *˶Fv(1_kӕr(^m5ZG.@m{hįPåsnאqBOeNeC:Sڡx%R|OTWee/kR_*ZAkcZ)OzCJ=C:P6y(Ozj/so,;8ՠC{%PXku-G| SRhKKiu=PBQ7˂%|_ejfl"P|Dů2ZQveK]̢m-šb);uB TQJ3jl|G$Dϣ_\J6 Yx]MD ]f~W cfy,UE+4ZVZs(Z5q)D.:Ԅ?$LOV(uKl62hL:zp-'S'TPJB XFm,K(WgM;v)滫ײ2;v):xQ~6J+e-i^yyBKR?snϗRPWYDZ+x]lXC }"Mg*x6W(J(ޯR~ KKaw;+BR,/GZo S ehX2T4U2>y*-5G* -c;YcàVɌ5dRna)\˴֢PV؈&,ácYFoW7B:ϗJ9́R gRmJżͼe*bRUBm6#*kgh痢#rFXkVˋ!2OZ,k,ӛ)Z[;m,pWlkT.gRd&]ߕ@h=ʥU9WH+|EKAʮ_db2ݗ~QQ7_BYtJ,[t?.G iſEXB KZgí_|_eUZ e>o@uya@RIg54߆VU۳ls 8csȡxM|إ)s(ZfQ3m+„WpZc푙ocY )u/2'r8{ΦJ}֠p=ݧgSzX2XtwMSѯ?Β,Ga(WhW+ꟓc?30_n>Ă_)kE@6HR"2oJ>o9dΎTGTLPAM(P˴j +^YTb%N|VT8X%.O3ㆦ^U]dN:n%'wSJ(*p ~TXDo:K Oѕ3zG%NY9T=eEKŽA|4_u+>8Mb1.EWh)Eq e/ͧyl,\Sys-UѮ{Y~+.ez K/EץzπOb:l'ˆ]y,eP/P4j5-s]37@iοB "K)+O-U^JqCBo% v+obv)bޫXEG6b[)StJiz+> /~/[(Jh!XFLoe*ʠqaUKQC筇z=*7 #6O[k>۵* E^߽w P塆VF(C=8o2W9TG _tբǃPC:jfۥEV@_ٻ]g^#}37ڱFzZuK?UZk?SzÿPCM[9*VBGKtbq*bVtTIy EC]I)^xs6J*s+-[)vws!ڠjVyUP5WyB5({Bec@d|(ꗢ6Z@yVE*zTPjJDzU(+7ՠqSh? 3Ce?E_~>CCa>{=U^e6&XU^ EǨPVkRVPh。+Ḃ~ (٫:oBx C ݩVC^У*bUԐ+ Vwt,]PC݊nfg,cԡVtzoXٸQXDl,jԭ+=-9FVy*n5h=b_s l@;etĊ!zg,y*S|NiḙfyWfٶf~JXVޕ//-R>XA9%T*ѮP͆9&TWy<* UT݊!VuZ*{+X;t~yv2(:*H:Gox+5F(k> ECIzyeZ'Kysmj[o(>nR(CE?#Tپ:buԐFܪa"Uv+*KG,5XcWܝKwe{+:V1U|^Z*5ߕVQ6@Vt*:UַR(KޛVbEjEj*b mEnS#t=@x]z5ʭ:G)n]oEw.TPK+=WGy((뮷=jXg6l#l 4k(T:WȆ]PcǢ+{|ape.Tzi5**Ō,UW(;e)w ~ ePav(+%5,ZejVy5?%tB 5bi|,_kTbWO-TiXvBs܊:/:j嫔շlxN[xP!G_{:zxPCzt*U-yU T}P9LU˅6AB!6nPU.U.E yJ:U=CqJ]Q]zf0xtG\w,UJX7C-_e;VV[ J3tg6Bl9tiPk؎l3+jX|VPEסPCTEqʡC١Vt̩bHz]HWx;v_"ұ]j6K!Vۊ~P>d܊;[Io%ElEEzͭ9Q KoEgDV|MEo>^k5d#7e[љG!~\*Cuk(Ԑ~c)*Qh2cePU.VbVFmZVh&P;t* 5C3*MCE)vXxKbV 6+kj 5v^3uwm*!VC%veUZXAmnE7͇w֭yNwP9 e5hWي9@ ^JUXt%5]B=*wX+Y ʠh#T6֑S7a_|o;ʎş)GV-ePXѮSu_|l&CVt'*[ F!C!`#,PX]EUJX:_ (*1}.zҊV1VY(' ;O:݈WyP姜>S[||Jz¹l*bUu+b>zW٦zʶbX:{/Y.AUՙVu6Ty PU.V,VJeRK \fIJwq$) W6*j_?PȜ_|G|[Qĭ[VdPְzhWkX] Tͪ?%nEVZV_J󰭍Kѝ,g.%6Ce劓BcmKTIJr-~+:ۤAyV~+:+e@wM; ]Jv,Hk*gGtǢĭ[(e*q;g*Uώ8U߱[*q++jd՟rk@ͬZ%JYMVZJR|*j<QzVPUUoEw5PUVtϾkP]iӭNƻҦS{[* ]ݧ~6c Sڭ lVjVV$ *!zאZl&PUD( ޮPS܃?%nkqy6VUv+KDrmRTm^FVy+B%bwq wl_ĉS^ҾJ9-9e,UX8FSžJ݉|*)~#VmlգG*Ω'3'iQ hWEwkmQ2X$bն4_?t*q)zYC!4V7(*[ Jz2b7j VԐ(VX|ʸ/~ D jd[jnzUˡjVj6;WjJq zZ>b, 㿲տʬ{yfݪQvU˪?%nESQC)OWP]!Gjӑ >+WĒ읢y":U.~b-ڭJ*"SUX]TَeT6k_) ղRPU*t<4wBѻoE^E|VPP~sR6ZesR65̪UjdkRJKKBF:nTv+PVG7 TғN_/o_ :ZV\!BIVz{YnJ/jg8v-C~ZC5!} -1 "j+f9H[Iv)+!?;B^9C |]nEp(bտR _]J *Jʵ}Ҭr@hw({W*?B{G,W*=BEbr[ 5ޕlOKQk+R\يQޕnEOPцXA٥4Ncyd]hߊ݈JEVt@RmEDWo)U*[(*a[Xr~)z P4ΎoX][suDjO}c+sE !bʳd묗犸U* ESUv+ U@b9j8*>7&jH.EfQʻ'zrs7Aދ}wz* y;څ7> 3'ڵBn5i?VtK;p}RV]^NJ+5L+v +KUd^IldAhWVtJ'xՂέÊu+z/UO~+~U U⫝̸Y:8zSOѵz͡[PSVP!ECͭC,NU%nU"Eסmסd+EP{T1lAk8較5bVKs`dT(rkV('&54}>J Uj(m+>|RCzbҙynEw=XUvwB~(ˍ~37U_M˭NVJۥ2maR{mEW*z܊4PX2oE,WYe d÷;%MbwQ!VJ<歔ޕխJv+նOe[ҭC)Nȼ5!}PJr5e+ͼ@ՠA >(fʰ}CeUnC>s^4V5⿲zaݪ1ǭ:mg^B a[wPcUTjAɃ(}P eYs72l,ѡC,Jz>t biy[fH^,91rZ )y5άr9|轳 AZezB3BլZC_\jn5y 5l,3ӼZe# TqceܘJ_eA?(C5A!u(D^oPXFU({^YwPPA!<( TP퇭oEz 1:b n׿[( йxb-(M]Xep$$KtM{Uv+{XOo|+{pyԐ^jW02Ou Esx߫vIۊM=lE (^1(G,DfjjL:<Ī[;Ԑ TɊhFf=G5g?ԭ :!}&:B,iV^ߪ(:/b|!JW7޳S5܊*6ovFP]w{ByjWSFW= p`|ѷhpBvAIPD{@ckW:Q:2O57Jz&qhgoIlURtJj>t7%%q& e[sV[%9D6>tletSҕN+PS=נOjR+̏5y}PXD8E,{P+jҽ"֩訄R+xzk͠YvY_F[*\YnwZeoМj)yPEF|e Cm?UЮȼRePr*kުVuPc:֥8uPnVnE^>Y4$bɣѷul? \~+ qz%jtmVT)j΢My\%ˡ|H(jnE;U^?jP Bu(~v%PG<PM=J+bO]VPh=^r(5ﵝd{@ z}zko%V܊>QXS_&!}gDJ莍CX}4yk5 5/3m}6y[G,|Ϝ)Be(2+SDJFQOFV[~X@=py#TC,~dg69U{1k]WCɻ_RmjަWoUL >OPFcBنDiZ Jv*ݱVĢz@(Ю[GlAO+WP!8 b JxYEStU"ŏWKN(|Pݳuv2(PE7U}CVKW:7Ě[ѕNT>֐[9Ji-TW \ÁYBIVZ>"HPo*\WotU*FoP8=}6j>Xt/URtWY^f6ڼ;mފ߁/ڑCz]C. o6RUǚ%rEIv-U"ʆXV%t+WVסVˇji3=VĪXD(C(*ّ +PxNw "=j *klv ?^CHYB=ĺPm:)O*U%lB,>F*#tKM;ʦ?dKh6B6oC (:*[j̫ ʰjE1&gzHo:kȟ ҬR풿Rq6GyZ%nEWPh(5B>+Pt*Q"JcJ hu@_łwV٭o /4Tu)έid?+rHGV+zcbpimlU)ޮ|KgV+޽}QP ɾ.}P#:Ug^cTUPA5(}P%YB=wPVnҙVxX3ѡCC;sJY.)X.Kcv*y!M"QÛw5rH P5C5l6Dt"/>}W Q;_ݶϤ|R|[ [\P>Vѡ,Jw\e$VK< p(}z85X|]a[)EC7J/ZerhPEVdòJġf6d%Vߊ;b_ه[;^v%Hv(y*P}fjGx_usU(G,olQhyǢߎp+Ir+54Xc6i?%T6;f=n|B6xUPE*q)PvVR|R7q)gS|C۵*StPu﨡U6BcW{DP+j]b_Ze_fpWٜ_N9T+agG6* Jv?;Ǖ{ZVd>|x (宲8YBմ築vJU*{"l*ŪejT%FUǫB AVNWGyװTR|kvX_rUVtv^?lU:g!rvY|{ Wٟ6QÒU2jyU&!:bIjlEJls(ۊ΢8_C=R(ݱ7F vCPV*Q<#T6:G1r%~*/LU/jUbG߱N%[wFN޹P8=D#i5vљm[5KgޫQ2W)C JaZɐP#tjCVt U2=jE Vf^5CBFB+gfJU!*1۴P%C:T:2\9ۅJJƠ58^Vy^ÆXYv'ON*5Ԁ4\}y>*ö],t]Jp~Tn%>j}!k<(t%*Q2ڀjQgG:gYC P5yȡD jzv[U3ߐ75U%]=TJ']q*Cͭ& &wD "thG,aJ d~;{lhשK3R"T.9~)+l-**J5!]2wZöԟ:bљmT4Z w eW焊̧c-h6ZX "JU˭^G6J쯧1R<~>jA *],:Ժc՗ ҷ$NWWpTJEg:B]#jkC=/ÊXJKi,ZEg:6:RZ KoxGjXY֠:QǪ~FAU(z6oA4C,U3@j0X~PXܱMn:f Ea5<#U.j(QC(~BjH{ot|u XbvUC#䫬g[7%%ۮSte8rF(^}RĢwu1_lmWUv+dF6Y[cUM2k2fie];wB,:oH*CVp͐ l'Y桲5Ն Y(Q?EY=CXlfcAOoqvQ.[/toYJTDAYG0zZYz+cUJ 6?fՊΟQì`TPta( }/`ճj}#CgUJ܊٠jV)q+JJ+kj)*2|g#c,lE!.UVkZZ%.EWmPu+[*ڡVt**PJhCekh(يX%5ܱD 5b(kVZVbPUV}C͊Bͬʭ Ej%b}~χgV;FߠĢ]:bwBk&ߕXԐS@,yWbQC.LmX#ĎjVYmv6h,Vt5;j8j/jt>u^* EZ]E:7zcJcjߪkCwJFPiPUVU3FVYzNgCiVYv+.vwB<ߕXԐ+)t,JUbBEUwjjE7} ճʪȭ*V;*:oJʪح^9ʲʪڞ*ʳJ5(oXpV(QI߅QJ,jXb5[7hltjJlVt Aƀ%JCx TԐ>B,: Ҭ1A9*X}&7~QJqa*1T7x MB!$jJ5ڡ"=êm+9lHVENt8څy#ѮUbt)f'4ʶ+j][\w*7v}j}EDC=Ċ> PUJ܊(<ߕE͠ALd].sL=b-Si*=[u:XkE:T*1PAukbސCĢ+ W l,&hW:.a#pehW(CȆ>X/J ν%j]84Yk;bl̆U=U@ʁLJVPBMĢQʳJ k,5􂳃t,/zQX}+:5\A7Tu(PK q³PCG 5PEDzGY%^+nUi%Cv+ky(zEJh,XC9Z*;sE9S#YZYe5f=EYߪ?#V*ޠA T{P e[]!PU}@2jB·S<ĥn%y{ UT(l|_eBek(ϗ=B/5XICw|K\^}cg. 5w,P#b<)xF ?F%PSr/V0R} fUZ~+݇D.G'>Fl,k[O JوX?(C6QXWѮXG?(B6PۮCv6[ѻeY%nu+ktf3sjl,kŠ4jȳCe%n=b b%{XzcZ>l~c;[Uw쎒,Da(eV$!MeqcTDByBzM}8zC gUTcgܨ//P(oPW]™t)rxH[zr/T{şUGZ j>/Pm刀ҵ\j.]{Bw.]w嶯⿗ҵSYU3څR䒲ڭA[B">"t7{j ##MΧDT5WD@j"j\ PGuI\]S#)h -E*F{OS1(YYU1pVq#s t^oի*2@ kC{g ȵ.BeV\%R3ŠfU .T pkǘYΈ=Qҫ"׾PB)Ew0@k>O׀^NUͥ[ ׾WeWKP(7ծ3؍-!sK] t먖0b(w"T?1Qªҭ j].Ԃ P6Jvq#Gѣٶ%(8'F=S 5 5*2@R(9J\6VUdj@.+C[P Ws=r+l%=>3tᏢ{;RUsЉ6olYU zљǽ2׬WzUUD \. \YfkN\g %UȅQ u~I*k-UWZ;FWP56?5~YU\Ώ ^BIUP+bvUED*!ϕ(|UErͣ\)h?T\qTjT(!?&7dş-ρ\i\W/z]G *e=J5xUD # #TP*"70}+5jUEr)1ݓRYsVUԠʹ/ExN(tPtՕԏӡN`#"U55G8ߥL(o[jJثP SYNkl Sk7(+U5WЪG9bBJGlȵ*Z%ggZU_ժ*"(~87^E{ů_5|Tyܐ rzG=U5WZ΀󵁮%YyzTx(Gjlhͪ PEG6;Qka<e > %{PGjG9rY*bhjAѻP]U;UU {\UemYU'|—g2|s<|U!WĖ cAa֌yzأ<ω\|hlyѠ8/󆯪(>'ZUeU\:=SܑnG嵒ߥljG{.rWmz*zG}uq(:bAM(:nHTP_ͥC (G_eiTW5j~U3H*L-ahuPvP {^/ZcBYmN8rGW_5rD@Iu^Q eUPb(Ҡz(<ʳz--7v=w2f{*E.z~ٞʐދx+_m(O\W)o|"TR\{Aͪr j^x^jV[úѡvYվj>=jJVFSl\QT֠䭌~*ʖ痭2MdPBGo"Kv}D?EC{չ8JGuq0Ni} @.(iPtĞ*EϔTy%\Vƿ*2І\L9 N֋ҧAiUWѯ[.*t᮪8V#Qގo-vǚv1o~BYEJ.r.rP>J[Y`v)|Uh*Nw*e?AGv-SBTz/M뭌~l9QB:l}"C)mQEGl~k@I5WĢ^+KPtV\j}}/{+|~9E|+_B࿉J\ k]>j j@ѫUUw*9߫=j5*j\EңUTrKQB沧ZPtVFTu|+55h^=IGE{: _WC>2ڰ+(M6hSD.S>~i(0|Uh52d\A齊؟߅6rYUQ /.ӡ潊؟_]q ^E, ^VF&OuK(VFNO5{*)%?EaFFrU|jܫ)e W!WGV J$\|Bٽ؟wply"yrA|o<vȧߡ2*t͈VFT5_pgݫ)a_UGѯ jT˒%U6ƂҪrYQtz5^EO=]VWStOxm*bq.2OSaUܰwr^ܲTWStl2k\(*:PxRAlY! JeG=mȆr6AͪrQti^EO]]vW{}=?iCðy_4؟; \^EO= #Į-CM%JУEX5ꭡήOk6AمEw[^)Ag+3^B6LRԋ>ҶR!?+SA ˾O ;?^\( G9Essu<*b6oy˽I59V6Ø JʵWVU{}L!+-ObiuZ§Qy"ԋ>Ҿ66QBؐly_ٗQsAt_l(Ց*oІ\^G.J׷2KXGѷt W_ʆ5S,Vwz*W+Z>?1O.^E,Q-Wf ]CM(zբQ6VC7@K(PB:砲~6B %GO.mP\}ߧ[*WEWX*bO*oe|SaOUq*[_}TQtG.rGT'ݵä)ԼPe쓋FP"&mB2(CtNr=LTQxa"m!׾PֿsQUݍƽɭ[Cz^((ߧBBمUmyn\tw WPSt j^({roKo.)IO.CBK8';Bg?j{?9߫)zrQ|JUEPSBwX*vuW2 jV?EF+E"Ï2+}j,g*\F]UUJ(Uoet?8U%Ue|eSşϻ|Q(*=wPDR@&r2TNՂ:/"gl>J[UE[]OՑ6^T8mVEPRUVFWS)rXsP/hN(:nD?(u(:n#.(:UoetS  ]뭌¸g+MRC2ޟJoet?F>DZGeD y[]GOql}+t(|c[jkLG9(:>j/h{+١o"<aL{z[sS""UGEmІ5 &5'rɽ2~\zLC{Ro8=^v)Jr˹F(UsE5F #"rіT٣x{*2 =DԟJhGѹx)+Mg Xo<Δs2ῗFCjG(>wT"աFUEW5*z%Zd^|fek3\j7(?jMچy6⭁\zSK8Zr SEl\7z^&;{J:O$CPRU|NjG֋dm2AɞPxM(Py6{نt'lCm( "^̧G{l _UncB]QXT2-e%tk]7PvP{bDWuz'W_5h.ZUoe*.]WQ꽮zjG^A*(U_eTm(^~FP jS,a\(:_P6Ԣʑk^uriTMZU ӾzU!Wx΍2}T*½(5շ2ԟj ꩽ{*$Qn:ѣ(~<*b菱:Ըȅ&V4ϯyQ\S|՘Fu" :/e|eSy؈x)k͞ʏRz㫔ޥCR8bTK5L*$)f$2@6k"-&M&[]O5^m5#OG־޻蝃advң&rm6p+ُ{E,B 䒣&Pv]%"Gѕ& .Az`syη2"Q|z-(K6_G.rLgr(k}Ԥ#rAys\Iv71<ըlTntETL ށ+rEWd>J7O5*">4qTRUftjx⼄VWdU\䧚\ \zL>^v]![};o,Q^ ãLGsҋ\+bQ:(}o9Jep~e\ޙˡSǵE.\zPf -KXeZ:rٟԄ2[}c<=Ǧo[?T[ʬe/7T oqO3bBz)ddGEDj_#=zP\-UXK꿈#@Y9Ds0O~ U_Wj_ b梣j xqTz5NѨjo5l`BIUED*K By(U(T*:T":|p~̤G6i5W:Ih&n@.(a*9;g"(Bѫ(UUDf^VfɄT %/YP"⭬})"^A2>3B;EEx*C~Uᴪ<{:3PJ6SS!׍R(:цd=녖w)5xц>E7jA;PGzUF*rQ P(Sem(6tن޴AޛjEW-(^>Z#OS-\6GoWF*J{Cu({*{/<8AQ+ePH^􍻩"| Jo=MejAa}Mře{@蛄Sw\#ElPPr J.rM(-sͣ{zz͋\-U5|(5{K7T抈T\>g(6RTsEDj.Ӿ6'z/IԄwZ\^ԾP=|(N_-WvxOe)NWk!$UPHU͕\齬7N(M廂7fC(N|DmK\K<~QPR:@TQiWa+ EwepD5AϯʈJUDŷ䢕Ut@򈯢D7f*E.Wl eUU3/QWL+2:ĈrGb-;?yߍV^tgڻ_'=i|pmv'PXPm /Ԇ{E2=r9۸P(c!s*٫BcfUK/k֕PTjxV]CE.HUϵW  ՐWyRUkVW[/f\9ʋ_;%U zTQtGZ ՠoQy 55ZzeJ6=U`KG]:G&}~gQ#|̢:=j^eC Z1RUs_ l3zUyla])9*6JUzSI(c6^( ?;y|jaDoae*Ucccn%Pq Pv j]WyUزՁjTg/U%WeC;r=KP_K/PBjQ\N5*3M*oD~?ʡ<6{PNIաاa;V |*5z.[j Sy,ZCBa~JþB2W~5'Pj;N-=#~]|WE+j}Aylulͅ\z[85N*ME.╟J|UD6J(5XXCtzoB50:-ZPy豨|Uyl#U -aMDW^/'Ut5cCYU3g{PQy;#~RV| SGѝZ 5m2ݿP ZTTP:EwxįRժP%{{* ̜J~=L9\{.#B ŕM8PmYU-DVWt/ٙ cT\t9eDPs/?Pj>8/)J_y^Yj<.#<#~Iv(R W#vIO\'rYt_Byl(zǖ>=8+[أt ܇r.MU^*~?} %WJO_C w%_}Pt#.r_%wP"]_>-]zPx5:BƆ1SUssUk(#j_t6׆.JAD|D䚡&ȵ7&f9/:єT\C?$UBO137F_7*zt&3 ꄢo[(S<KBC-^T 5-U=W;P :͵]7c屏'Y\{uQ E_ #+-G@[R- 屏wj(\epd@I(PWu#冻RRw䚡T\~R]Я޶w%?7#jw(.:Ṫ[ҳSP5B5zQB@ֳ*wg@'>.rҭQ_%Tm=\ѫtՠ,3U5뫶PeJ ztAt}yZeTYj.=QN(-*kHOwO屏g뱎bzS]p_Qo.豅ʣ^GHUլ0>=4](ߕ \BܦXEחQCP {zzޙU> j@1$U5wjdہū?mfRk\ sѿS/~j T̢7Yuk}rѿe?r '[cPTW~wU8#HNj.ݡV5W=A*z_\lᄢOh!?#t蚔m Rm{NBz*N^xWy~9cM#*?0z*#uB4-t[語B'՘ pW}jC }TlAE5)+BP|WT\^TB O(zPYC@j ="U=Bm 2}:j7c#r*ϐ -l;<s8zUyo.i=sUru&rݨU[b㾪Qm!E_5ha_%r^4Ug (z8=Tg-=E.Mk2֗i /U%KB:OE.C|'Q9yjG^/WiCO#9cwET\ִ=qBʯG31ygO y)g'=B쏢w%q'A_W"Bs/VTt(/EGB׬9PQ헜qjҧ')PQHUϵG]|բ。wV36Ij.kUok»RݲGR;SЅTwϜj.9:(}kfPQK~5rtBze8q#BvqT\yCe áY龪~lCϷc5EOtT\D|*ktMUy+_вPx񧞽WUY;1jUUrE3WUY;Q9AIUE.xW,sfPQy@-(h⫝̸'lzg:rڣ :%U[Z5/ Optrj.HUeGEq{_vW_{[Gu:z=Gmzn}d *roXo=s+}=Wz~jPR<[7kTUrƆ\cEzz kL)5.TjU3@a>+UP'ZH06nrTsyBP\BURtΖ-W%-oIPZU={\UeG_6ʪ*r@6O*/w[ TUreLWmMW诹=ZYCAU\U:PSUse =+F*{>URQU(ݖ@ͺQWs_WҠt.Ԁ7E:zT5n2^Ù.t׮v 'ZHbPv~*π\VmPv|i *;U5_TQSRUrƾiAݴA٣YHuR_?^yŷ(h]]>G,o]ir_UG*k4W^U Ue} 屏{v5 ܇+}L屏7Ryl(B 'SLSrIu=;/;P7Zzl+.Ԃ»  ur_Tr 5~smR_) 6hW{QCC.-&%PJUS<"W>S\C|B\ȕ?T-]Gv\R(*3+BPꍪ?e>zUe.PUU;ߖ͜~&˜<57+rj'ïKx#="E.x#9<+S#ǡDA[8f\E5:T_tV̝#c0+}:LMUfX䲪_+O8Ԫ 54skG樕OEryDj# s{ jU J.@ Va*닾9WA RzvrPtOE[(TU4j]TբO\ŊjET0%s1,E!JB ^2SU[h>"S#>VCjh!}ժzE=(ȅy+tq( Q"A-~}.u/Kdܕ3@PmW34T{ Wפ#<"U5_Btݷ]C:s+ȕ53jBP| Qj8'E없+t2*WG W\/\\v竷ƪ*{=S+Kh MR]ZhEOf@_\P|M6vRUs_2PW9E ~i(P\u<.TVj Z{ gAW~]ԬݲU ۽=Wow3@l3C{K:< ĺmN&D{E<ŮƏ\2@ 5Ye_%~X}6JlPbv[gej@u5P> ePePs՛F.z eXU1PdE 6e>,Ty.RClW+[w [T^_-VU~*;UZecmQJ1BtJVE.P#W^PB- YN2 au:rae %71S>5n`WտJ}"\?wG_E/cFrEw͚U9|P\cb7jU1\+eҿ@ͬzX!;_*"\MXUӾu)*@._7đ|VY׆YeP__4j*(ɄȵFX]g FU"kkf&A+wvߵYT6Uz6eQC@jX]-8 kvEy( cK56V8Uuk"2ǕUv4p P)*jg4W:zuWt"BesIf)޹;>4F4–Qg3iC-(Z]Besk[^ 5}?|VE .P%QCIVE.P]F5ڏ*B.:{/PZkB5qTP 5QC,ղ" %Ye+ 5J.BE/T-**_NEB|x*|*f*\ 2@_#̪~X,tOggyZn2EkXwlQ,?%D.Zú~(ȥ~ێ\7bO+\PX77NU<ԠFɵ?_hT"B]Z1By:{6bwXeBŌZ`/Tyճ2|tCgjg :_ Ծ\="\\GH,*"V6BͬNnEe>,|P#]/@2},|VY~"W╟+,TPJtufu5 *] 鳜 ŌfO)ڑdK[Zg*oܭes՘|FM#5*r5J[]ȵ\}VCt.uC  f FUa;;BmoڡE~ R(>jXT6Ŋ+V##+j"W;*"vG(`k@!7qY 5YejJ0Ji[glVE@esqA'54UJ}\޿eUk|Y,TP s~@FVIP>7QyYe慚R~k\Ye݁2 fUX(jx* P+|F}RBͬe>Ϸ\P Ego/ȵtFsZEgTog,ϫ!_IXWɠ_F)EgTk\^u*źY>"5ќ#{jdj⿴; ^\ sUlJ],s_z."3jU E_C5Em^Y,c WW/՘E@yg/T9O!P1{3X<o|o,"k-UPTtb] Y+ɪDߡt0; c^Y3B E\i*r{P?-O+́\^YW \rpJ(# 5soWPJ\?]7ZYm3ی\=}YD|. /rUWRJRP5y(|8 r{e7yQOԐҠzV#PrrͽZgBl ez E[*ʿm2C!RfYMsCIViC9?*m?JźUk+ʉʯWRNE{qR\uΗV\ճJ?CҶE/YP3-<@ kXWW(PIo-EE7J&}X JJFld!c,/z}ƵL%rWYME5jViv*gi ղJމt@{eg9k+s~)rͼv*୰H@ P8.^[-5P:t@iVi}*cYmS%*/v*mW~7z,vGv,`@~,Dq,}g~/26[C!+"W%jy(F*k*&],PtG8Yz,[vT**6E;iX,\5"BḔRWm4BYhP=.~sX*ՠ ,sw,uꙋ~5fPjUZBQnj#l,W=Usl^_UJyo(jtFPγ5qkPtnXġUjPBy.vl$u* jAѵP\ڋe(^"P3-cPBYA1<eFEߜy+K pEgٟ\#f6E5F}B \\aQSMz(#Ȯů)T9BhX.rq_=_aE"FP+,P!&ξE@s UE;wYWɤ;S+y5Wiخ,QK[l5ިV"~(^`6pAjFv;wa^ӹDV}ӎdy(Vpu+xo)xSKE@esoE;*%٢J^ȥu^#}̢"3BF(8Q*U5EQE*_Ce@S%V*]BYlBYE T+鳨Pj( ] 8nZowx/8(VCGp\<*BYl|Wߞ5%TI\TP٨j׃|ݴrW6hPk4y5?1l.cXmj"-f+kvv4PBըᅊj<},PW;׼ź_Ai=cBeG(o*#xj#rQ*KEgCQcCNP" 4fT^+E\inT_g/4d7E;&YDl.Tx_,R(:WA.W;E@]yUqC]:WDžUt'=*"WPV5w1z+yGVު=v1jX bnұp-kqZE;&.j)CXW(aWdP5tǣx#q,1BWPG{YߍUS#\XWw:|]t 5EXD\PG=E{3j˩C'A.'eUF.WE@s< =2sEvjP>jy(r\*Kj+c\ JPW_QϒG{7OUʫZ~,PQ(0T(o#ʯfE@ekb# e:],dnz-GBTFD/PؕBYhǤNq;K) #}bF!"vx+YHg+ U?*k Uש-r>AYբsmtq*>r(k5 ko͞\/Q55߰s虋>GYęЕźϱ=,ftN:_B \'PCweaz Eq\Õ٫+jHPөT;Մl/S0Jh5d},oP/iMp\PJ;ՄGѮ8ohP(giJEmdYztwA(KXWA1YE C*k{S6r쥽t,"T>+wU=jP|ek_~{VR+ڙf,躡5FHWR(Ԇa Z\)bR뭰KW(}S1%dN*17~&*R%ֆٛx2'abίzij讦M^ϥ뇢Wڇ<},RW)ƣ_r<*Ky 鯎)uEG6$"jͬCm,⫄5~Œ/rHG8bZVYġ/UBT>{鞔Eay1˜QyC;f5;].-ǥy:t.*i%sڣ="-ސ\ 0dM|^8_Q]Zn`73BydGh>T'y>z?զFP*;B26zj E;ɿoZBaiPyE@y.eEmqѳ\\ \ؓZW/V_%;lSLTC:IUrE_ϗJ*U(~-o(u(a2sĚ!xgi쮙J/Jʲ&dU/#lYe %\U+]_7$T6ΎoXGjtiڟrBup(uxjyghWVg>(~Ty~j:R =_*E|TRT|C56ԀPy*>{P jsq*u9_mb5Ʃ=/հk3m+jEB.z{ E̡]b6pwHP!3*<[Y~媞۳fq jsEߪZs~ksvl._M7"ePz]P gvX:NE߁YJyᆬTܿfP yER4źjٖvX@u(zדbt}۳DO%|n`YlP ^ဢw9C4oUաf6ʔ΍~(.(z}*?B]TCw{½RE \(~_/z(ޛei/TeP.U*y;,·TJ}(TEւ\R<}">JVWү?${o:YġNka6WPkiPtFExsvzǥ-gύjl.wQy8s͡,s'"-ZVYD( R*@ͼz*k&Pt">J>UAEx5TTQվJiD.Z 8TJ+b=W5.Tgůʅ\r[*u1oU]_Wg"N8A [m{Y tR5IU(|kʶkPc+FTf7H(쨙د @?/Z AdiӗJ/ {jLrf+}?{IC.˶GRȡ4 %Yo5juҷZ:yBͱ^PȕPq*Y5$j m{lS=W9wzTC-i4Ph >n?IjK[EO˅حi{Vl~h ~BYPAyˡqP %Y\tTBkw.a* \u=R6 \|5=QO :U wQצPBWѝ_ ;Pȵ.Ԃ e[5~ J󪕯BUO UP6PBzZ*PO*rNvXCУCatzZ(݊Sy'f^z!}+P }㢄V~*?RZFg;5hPdsyD|QjVyK_BwcTfsyM5ڊj\䊹W(݊By.(w&Аz+oؐfȥP{7By^V} lʷyπ֘*^teG|T:N(!W}#jfPxw2m*[e+Jس#B^t|#[}#5Q‘-JUnZRGmL Z3E k^yP<~{G|}CЫ/ܠjVT%U>奁\l O)"=T6#}o_BՋ&<=J.ru(JӴlWҕP-kY<ZQG 5#j]{݃#j}[)} JhJtk,NtW7j[*mu-G|b%\[wuQ5#>fCVl =e %,YȥYwu3pP\RJB?ݴ#ԠFʖP(?JFRiYZ~˲cQB%okB h +J\^Q쭴w:*kCvӝ<*ڐމ6 zifVy[I<v&{J\ AU{-G}֠a E \^VJ鎚<6_֐_Pz\c/J(5/r-z\^\٦R_GCP+A޶=;GyD*'(yGB.,*();Jso6G{0򣢄tf;T@2fD.EF ^B5 `>m oo({ J3>6B_(e%lPRVBR˓p\pNE*k56Pդcy(*ϰ*Pt|-ZY4#EVE{j[ 8#BesWC.:J8QB:*ׂP ΢2Bes)vfՎutl\t8J} Q#ʲGl7<fg6jh亙{;T彽?mHk ճTϣ=ʙCV|Nh "((62*Tj@GѽӥE3Zx;]jPQtt@ J1(}\)=J }JjǺR z ݊8T{TQt?j@gCG]ww7J%ӣl)Q:GlE '5H"ա5Tsԯ֠O_*+|P%F壔Ew屏QQt7?AUCGѝVK5U jAѾQ'< !(}!_jP]9Sk tNRkPtA|j}+Tj^ .zGݣ cfFo7<6{\G)[]Ub,+*1 j@i }fۊv\*U|(U:f6*1c(JzQ[;QZzA.W EKbW Egސ+݊Ͻ#WW@~\#6ɵ~(:G5ZYdjׯ+k/PUݾӻވ\veE9B!BaE+=C꜡^բB.:ղJuSzVUP#TD2Uk}Q@{%u)z^ڹPAOBP;}ˠ}%t斮SPEvkϫK(c9zo+1mnUZG5.FJ {=3cWRPyM=F4W/?RU?jyZjTa(z.௢+LzYED1o臝P\l5j6W_j(Q‘W]J^ /TljGȫ1QBk=b+< :cIgYBsC5WM:L9mXjyqkk+#< ʲs(皶ժyTP]c9Hɫ5P02=E#>heEPtQLIo݆m(7ƅj/TWSbTfb(ឱًVdwEO6P艍V>hEGѓ h(zFmE(Q1cY5(RB'CM(YP J.@R(Phyws(+P-ou+;SGh%1ґbBzVFOICZgJ :>G٣AP(~>ѩУ>߳Ґ *QV :x?3TQSGsN%qJ\8=c8UQG=cڐQFϒƣ!V낒\#E. PvlVEjyuPQ̅?J.r >GE.۪E։.BiVYjgxxT>/rG(@ݴ!T[˪*=v+*;{Tԋ^Q]ZG\jJ.r-twwWcB-(WEp(eMVW{q#ƣ䮾%o+ȵ-U亨 G+AP*^ z-*PBUvTPjC5/rM}BIz- u %݁ZouGIy}ڪ4{D(ԋ轖WGF^ɀYPG(_/P+[hyOȵt_bZCsi#B][W=u=C\ jlt[?{"E;*0#wt>,ZB=[/6ޭat_bπo滄F%[l W9=T{;J:'PQ|^G(j cm3r̡k {B\tw^Uk?b]%;zVUܪE+UjD P껄ZP^i0Co%[jj|S7[( R(W<#B\;s^yygϭvyϭ\xVz/ >חo9Gh/TGz1z߉w+k+/ZEJ>W_ȥP||)r2(=  r>?f(⪠ տdGjBah\ (P6[;ZPd,{i"B {6Pt\܊܇tT^}PEVfg})٠E6TW(ð!U^G]&P"^/!\TaO}+ԩrycZ(} mVAyTJb;3,Sma?۸W㮯XYeEs %c<riVYU)m(W E?W(c+/{{ PhyS@WN$Fa(^AB/֭mg^ H ΈIW})C}2EK5Q E^Ҫ!SUU1~(ڗš^eVt=vNN2em*cwOodC٤뤾#=zu~(ڗX(z^Sq2/o}3(g/yt8 |AGѹvcgS ҝ> k 7&? )/ur Q5ʄJC}d8ZުGQˈJ2 *jwko#@̧2s25*F[YNJ*FEϕ^e,=[n4#aZoE{ Us+ΒHV%USɕ^eVtel2v+nOFռPފ͵5PB~%UnmBV%5JK+PZUTA$ֻ^t&k6Z*c3Y9rٽX(z̫"_(舭[f[m ꭪2bg)w(<}HVuEWfV2⩂7JUnEt*cǚȵ*fJoPVU&3,=k2{VUF};cZU/WreGE-^AG[tx2UUF< }g[O.,#^[UOeBtV{2躶ʈ+2J*#ފ?s0l# f+/1fW&fTI٠b+җ¼]k?mUOeBYV賔x+:5*#ފ? %U?m\S^nş"+_Љ/(ٜ;PQ{ܠ+2:qhUOetR(G!2%ղI(D.:|*ҷB_ϣB>J[㴡VDߊ?eUoş΅AyUeKՋ*c^V|D\iۊ^؝+6!Pzf+rMAՄ?)I5U7knEtʈK'TUFnCrz)t__9_/Eӓf{P/L/cQ [}[=Ӥ7YJء;rɽ }cBMhC\ I6#ʔ;OYB.\\~ڀBSE.A^FSlBمj\ytʈϣ2Fq.T2(z=o %elBR)Vn5*#ފ>XFUrͶO̾vf+v3luwn/ooetҋ\j]CѾbsl|g[\|>OO{egS^Cr\lRZiSpl_PtQ*z=Wtk|]+ Gu2Լ%R- Irp(1plE %Wkr{e(!}ZC|+fz*Sv t~~jB(fa3+pUe~+^:J(5SU cS٢!Wf("UKG)Qxw*OeS꼧@a5c!#^[ ql _TG4:ҭ ȹ7G}bS!#ݑ[VF(ºQCF@#ᨌ03\UseS٢3bpVs'|q*c/J8U\ Ԭ*[+NP\WQRUsѻ5p6E읋esz }sѻьx+S悚[;(BCF󖏷_RNjMPVN/9cڊIeKѧsP%DK; y+~"5 oT\jY j](ׇboů{tߞB.~=t+~-*fV:JԬ>KɈʿ<TS.uo@s8 W +#B.GV/e[YoǍնZOO򋞿քS8 x(S.A.z6_qTf-x*[K8OqXX8W@WpFuq绶Z}쭂#^:̠ƅh %U?@iUeS߭Nz!]A#ˠֽح 3'WY#WlW_|]_zeد2}UrA.ލfQ~THFU}ÖWs+TlE,Aѫʭ+=8u(J>eńs:bjVUFP`J*#B_9݆t|łҭ蚑s }Bh+ )Έ Jk ʑVtECEUeSe iVސ?Gaɕ-DվZ6̛}30K3kU?m8(܊C\! 5A.A.SKP7mx@hȈY?G+P\ߋ \Ѫ%V[kG *^oEwX䪪oy^ }E2>W|zE{J̗;e,\rr5GUse{A-(: !v;jf)ޏp y*3T$j@2J,tpGUKh6Ȧ%\Pk+:k7 -lB+ӞR\!ah 먌(Ue61F7uM7#u)8Oz輹 lvr+}^qE}Diyvˈ.rg 輹M(^VJα1꿗cW\sڎ%TQ\G] 07w%5Q?K깴(J߂3m?oZ%lWԕ8rG=ZQʞߊaPK mW:(ZB]GUs6vي^U^oqUU!ԢkХO r:ң5\j[`vr (:,=W^RUf6 ע,E{ZP\P% lTɕ6NoE=0h6j@ uCPWQ["PrY/3fl+wm]c##2&Ϫ P}+>%#ʌ?Yڹ_СZ, Jx է/z2]ߊ 8z%Vs=3%U~+@-ІWUB!}\U:EQU'Wzƍ'WUbc/8o(Q~96Z¬9J/T{2O"~(+wk >ȕBZCv b8r>6~ḷʹi{eVoGXTc>v :tSGߊa3"OY/((a PB\ZWߓvzW ՞*Z\'=OUe>ފ~s|S&^B^6, D Lr(֎皸f)ᜨ׸P˼[~@ JHv\za_>\/CzCw *#Іtr5J&Ԁ)SO P}! jT(l`PZUr7 Pz G/Efu˶EwJ_U\먝+}UeJk^WTUF@V\ Ǽ^)((JV|viQ*#PB׀ʚ^ m2܊E2Z؋FߊSYOJ5+#^~|ZC2_^]w\髭GsY 3{m֡_Jh"׀ZjB 1UP&P|d3=dT5}T{enQ(f;0ƿP\>V|BԬ, V땱P2(E㈊ʈgkr*s(GOn/*@ cTKG!W8/kx˛+؝+P{qlM{X]3oQBC.>}ꕾN -0[Pj[^UU\ƠzOmѱw%Ҡ^"ׂ^uԪ%hCzUe10ȿ +*3@y] B\޹w2bawQUY(+cGoޡ5WUfUPC'JEG5߹^uBVtN*Wr (S䝋>u Q(KjS̺}:\iOF@Us.E }+~riUY@ ?E)PZU^YVvUU\{#J.~e;-_ N 1U/o㌢چްCjע^W]/~=u+ g=A EG:% t=g,WUFPJ'~Sv3*YUTYz.k(agPZUToBTʌx)uS,ׅſΟOE+ozE Ru)>#-W7^9B eouT(Sr6=+B.g=gX\GeVQuJh*cÚ?_=v }vlψ^Az ֬JcJ+wn-C a^y[ ^U\Pt<\\چެA-(:urU7P3W}#3^Ns}[~y{e ׄr\L"WGV-(o^IɈFg\E O.݊q)hy2v+wP6JTu+޲*J\RncqTuXyT2v+: +Unt|)Rzl (B|AYUeE{R=1!=zݡt+&3@] V=2Q%\P'X(+ŠE"#؊I-1 (>ԕ6($rh$$cD}.N+,:)4/5c(ІZҪ\]ɂh*r ʩjPB;T-%b.w{yʻ^jpJFjYJUh.9a-*PB@ZklC*)KXAU󹖚PtX'2W3!WW3v)>K<:r{5c*r{5cP^((!}~UA.:Ա['%P* O؇ҕϋV^9 A9JȕWOfY/JsJs[ym|VhoU*P݆qQAƩS|8[->Z)ʳjSu@ٽP\Ԍ]w%]֠R|KڷY5#>퇽 ^yE۰ r{+"+}@U^y(!=PAyV͈C\X sDCAwU)P5fĩxBɅEzOC粴Jg8J+BѷJ/PE ^( 62BnEGpXr+tWٹ+W{UuP/d)Cnաhh 5m8#B.P~Է}=/CPq+KYSyFɪq*>? ZQh3*r:GY5#>m0g+Y2zAz]ԡKYEyh.eY5KK큚K]UVn{ՠw՗_Opxu|^P^aMKq*:^^y(j^y(jY5#>{QW^m+:Z,U1̡R6W#CUFUf=0#_(\wl?JAUץc.xVwlêU3vy/yt. Wf{mXy+*gWAy]QXAe* (LqJWE ޫ+aPU3Cp(@_6YZ+Q{cV;qUP\|ٽ^,jdf]‹\=?c?#etUzN5cVRtKo˭ OJC(v-,A)UʗJ5^إZʐkܫ6kBլtdkeՌP›^AykTq f,.RG^إx\^إ=JKPE7"Qe[!~\*VE%ůr73JJa@'oH*'fKyhߐVz@.:FI+o\DoUۈn\t ղ\}DkH^XVm\o(#C }>[5k 蛞/u+PBzh"c(!mݫT\^إ*SE.W3:K7ŸAw}(C)^T}Ca\a_K1 (_lO5 Ts-5}Vz*z=Tͪ>B](ˣC+=\gUاsC$>J*S{yȪOEGPUa_xP~f,"W+o[ޕ[}DQVB.:cfUEGUaOEO4SUa&?9\(^3(z/BRrMUa6zs(>JHJ/PUa槢$W(Ϫ0EGoPUa^>/%¼UՌ]wh>ݫ=\lSa~>Vي%Yz*zy@iVPt5*T|MT(Ia3rq#TdUXEǍKEPq*giP ejyfn=?T *Q/TG.:wW %Yxk4(PTtS ! :%PvTt(GOVB.ejY>j|TjdUX8Fz/إڅ2JHse_3*kWk75ߕC JHڶ%PU3\V:6\iV~ѧ_?덪rZ*r15n\^fUxSC ʊnE֡Fg;kkF*ѣCPz( /?aCgJP-ax*׫CѿN5cw.zt=EwC\[WKѳfb+nʩ“H.m~QLxm;2>PP-+E{|)Al]Bx:=]J{o2(PУ% URteFKXF[@韢'h«\ TU?rs rѷofyTO3Y3b|})D3i !TV*JPU3v)ze^tO׀r(^BPJAE>6 mHGѩ퇸VW W;wnT kF (zlluQB\ޠL*ћ%kYBB(:zP^/rɩ)r.Tt;DQ(!szR|.㭼(%4k(z*,5c%\hT% ѡfNgġCE OIPt_j.gQ/lfVJ؋y)U 3RqEgf,rWƅEfĩU<Έ P36[NEggġ蜞Ֆsz3*_ªP}):;7#^*NuIg 7T9ѣl):S\P3kZX(:\Q~J (NEgġw4mQU8&PBu(˪uѣA 54f[tULjMSryV͈PBԃYzAȖpf@zKPBK8*IW(ɖeP7ԌkBYVHRJk:q*Z!]Ki]ˆ_4P%f[ ڠcFЕ“(U5#.r (˪V.||V.{GjȪpR}C%,y5vzZoBOeC>JHﯽ xgk3*[B;]I8fK*J+=Q8#sXp cT c|.P-f[GP\*@R4\\ VJ׌x+2"PS.ɶR^1#ȶz/!ޠO%hCS;dK8#ʅkWS.(z V+oh h* 緊PU3\躃@rA}DfՌP!*TP dՌx+=j+?#t=ڟKv([եԳ读2\/["_ kΈS9ʵZ\[ѽʳjF+_۪EwjWqdՌ8ޡvkЖrqU q (2#%zŅjȥK;eF_(_J||CPʡJ>E lq*:#UͪVt\Cr_.Z/m*RvF\áhk*[(S7hy_[~+[w> c%bT߱//@/ѠcaF++p*-BJQFs (ϖpFl\{ b)ơw5=2#.JءZ6WWڇTVjQSU5|.Sѽ"3T|)zF]*<ѣ#Q>Q^Pc)#hFT8+%',!]SSOCehPݹ㼟q(z %o_[!ׅ G.o<ZS[чK߸{*cC ERn\:^G6dՌx+B{v6o僟y(2Z­Om~XоQb+ԋKU~;!wZUߣ\>>ʠh?/wF=ymR|5 GUMk>v=U2䲥>Kw(<|)VhyZ we bĦ6Q[+9TͪNE-aHjy1 ˮ.*K#9oψS7FV\I"p(geWUg.+aJzRrFJUmԾ{ozxy%TT&xȟo僟(C$[,2+ދQhS/ehyMO(ʇ@/(!V.B햧!We׫w,hYT|v(Pr*ca6droUU1,NEo KY\P{Ԍ͏mtwD20RtcՖ1cNv #hȅ-Nşm@EVzRtG4=Up@-U} Ep(枞>Szi suԫ闢ۙU˪(nyJ;^+]JH%f \tW}#2UPtv*ݡ^=BRtwİXK^E;s7rlrA.2mÇ·V>9Zc5߭W(_%~sAw.=rǯNeUxo%oP ^Y"<,%-"WƀY!{T(dU|(NY!Tt6ĠƽPIVoRP­4|5_~Z'OYieȥ%XXo5']CR|Fg.,fl9-?K=V^ '56V"[E?=Ub墿Kl{]or[ gUxS\mZx^Kѹ/}= wUn{|P[HP1 JhPUĠh @YPJKQ⢄Tl݆3R|^Tj^ Bo(Ռ*fkNeCkLy骴5Ҭߕ 5jFZKjhNfP~0nsm k Z*V\j^t\="WG "WG.MWA=e},%q />#mʡ藯V\3/gnmze^"Kyl UfEU\u| M0F }>TG.U^n"Pc)z%,$Cy(7Q(j\RpdsM\EJ1P(+\=2#f"kK4U.TsYP À]t܈U>C+YQB.:P+~>+j@B{+i Brl f,/>r>Pp^zf xݪ.EgeYP0j)7bd#nw2Ҋ3MM7vm9g?#6˦vKpm*}98>l<]|4g-ղMZ\PWUj(f9+UWћ P?, FznIC:cp|&e; swF! v?{O3 vħ]]=ێdᝏo03Op|=nOit|*kpt?ѣf};tj>9#=y:;]nl_}Տ;.7Ϫ[7RFR+tG9 nXC)%V_=ofN7N8hOvnlgݜ;Xf'Z3-.g\;Coܜh__-/v};) fۥٽ:o@KWo Z('ۏ_G)ىX!ӽӥ .LO={<=m*9=8;v3ͷݩU^ysSn{$7`Ogt~\wm_px|AST Ô<\3= wBE0LdpwyNuަ> zEkR>"0[`~ӿor«v.n|8Y0|ooF )O'+w[k-ܛX~>.fq1L}k0kwfӇ`a .s&W7[h‡鋺-Sn5 mۤ+qFqϷCS[l$lHD U~mWP7i/PjooPߜjſY|;\WLwC݀4?'P"qߨ8\?LL&Tpcܠmv '?'pNNuymv u]"yq,pNipNipN6nd׊n3(mv8wkU)B8}Tqtn6;ܤmvEpNN6bWf zˮJҘ'd܂?UpNN8X&Wn3ҲR48KR0*N͓mvA'tNlm8=j:\mp[U* .R4gman't@=t+S?N/7fuݴ58>n6'g⸂]NhW;GO)/^@{Lb $Pw8uۜp턋P/'FUp<;`r&rsr{PM^%W(;{zW(; eZ`[5}cvq_יnqp_MW VP שHn[W;WW3զk^O8\mzۯz};vyZu^n9\q̊}9#6IBppHX{ m^vNM7 뇩#&Bb]:?ly8m&lθ[.g?(~X5bE1>͸%aYgeY7U&,n`dYov'Yɿom6*YgQה_zExqo,d#ˢx9<d3ˢx8}szLeQ_=β(o=G_B\B|A3}}eQ\_[?V,ۋ7ZEqsrqYɿd`#ˢx98̃,0,|پgQ %oarq8aqX2n/g6p2g_LSd N[ȓjd5ˢ_BNֲ,ߜ 5Yϲ(~s>d#ˢa-g{0hKƵљ[_M8}.`c؍( [1V铙冭r0cU1=ͭ!N?ҭ|n]qn gnGٳl rlL?8lǑé<1mbW,3;yfY7'OVE~s.w Yņ} f*삵7&/Nl//|A3 dY'_k6jEq돓l,{2am t#la']:33_t3̼e&¦[7N*330קVyIR; ˢQνuf,uf>9 &WQ*vJ?f[ufOC{_TbuZlۼW1Z|_լ3'õ(zOڗ3s4l2n|937*s9J'3׏-F]:c ;E?(!qFӏ:F1:jkCcYg^&X`zIdpQ<`DNWZYaaQežҼZ?"rE/E[z85*Z L/ u"9v~d3B4`q;ka(+Yg^'YkJkt5Ahzg:@ܒl1A7.*)]+d irQoۣng]T|\23oLp[ki䣧~N,]ydص\dr쉌{v߭rqhy-m2=]܈32=60;\1n^ E'9s3ϸ}yNgtr9˙0U4i7^i_\70ng?bؐJ>}r d>mM}P;i|; fiɷ}9X%+(<#ߐOF1捫k`B(7{!Gnɝ9q~3 7 ܔk_|;q sYԪg>7~pg7q̯_gtchy\cQ8}qz8b!N^5&o`L?x%pύp(K3Oep3"l*Ǯp+"np;"n:b`icw83swTwk7qNNWc/vWF:|Pc8l\uy`ou ӧkA޸E1LKr;ӟ:?qwt?YA>l}n]6:Ƹ*4+]O+7)ƥ] nݰFOYu2."/Xw0#ӧ:/S9>6đ==(~XdLW7.B7oDZ#ӧjKA\ai θrf( LIfIAܾaaSVK;/Cq8/K V(+ e(徜l4}j˜'UqaeكiLas3?L@G;-kMQn`k|yYz*1Nl8/[Nd8yeS`0NQf_q^<b ihs_ZyQ[)+da2΋ +΋lYgܺ=vW-yo8Q6lٗ+7{ >AwG;Ly![?yr̿⼸lg38y1 _q^L-#N6mrݰ 2g޺Q6: V y+\RU%r'c(8/yVܾ⼸KFoⲝ}ula󆍯8/.0G49Gqߖvejd-V:u,c\/0}>u^k'+YƸ(7}97'F5XQuֳk3qQl`FG\ymlgx|ӎex鋛92Eqh[q:Ȧ?L'˦qGZq#j1.ՎY2Eu^{#+YƸ(nF`ą:V:6YƸ(`͚G\yYƸ(&gv^G'[YƸ(`f$ r3z2˲(vu^y!.'F_D2w9\`dx=Lfeze9j1.uG\y l, } L^w/qٳtl?LbqL\%levȎuQ$F9:ss|f]T bQ4nʺvq=jǮܿ1(z rekX.*60Jzy]Y(=ilg}i3uJEExgFid0mm}>ܖuQQG b;g]T s2869ʑuQQ kbiQά Ջv0d#:ظu̺ Rm!-(\YH㊢8:rgGş=$^?77u}9KM?N9XC<歔/U>:Y/M u&i1q5"b>DEu&>>7剓o,^29͋0mӘ[tbXVWQy JE1N ڡUc15vLθ_ݠӫr/74S&´ZP;ɷ2nY_햌3}y?V2Sr;&ݤ5U0k(F༵N#6hqGs/M [3-2ɹzA^!lj_l[/tN>"9^j^kat^8U0+(FyL)1~t޿7#8q8ɖ;s"M9VpR7ƶ7ϬvɟnLYɫ&EÆZoqO*~pQ0 jƸbV7qX\RgiVh5\.L/buQâzZiqz=Llޠ;q}}S:J}YVI%'V,J*XK(rzX Yw*iT^ow^YXَ/pٸǍ p_xE1WF ܉kH)JNK]ZVE!7l\l niVt̨+Dy\fvr 82QA޼?]}AغEƋ1Y}[pC.Q*o\zE=Myʳ?H%poxE<+6 ?2%p/⼲NdJwtE`zޛq<WMKhb4 hx׏y^T, p]4QrqQf!`zu6۾>8WlhE1BmW<{>?5%یOZbqqQ|Xb9X}iO^>ӺW,6tgxFg/qQNw<l&3DůZJUG5| >g-'݂ӣ(>,.aI[l%ebمo,.>FY)t3|;LObQwB'`S;t+5Z!ñqo\ Ugup30baVi?qMNQ 8pU,V%sXk,!,|Lyՠ  ̰B_(8W:[-9Zq'ֱ+[|؏=1 jȰer.a5JnNQ#=Hfԋz5l:eIL;L|%Ϥ~|Y1Ƃy5_)0!L\A`H9_!a=;z;w-CZ;6t=?Ml7B7G4kaʗnQACoO.B9o[/Xob8˺P5:Ϻ0ӪõuQ`v:va^}ϢJ{0AƭG݃q7*{uiV/LbuQqazZͬ ?ne{ Y\$5* Llx07n?㤳 مWQ W.*['1 I4K:}hkh$=:Fj`r`ۨ&^m :E bq_/`+`W6" aײQbRE!NZ76/`n{øq;%QlY8ͯ^7`xlME1vJYXp&n`68aMkq|L'Me[TNZ0uW;7qz\#{%,2Wfӣ(>Le 6M\M9^:as0pQH!JN\ԃaULEVriF8?1oi!A>m0޳=J֘BިD?trIf` K.xG7c'ByQ: Vg\ltE1㑁ff|6#8=J>͡g~̶/&^aiv^&Bya=ѹneOܝ4I# C壥BO_&@:^d dY-7EQP,p a 7(sl;['*E1qnt;t Nc8Cv'zX?giGbeXɥ24rb䋥h]>&/Zi&?s_ʷXQ VK9 XK%'_~M,YasxؙH&mWo< OK>_ƅS}sל lYř,'G40mN!o6K}(ޯȵsIU(9' ?v\aڄGɓSŠrN%'_qε,j|O{}QˏjPyQ?&y\M8cҟP53 ?)JӉ>ܜ|DwyEˋte|pYGsץE \:'/WnނK tC^ڝU^9٭]~ݚor{[D/8=h~X)OzOΧ+ٽŃ{fʋٽŋnc9烡Ӎ^bs4S}=YAb*oefT58yMƱ=]+rEq(D`Bb~24SZzEwm:9f^:ub~24SEb87G/B*ЩWsZu8~٣!yݥ+g'pQ|fc%oiqQ|鬳c@_l^TW{9^6AYD#.|uUbʆ4ݝ7N|`g?.$bw qQ{=ڛVNn݆<ǭ`bxŇ'O9<bK,z#oÙ:.vƸm]:eEaCb=j18rxTf5JnNƭ[c(Fl?< g|`o-.N_y OAEa+~Vv\餳Wl]GJI7 Ym/> JNs3l']:fh$s;uخ`4[ӹi\dqQltMټZ OqQ||Z`N VV8׮>a1k n]{Ϣ(kK\dx6_Zx@ʹb[`;jCډ~7?(mƭm 5Jb3n`=͢/N.[4Qrqr?}p$Þ;O!/lN쒍AmPqeLYc6~a2ٹ' C8|"qa)^bl&*\=z8_N0|1M:3o MhYѦ*Ȓ wG僬fޜ>fEɏ.`+͢[r27d ,J~aQ8)Jd?%SХ}6[(iV溌㙮wYdCŸ.L7eY(%V>atfǬ;ʃ56RߏM8=Z3NEw`LE ҬFŻ.f5JnNE?8]9|'V1|uWG~&X9,qI-ﲢ.=bfvPą`%ʃktQrsz ӬFK^ҬFK^jEݜd|K^ZVؙspQ|XJcVE1g-QBw'G ݉K\k(>,q܍q>(~U-62'ǭB6,-4eUeQoN>MYlgYe>{u2˲(MkyZܜ|B&,zsZd5ˢݜ|6Y˲(7',#Y xϢJO6/i[N,usrr؍leY_`w'Yvsrr؃̲,u/Mj?o6fQeNֳ,ǯӿ:^tニqʴeVNX ;2o(t냋bvM=cwlZ3$K;GoYEI\l‘vQ D+<Z?CJ Ko{t=em%ND8y_ܳ`k#of{ALY q{O?3\3 zoFGÞtؒ ^*7omx*Xbto it.]E\!3^t8s<{8==̍q.qj7\i.ucEpUmWyvsYa[=_ܝ:ҥb.L.Ιqz yrn%rv02+7ve]J"ÿ@C87=o<.1̶1,޼q3m6 .Β$ y#WGbI¦i% h%-އ΋ѓJq-KNjljqb)" q &'\ Fw8샼kKoq-Z{X8[`8S7ۏ_Y01lpUʊYbqt,hkfTea`Uc`Ѳ,[8R'⾸}$m6񯋵cV֙Uyw(\m3üXZMȥ҂4;F}XyIMb iyq98ޢXZ+}5ϪaSɌo0&gTϑuf`@) d`3˼xVy:ejrp%˼X`(N?8/F'Leo~]0H|tSyY30Afekqn]`]2 `j82;ƙv.7oVKF>8ރg虫,|0'z_,.N\3Zz4\ _\ *xsw%\iyKZ:u8rff6V2Fv7D#"4}1NzlewJjQ8:DMIo-pfÂγaeCT f_a6+X6FUcs7il7q%xl[q=g6G01l ^.%n{qdž2{䭴38ڠh Kg`@; &Ncl K0"% sy`\jyHlׂԲJ~0̞sqWn f`V,&\:Kzu7DaMǬ%65n K4m?& 6h8.VL8繳0Z _UL?8~J'6͚.l*K/҃a[YWy-Hle ߇U~hZ+}7F&`J#ħ17<QHj2&>P5=PYf@<zU`Eb "'b˹Z:X^^$_9"-H~>:o`@ *)(\ P}PXwP'`ܶz'Hl#~LJlWpshH\D/Mb68DOTCD@/l*qVHW"~{ZeQd"u+*P9EZ"ѫtZ{/[GFW ZD>H[b&&<[byD^ӥtAby`bs$z,H<4TjHj@.K+@-w(|n>+le?ť 8PP;O'Q6JЫ?%z9E`ל $`ȨZPs;z5q8OC="2 خr3)H\y%o(2 % V6@~ 7C-<ãZyL䧀YO+PPdm. $22KOC]7+~^8wD{ `' wK 0wI~a"+?T_##rd7EYRKčjo(9e:Zր~7@((1H| 5,v<R{5༂硗 Հ ^nՀk@8W)v{/vdّZϐޛjuC/9A~7PFF3y?%>l& =|J/ѱm*ն"/>ّlShY6G> lShkcHo|5/DV %P^,#~1}| ۓHayb)QhHyD^ 1r?%{G⌡fU" MNCM)|2/P`mu,$Hoy{ D17olGz[K6)Qt􀙃UCbO^O/%R@~ XJO:;1lf&-`‼H'ybx8tr!/@>{O:_D>j_3usGy򹣤H\DN7xHĢM/^Zy&>T>#"&\/=@>  H.@'j]i# s]t|UO?%ogh ly NRsxCպ KKN=|5N%d.^2G>Q:A> -|ֵNJ^rtz)/&)=N^Z/V}t0]hx0$^rϪDVN/z 6Oji $)]N^PZ;A~KG.[>Q^r Zm uOjy# $)|"ոmA/x#1@t)8%Ym0%ğ Hou9/yC6ЫHg _:8H'{ *7:HgjmBxpX9ZЙ@JeCsdH>lЫHߙ';2%Ho?mЫқApP=/yCY+:J/vy =ӕ81T~aK^PnnE/>{ }paW%1]W?nE>x #,=@`xb z$r^B_>P;-ѰwЋ^RPx69~EK^PěPUk/yC$偉W@|ѥ %r@~ 7Uһ^Cw*i$6rx 5%o(!{I5߷*o$k" 7%o(U^X&֋ʶ mЫ#_ _F/9A~eޫc<;:༂硗 -dܫ T2[l^[[nU$<:`KNޜjy'C/9A~ګ+8{zo6R:yB-P%'yu,bH<:`7t^rƥW,W< 7r7Z:o6:6C/9Azګzk\y%'{ur C/9AںՀ v^4tl)6L>'L5A}^LZHl z[DuVX>A~ 톶֐X?A~ {֑Pj38Ļ,j<+)jW:ě%j/+5;+)jں`u ]P[LuyL<XP[xB桶0F`v @|| %~:p䡶>0 8P[_x?@p塶nxv hym&چ`I::桶Q0@z䡶Q0xx^u ~>Q7?G"NyCIǹHRR<6&<6i{Y-M9Ae!uSn:BI"ujymjM.r#7YW@j W ׬2+CL4/͊eWp2fV`$& JD/Xy5`e.0ѻ2'=mƞhy:o=HH.uҦmKNH]XKPD XMqɭr MiUP۪'HWZWG@7`CcyZE8PmpA^ PM@ Hۥp4&e.CiRL0U@Ci*5,cY`Y$뀚Ҥ?4 7H/ 2Hz NK큙flm*q>ctm0?TU+`~UQ瘇TXxī<lL<kʬ?0cQe<0[J@C$N"M-~aDQ ?4!={I@&Z=*q*֪=XyCV[%Z߽cJ+큼׫kJ+?zj;ѥĎ\&`x?`۫<c)`ؑB} `fH, J%`bX&0qD\DC 7޿lH ^vK ͐17CeԀoMKz Ҟyy%'H[߽p\8nim5= $&v䡯?$Was'W@s\HꫡZ$v H77C XҶpi]PmCM72H{en_v/yAIt!zu$v/DiW$vi}K78~r/jy? pH@#DCA+%c6 _iϼHHݤ^G!H^ X"6:q96$րu~5ԎzP;oN$΀iH}.$cxc_1hy({KB{cisWy85/9@zj@C/9Azj^r`Հ5mj ۪43@~jġ8cpt&91u蘀+Iǫ-dj~8SW#}ҥ+ǫc J̫ J?Ց?AH_Ht鳁^ J>7HOPfBKǫrtO1$OPJQA}U&Vj$ J0q\Ղ J:'(][)@> J>H8X@b H+j$OPSH J׋2^eOPz,H+o(.Xsh{ZH֗^J}Z$oK{Cɴ/` $q^C`' Phe<>&z{1:Dd<}*![pHjz^+v̈́k hPL4Kjz^`C` _Hu["o삸0ˍ(7uv'9.D}:9 ];֡)X u;BOpX }s4U:>BOpסXhcz]2Lu .Dg,αu~'Pru=@~ o-!ד'V:L_}1Ƈ8$Л:CMȻuvGE#@ޅ += 'VZ|z{M=҅莊yO jo`2Tzf6?H?wl_y3aC+&O.*+8P1_#BTA F|&PgkW7@C* :*O0q)Q@MIKޅh,l/J3 fs`BjX6[0sjPQ?H?!ge-!=?'"'ȏt^9Az N 18sÈ ?@) #@@EdN0"8a_~u73~ZaD^v/G=."8hl[Fi{>4È`}|Yy`ZB~c: ;fe?,fEOTJpgE~.t2 }oY%oo+~L~:Yk/I [Vsd2i; *9x+k&"?P&=)TMJHP *S4j/, u.Qbab# ~fE\Q'VbOȿ"E:+OPLfB~R,V6F:/ʏt]9A^9Ae U0"';LP0"'H;"wNWB)bӞiKXgyA+ҀcP ͚*ήHZFigWWFigWwFigW&zJ-+Җ0&P0H["Tls֡Zyq*O~`a.NC~gNk +n8?A k +Qq}b-aa']Ryʽ?z\FzEXyt`6TH'm6*~NPmLT#0T#?V%,"Y+!m U!8>@̑??Ն &) F:!&8tBMj~NȻImvTl`nR'鄴Tl,Tu6G؀զ mChu6 nR)>A*~wM?AMj& F:!&5k4#w5TO0 i7ok`ҦPy8~4(PrsvuU1d+M?]UȻ/Mb&NvF:!4[h`X';G'鄼ӖNH{#r}\WQk$,,%m)ຩzOuR^jk ;^0 WT[ '( [ "p]A;UD0"'Hމ4-CQۚp'鄴wET+8OihdBm +ҳ" 8P ku(vHZjX٤7#٤'(? p4KEsTt yb ybDb X _H74L.ЧLH# huG(iv~bhCS+sOH;-#T e$ "T earѦH? 醂H:#w[#+N˅WBYh CS+%n)S+%+!4pW(KvBibo7{xB:#E&B͊|RluC4Rz x?y: ͡u[" hu;" 0"'Ȼ_ eNH#T e'佝 _& yogPa'3֏M UMZFVv럷cdEi 7D::[.Ҁ#r}4aDNvF:a:/ś ,v&+!mьN;- `b8e^U|]U iQQqu .y* Cu( [?" hu_(hnS^T4I;"Y6z*cYqǡ&"0JO8S{zEYv쫊M" ~ mzǫ">Y5YVCoܯʲy"PnjT2KkQ<+F nL>D0+epiV{"y{%dk \zC+@]3?3@D~,zBJY+F:8;!mB281w~xΟRNsx=W'8|LD"o1TڂSƞtBڂeb-!m%tVtAE}\$#"P {BسgH?p(hWƞHuMOH{"e6De6D:W͝0 iMDNwmY8^Qulـ +6H: 6H4ߠ.[ iNQe;!ω4`~sxcϖicltlՄ=Cv$!/7jx;蒷zNiE{FiEGFiEgFYNhu_IΡ=uP(miBDNЁ6aDNЁ<: :jFjab7lYomVT>%+ 9!"PŶ{Yv D {ZFjauQvSOF F_*Cb^>-7*P_p?O\ Lsԡ.W  8P6]P^HHJ#^7@ev/]Xh n8l R*΄E/Ɲ4UQ+SO" q֯)iTC٘|" "|ߠnфH\|8tbkaϡE~}n XG>iסnv`t@oP6>" 8ҿ9+{:Jۥ@Kȏyi0QCEi+QyzHzE6wB. Nn)ҀVma3!=%u$]N(ea!H ƌ[5# ^tfQ}=!ݪ){_(0#+ҭWylLVi[{\U\Hƿr u?+kzF+nk̡]yo_P0dEWn#r!Ҁ | _֏/M;^u? &ty _/M'^uׯj\?T+8G5F? end^ uׇiJ+_0z^]/X(ۤ^1ҧ9d:&.Tn_U/ªK;\7;dP#W-^Fv7&t]C]7:4 u^vg; *+8~{:'z@ J *z-Wp` SE{ ]f+!}XEo*cE-!ﲈM T!EwV;VW΄u!.kWq&PP|ү`:|LB{D~8]ՍhW;(8o >ЅS[F ][n_ :28.{rh*t!F:È` 1yq Z®\,/F:+OP| Hbŧ',F4 "tU7"PH_0 Ri }: HzF*o|=W##|NHבu=!=!#Fmp] 5х^ 4*^L!8yf+8}\3!]4^cuKH# خ )(i9?SWCsuJB" h TjB' Ǽ ЯH'||yVy3gWԭ;-# 80"Xة>wD$LXH6 +F]U4(tB1$$ԫ C nQ}'kFQ>QѮ'4I$4n: ^ ˾Aіm ॢp>IHoPWE5T_'߭D myw3k/(]MڑFEE=!mA4*oP$_<#oFCW*􀈈 ytq#rlH'0"H7D.`D+t 9i@ 񑬰PQ('+P\oa4`9@> ypk|DQѾAR)`4]B % {z 3^C9A> OAt9B> Ct9B>+~|v,l -r||# FD:Ẁ9@>F˩?Ҟ@uLoP~7(w>"(/lY _{V#rO^SSBˊtgPDP)ʊ|$"PI/Ίt3ZDPI/gEY;"Phkh؈־?PF;u̮7(Xa["rB;@)"(C"r;NBmo=~ WV{$ 6*oP՛eIB>-]PѿAY/xy׬/ 5!_Uخ*N~,- VN`> u+_@lº+ྀ>r⚐/?7T SNC쯡84T$QQ/v|I| 賟`a'`> 9O/?/y} U$ h:A>/'WTp@]*zʗ$+.vʗ@} Ǫn'|I v|Ie+8O"|;*_E QU*_E큅n'|Ie Z;AWTZSflGȗft.ξ:1ԕ/ t|-=Aޡb& W;Aޡ6[';?^Ttm%ۥA}{WP w[P(sg݇T޺鯯qdEڞ_E>-" ǡ*-ǥ&B¬H' 7T~usP'<, Sؿ977U&/5"o(J?`ohCu++f UMK枼0Qh balxCQHد6F?9So(Ҳ" A<+ZұW y(KZV_so(J'#+F5>F6Yıɭq*T# {G F:!m]x9w4vω:l'#cH̪CmQ*}hW|i;BT>H6r>L@ECmj'ȧKiw@Cmڏ) o;/QOwYh߀^t ogjuYB:Ԧ'7u9f<8\)u +臊|gߧÕ#r#Ҁ @ObsٳOpdvzs 9c:G:È(W 3qH撐O^R7F{ RcQc6SEzdi~q*> *C2Qo((:ۯ"Nl960)T}J=|t69^s4lc+axKOMHWE=!=t%WplR8~+V 1>IcQxEJ Iu"y#F#A|hDf}Jb|xlxLn8,L PX`hXW  I#p^ ?gF EiS, p~~5Үp']O_s.`5_Kih`ֺ0 P#KOPt,LC5 CMc}Wpח, 5t.u{`aig  CMu7-t%F:+Wh?Xjj(o{{BfZ7 p$̈́ϊ8BCM^U4pjNqNXJ鄅nQqT\ pTL鄼ŚgP@MH^0 iJAvUF:!mzѶ:*'鄴E?A14yC1ڻߌѦ?m6|fDP67#r)Nhu,Lьt^9HլCmKEcOaezj?djT>3uXja $aaeh p m*a0"Xi薑 `afg?Xio(F;YfZd`LK6Pvq v'D4vbSWp o'~BL*m 6]UwBiu"r)f PPEy{'鄼LQPE ?H'9*X*oX긪8O U7*"p$?btBXԡ"7 vȼGTbang:*٤^N^Oy-!Z[uԄ9}‹ `OXhWp&'NH *F]AGYV#r1Ҁ+!zH_U\rUh 7Ff %!b}H,u*jBZ`a*`j򻺀ZjGᴀZ@EVH_-Qq&髥NT\ y*`Pq'䍯ZΊNH,*JB 雥&䝖Z`a*`j0*0WK8~0c0WK?X 髥N@\$y.@͊%"Yo@ˊw%"/6`ϊw%"/6pdEpZ YDpԡ46DPlv6Dp֡;!]4ZbzKHiTu(6'*JBH: PyN(u(67%" u(`OHNjEPl HHgEסR@OHiQbgB:a2Ҁ^btfgpDpա%O4*:[%!tVbkjBRbkZBi,v yGP:8Hcu(Hcu( p&ANu(;Js"֡;!A4zW;UwX0 i+@OH;0_UTT yc`ZNl0_-Ί4)*b :*\*m% vNTR༪Ԟ7ڀb7p7T RkgnT y[8`l7[QZF6@hXJH'کP$!`G?RwBO_vƖFv@8TKX] P!ϊg {|Zjkx5`lGB޼/*{Jt9wm e&;+?BӞoΊA K}@3TVWjB!] Hc?XM A>g>o~(]=iB#]7*&G\ 801u;ிҭ%D+Qazա]O}`CU'ȻPQ'Ȼ0@CU'Ȼ ]OOJp] L[v9A> (uԾ>6֡j7@COГP:T~|uw+O̟ J磛 P:h`. ?ǽzni@KHOd rT2WK5TF e־HرԮ ~ut\@=!h*"H/#z5]WgE3!=\ ғk }$qV\u7wu\R?\ KNW{Joo$top6Xҟp%cF~5vaݮH8bOSN>R{HcNˬkDߣ?P.#N ?t~دһHm8oC_'c7私`ϊrK{CqLQxR8m& =+.⼵P\bɡ.@z:Ҁ#r1F:_%a1.;: N(u,<1 #r~ZFH'_!vV|cEz!Ҁ^9A>=# gFH'\u3"paDNOp aDNO $䷟-a70zB |>^_U]tlF:! tB:}QuuTO0 Kkb#Ї'鄅>5Q?H']9BZXW|H',tB;n?H',oɊ}NH/nEE# nCE#vEyZ'H>?H',4nG F:awOTO0 eսPq~NH/wtB~e@]j `k՚`N٘RjMO) PP cZ~6?H'wʬ9*O0 INH/yXp֡Z['H=>`+jm#_ 4i?H'WDO0 @EE#^ Zjr*F:!f%>*^@5'ȯY F:!f%>7*^@5q^_ oU: kVWpޜ5tBkU^k_]A=U֑: ҉: ҉u_#P N|US`6Y6P?H'm6S$R'('#Ί>Am?ȟ8iTOP|ON+8P1ED ?2xs'#1#3.# l-!QiT&?UiT\f MP&^4**Kbo6;,FEe6OHoDfBzk&Ҩh̶[3F ʔޚrN(9AzO'8xufr~t" hut"aDN 4È i@È r|2e&7" ʔ tB'e^.R#r.R#r.R{F]H: һH:ʤ'eΊOcLzRNHw2MQo5 O7;%䷟"P0"'H[]}c':*`s$,)xWqzb8 (ᘱ(K]Q1aΊi ϸl_`2{V,n-ebhcDPf wyx#!=|H',w(W gQQ?A5H}^} _} K9iڹF:!=B2nX$,nA mMX8 ܊Tۖp6 힐Ej#_j ',WN)RgF\\T;!=4*OP{k i`Qq}ڛ$gs~lu(sӶZ8j**9+M9Az6i^9A鄣#r40 #r40Ҁ#r40Ҁ#ʟ*s Ί3"o2%gDN?F:aDN?F:aDN7F:aDP@e]&H‘>+*#6gEMTpL3օ]4*AC-<e?nlZ4D&kߨxT@GOՔbK6^#9IK`Oȇh ѹ aڵ%c"΄|¥%+!Qb,u_|KGBv.خ#l=!h䓴W4!R_jy9^%P4!?toP: ;+{CYO8W MT{U$ͮcXB՛רGDNv=Ep@kpaD e_2Ɋ|.Y@݀|g[F oN@,UD:+OPYBhe=!^kB ^&?4*ҞH*MD0"'Hi^9AۇH:vR0 o??#auGŕh"Ҩh`fCwBHR[BH]qvg0@A7@]VP넲[VT!0CfEޞњP %-(c;!o]@Ek'}ΡFBiuC]S]CgBڞwYD"y'hKBe鬸 yE~ֺ%][VuOȻ,"%F}u=!HH3W4`+UzB Q/g~j>y{gvm .r,ef]V\ iYqtBڞam*Єox-r^|#s=^|#s=/V4`9@ʑ0"xʑ|w͠9W^|?u힐wv-KBͦjl08'p/}#r{-{H= tB9A޽Z[+>VzNaDNEpÈ m_] gBڼdmcj'鄴yڞ8`]HA{#_U х5"YvvBˊig/H_–fEq{;#/YvF/M̊E3"n WVLjfEڈ wBLh(vO01"YB͊eE~{`V]?гQ/M!9GP7m-/9'鄼kG#v!Zׁ F:!m&tBLh]*'鄴кnT\O0 MPCGpGTQ*:Cf'Z7?A~кm}{h U>=ny8u'Poy:Aކ{h 6TM=r Uw.к nRZw;A05@Ou@ֽ m|`ֽ m|&`} mCง} mCpCJGWwWT\кPyj+iuwKZozuw{h ғthz{{h䭶v~VwZoik+ =/M{ʊ{_QпP7.YP7ZGH[mul' ~ VQnڅ [VGci/YE_v!)Ϧ޶'p8F=; i}Vȡ…;9pKB;Ԅu#ݝ׽?u}tw^ ׽7#5bsLDPεh 8 \95+ҹ-+):@{?г">@-(?eE:3Q9@{(#E+ \DD%D oA@#uR}jVwY *ji'xe1ޠ$]blȻ,`yX8.%,> f }YBlKN7KaK ЖExӈtB-~Hg*O;" 0"H4(@[E{H(Wsz> gF/ҵwB;/`O6I:"P uEX/E: &HJ|)YJ|!HZ;@h]؀.y+H-a߀2FBdp* uV*J[ CN{ n@M ..\r,UT#!$~6^cJ78.ZBR !, Uzl bD C{BEp%O Q!#/iTqbNxw!PԄ|}uH9oPlDB ?e!qAREuA#Ŋ΄+c5JP9"oP0.[eJ‹VS+u(/iYb|*W8G5e =#άWezF/\Y(+sw%" M~ `}?Ue C-!?\(xWKQ% F:!='RńzB~*QZ2@/8=H'&*&H'܀BE<\PqH|)xfE7(  / /F:+g# _^tV+ /F:+g#rH[ 0"H{;# E:`DbXV}U_N |ʯq*tQjKμ*{l+oe.ǟtU9@gHޠ$xF:+7 ex3!}TrCL|ʡ1J;@_qFTܭ VL@/u|Ab*_|VـG'ȻUpR} _ V5UX ߠ%䫝 )1oP%䫝c8*T  p$Xp&뫀ߊb3h 9^z0ǘ++13? y#NhRcSEl?ƩikOZOo>x~>"9 f|kFzB- R [3j#|Em|#"f 8w‹W N]%|C]%!߶@(Sw`Q =!߶tPJH.#!(tigBQP'*|0ҥ.T F `KCYIBQP&% )*ZBQP =!oti-!o}ti {BP;*|0ҥT y;`KCFtHPq'=󀑮 >ΈVpeE~]DΊ|3"e)M9 7@͊|3"̈́;eE~dSDygE~zFQO^`OH4`+@p$DC-@8^"p\ )(P P>j* y}1PQfHcZBZ:'뫑NhcH'Ա{Bi ul/FC-@85H'SWBi uN-#NOh/vEC-@ 5!_ω4Z:;%䫝NszBV:'`Kf# P j1ԹGBi "__tBL:m%\/ZFRō/!FP]P%D(^+*zBKC5Tl t jt/3!_JH?p~ * u%2'NW;Q1~F ֱ%!_>QqFEKW;/T5!_{V{ **^k,3W;Q1~F :*|s6CE/=!_{CmCʊ|[qv&Ί|;'VM4+NP'Cm?p6-=kwBNn‖/wGTzBP;g8:O^x&p%&p$TT uD C5Y U*4٨( 삊קb]5U/w&,UlZG0TSl +p`+F8nU*nZG0Tә$!_Qq pUIBӄ|{(%TjќnWF:!?y~~f@X–/tV?@㝖\/sk _ϱnŲb2tl/Yo4 dE5c]|~B͊|kF?@֌qv ̊|O' WFL57hc'[36v)[3N{:Nh{:N{:N 0"t"`Dŷf"p`D"E:, ??' WF9N 0"ȷJ oM0'_v%b py| |d|_uQV \6NW]py|g.['6z.-!oZ.ߠKO{tå "#۸PQߠJȏm\hoe'6.ooUcwTloUc]{ 6@|bZ/FH'/.TwB~\%8N!QIF ƻZzzsn C\=!zh%(H'lKN 0"ț"p`D7/E:<]yyoЭ'K>0+.~n+!u}tPnAw F:+tׄ|;]Q[ AwOtPy{x*tVo}$T\oCD:+7莡~wsAw G:+HgE{4!oψtV7HgyBޞߠ7 gD:a/ SU gFsN 0"ωt]9@~~7.xOAoл%D:`D鄭#rH'D:( ??' gF/t>]tBq'D=w!8'$ߊK5ͻVk!oA7pTlpGGŞu| e `b:>Hxт:`PwX y'A*$tV7C$Ί =!$@7D:+7Hg GB$0N 0"3"`DgD:*83s-}΄=#Yޠϝ=cowYD:*NC]>1%]VZ[F9 SkH'S-+gA_xEDBs `x$@H'ӕ+jB>tVop%HgQp~"WС7IT|鬨opkO'Ί|opLgΊ n%9eZ-&9dGkv#r* M. Fo~>PWߣ 0 x| F:!+8-!?B;Ѿ=fB~ :JL|J?"Pp 18m-!3aѾm=!3aq~$!aku)5!aD/ըi 8},!$ؿm3!$(6Oȟ(t67m%OD:^ap'OD:Ḁ,l {䏢F:!!jùZg~JESp'~ G>۹8͟DH_?;4478KT'X  9@\@ D:]`: p^ . FHX ~fɌo?HgHg%!. ٸᚐG:78|$G6 |?"'"p^ tB9@>FU sVw.`Do\{B>r#r|+ FHX ]Nh0"'78L'"/`DOvE:Ẁ9@>F #ak'F,Y dN(0"G"P/`D0p\ !"o8*ZBqhk =ҏC[jkPЋʠ/\H'"2 w6 }#tB/"o(Fa=^DPn2Wj}|bwjv5&3:ԦWMס6n8A\iuM̼i:ԦT:Ԧ~|T:A>k:Wj}|wjpL8ZjT:6T:6p;! ШumRTp+h`Pۘ'gtmCmOP@Cmc `1WjT u `3g| Ն'| zC1>5b|lcf lclXa8P 6@z q%7l Ζ| f{C1>lr Oy.{9>l%l䣶6 .f#o(v x&r63!bг"0/!r|\"0/!r|d"0olǶ'fG¿ϱ2q9~ա6'H='| z8QPpԡ6ڼ0/YO0o@CmN0jf/X9 +FP<51S#tBÈ tQ9A>kV9A>k~WjHF1:iԕok[p'#Ӷv0ujcou: V>(WG}b[!H'\umwqɍݶ'~8L'/-!Ua #p6 ;!նCT# ýήC3^݈$j0l (݈^-ujQf{0ܻpaՔt|ZB>i[G摍tB0#Et.jo%ĶJevCtBb[2zCtBZ6nP&Г)8yzB>57WB>5T1{֗*S,ao ]9֡LYh ]R]h+!4~8( F:!%@j,U Hq}ktB/ҏm 64j);!e HdFԞ{9CDO@Fz7'~f#=Ήz?8'"o(O@<㜈L>g6㜈`pE'aDP6qण}2&Ąӻ^n26‘QOP GVcpd5 eȷ9#a?zd%s7G~ ~d5L>my6#+\'BtKuyd`o(Mӄ_q|$ 5dmKP& fZږ  6~ՔסNN[>A>6 \m .8 lF>h7gq֡vve'tNl4O0 頝vmhܟ`!4GB:K]Ѿ_cz6][8()W]T{ٜ/@ltNt:#[BA`L鹕L('O?E%!=E֗?ʄ'O?=`>zBL7? h CL/U|.?6@or2K]>$7WBƝpvW%,y;"/R5aT7ao6h #}ԁFKX8cM髥g©nH_-uXFjƕp0WK]h FjY햐>`o{BzYh#}TA&gZq$g髥4ZBzZĉ'^RP0j'2l, aɵ̽G6аT@Z5@F:7Nϑ[y6ǧ"Y g#^`6sd+S SW7K-!z4wƞ0աxs@Ii鄽ԄN(u(6HXu(%,h:p&ﴌ4Z]=!e: B|zB|:pHRPO4[w%ԄR}5ťZB:,iQgB:,i@Cq@OH," 8P\p%S:)H:K[B:ei4:ƞOYD:arjctTV@OHBKjh\ 4)`|WK54tj3%,LWKu4FR%!â}o@MXU/Ƒ*},U (Wi vpb&XLH/4D#R@JHxF 44NYԠѮ v%t >9Yc=!Q$J*Zm@lrV)߸q$wuTn`o "ZBzD LHo>UɵJW@s_8\ޜZ 69zl'׿;aZBCcT:`KHX#W3ֈ<`}⦀F(nNuGBzjFK-p&gyR3H8%!=cUF}(nKE#= ;!?ՍUcR[B~Rŧ5"WKRo 8S]95!?cU5"Ɩ h '*X_j|+aS6༂WߣZ_sҋ>0 {;EqtBNщF#S8?H']hO0 {;E7'2wL8Zj ?7.;ai_e/_ Tre:\A9AN_o(Ni G6o(Ni - W|CqNK_8Pe u2 Xŗ+NК^y_ )lw{CqسZo(N0 _j6YkHcrըh vZFH: !H': !H'\uCڑN0"'ȇwWkuCڑN0"'ȇ#P0"uHjFH'WJ+v4jסʔӤ9ԡ,Jt(Te4't(Te't(TeN4'鄅V8?H',ܷ F:ah\`[yC#R>H'T\?H'V_h:Tq=}+ F:! F:!o F:!o F:!o F:!dqաwd:TY}%3ju {,9Az)KԡRl9+!Ʃ)|6Ыd*OPpѨ't]h`nxF#h҉ F:aasSca2aҁIYqס=!5:`N#rI- ׾zIKYcjh 5p\A95u,0"'X0"'X P>mtR};: kROP%T} ?tlOPgIpQg#e v>h,-# 2@z2hOPҫ1 {,_ %" 8P;H: u,W': ҏ#Ҁ#rMαC rIH/F嚐^4È 0i@È 0iYyCم?5#rn WKȯj6aԠq&WtoVn#rns! Zn8>AY _э ~կL(3!L _ZB~EW57z\1!myr K]Fr'4[BHq~vO_lOP֖t { K݇HqHHoD:}%;"JBzB֞o(E3{7" u,D0"'H>DpaDP6&M/`eOPvFNoD nޚ4'(69}scQ{:Nhut"zFpU2ՁMΥ{:yCمkVOҋ$c$,\J"I$q`pk':fŮ1(ꐫp,_M翰|%,\ Ʒ[eLD^]tBkuWW" 0"'X[l:-/X{JB~$"/ڲ5Օ HiQ9Az"ҀV9Azu%Ҁ#򆪅#dmuψ$\ }Nw[ a˞>i@( A: Vu$! gqr ֗ _zB#z66CT>ғ2HqH+H0"'X8Ez0"'È`j>f |l #h74ᴄt$,XU'J4':=!=$t6ZUJH4'>i4J64Νi@È RjF+k5 K+?SW6ml3!eSW6E: P8\hOPo@pq|W从=NuDaDNuH': Z9AQ#paDNuH':^ua,~ud aan?5u%ո®+a?Б @~Ts/н nvE쬄mq]Wz?K 5bN8J_`ͮWvF 7]}a`yՇoyG\`ͮU`~؀J}Q]`\E?L`?Pwb4BU"g БDϥ>Xq *s9݂pr\~=v[QHB`Nu2G+GoP7-sn>tᝉ Q.G NA_rF8_raFh/6N{:>11cJp21uaK͘\L0ɥfL .Yy!RnZt p P7- shL쀺iIӕFg|qӥ&CӥP7- sTgb%aNLiIӥN&.@ݴ$R7nZtiP7- sy;H9BXY#a>`4$RK}aG _ڧ$RD]C͑0t)IH CB\DAʑ0t)M8;H9.@Ai.jP / W ./4Z} uy)˘uy) ./4Z}RNk:./4`_0uy)kN@]^i(ԭR Fu 5W 4Z}u 5ۘu 5 nNswn,#$t@}ݜ{nNs&>9M!\>9M8 F}tsp`?eNs-Q7- sPcw ^JL4@{$R{^Z31u0KK &N@]&$R'Y5 /-u1q#QwboƒD{db%x5@]$ K%|Q;p/>lƒ'H|qx<7$/>/rqza)q.@}RG?PsrFx c1:aǜ!,%☓#a1'G+KmAh1p9XB/1>X1C=!,,uMu?GKK5]H}k;5@]R 9BXYjwQI웰 9G&~78,um<M@%Ùhdsu,`b|#30 ?nP7޴zB WαoP7/]sͮAzǻ.h8tv$(G]8b QG B+@8sue:sug~D̑ ԟrp`\ 0b̑0^|Mx*p*/pꘝps: <8ݠi ƾA]CKhODݗ8:ˍeL\hݠMu_nc9M7&op}Dǚ/7=X P:L>oPn};*u_nA pAݗ#i@]BP~ ?= 9^xTO8.ǩ?,5ko3x =um3Ѿ}x ,A8u{m#lD]{iU9rӀ^0u{m8k)A%ZN̑ #9 h#9gN'.cT`kl.X{4ЦpӀpg p Zs@.Ak47hm}s ͭ3GoiS9rzÝ5 0G.us_\8 0G.P_8 P_i$7hKr0 0GB4< 9 Kp33:shxcp J߮euA/p$ evA}uF%x9g|f P_i$7hF<|qi 2f 0G.P_13B/ ŧGs(r/4]Eq4@]!i@y@$u%<Ew &op];Fk ᫻[pu$G.ÂVh7Ğ\;_8@MHwɑ 7iY9rGsp`\QŜ#W-hs QbS__97j!ֿAzVNZ >Na3J9bN8 P_Bi$opnB} 1 Ж\N˭hM@}].8.Hop 4\r9 홣4Jz'bp]l'BHz@'v /,o.G.Poi^9rz[N̑ Իr 0G.Pbi@/@]i(@-g]l9 0G.P1{k{0q]3y$}F}vFv:QFb|vFQF8@}̑ [rp`\RӀsΠ#w4)!|v@[r`\RӀs̑ [r 0G.PGǩo[9 8 0G.PGiU9r˜#iS9r'ȏ _4`/@ePiz7_db|y_?_/0ʑ_?>D+GBq  n$or/Oxbˑ#aN#QŖ#ؑbˑH__Wl9>OWro9K ]?D^ˑ_x>B#8|D;GBq/ߠs7_xNg}nʼn &76_? \Lߠ8t 0q8 O)qVk'nZ{#ݠ>tVk OAVܠ>t7( Ow'ֺA}7pZu}\ݠ>cu߀!A}Gm7X=:~cz7X=0 py gnPz* 3VI psc\g: ÃK=鷥8c=mg#ݠ>c g>:qd>0B^yW~oh}|T7}| t]>>>n s_í>ouz7@^_ p7A]  r?.uN$w t]nD?/wH+;| t$i> t|D~@G@p Лub zϵoRw77k7.oߛu*oPo=]{}?)i|uf*t! KcK01F$CXZF[QWPr/ $ J?$_`?cLpp2Sn~?Gw^ Pau q} _R 99rfcZ!1ti k69]Zb5!,=pLc29]sXRna u[&G K Per7m!,,5n˄9 3K/\jƔdb 1%8 Bťn@ݖ!`3 aNz PesToL쀺-Cӕzgmœ.-u0u[0KK5&:ntimœ.-58u[0KK]gƭ٘/&_PKKm |`HVKh#ϒm bq!#; |HRL8|D:d%"T Wq< *ٸ\DP?m ?'lơp)ĭ+Pl ȇlt@>Ƒو$,,uL8uDBНp!!$F#$,,u4l?/" KKZh\O;'-Wop< &_&t xMf.U p[;o6;A-7Nhhr{G.uYazf #r|,<ҀjO8Jr@7m_6NOw Gvݞ/*p.@W@>mzC8ȇl\pCG6.'G4O@ܮ'G4Z ̈́䓖-78|)سh`;#/|qȯ88^XjHIWQ#|qL8pV`70aѸ*p aHaKF0aϱ!GmśU?BiQ#8 1/ެm|cTS1yQ}5ҀV~=Nc:Z|a,M9ND g ΄ ⷹl,17@H`~c)>O\j/ȟ478'r4  GyD' GFN~iY9SOW;R4j 9c1@>fO.6fwǍF>-3r$l8A>-i9jF/e&l_o*W8$hh8eg^ h MJsb@ ;| 'ŀ*ipb@ 'CL{̄|CL{;b@ 0h1>)Tx1.5$;)"b4`D?i@/ )Ҁ#r!H" 8 0"b4* )Ҁ#r!IFCL Y.lT@=78[O?иCLF~9 )hll?i4781E 6CL9@,RWFHͶM 0"7" 俕G`DK3_# [[{$1J78m" 0"wWm@ݕHjFJ[FӈtO#F8: =wQi7>H҉ i٨`U{y@4Q7h{Vy@437\h]y@47h]y@4FD#&}CE#οaC#οvFHH"hoHF#g.jx FiĈ< .4ҧ#hGoHF4#h.`~.q}V.Mq%.M4 =(qi-4 =(qi4 =(qi FVz6: ?HRH+S{ 95ἇ.m ?(%\Х%sZ}]LN&Aɜ=Ck'J =t1;A~P2LhAɜ+C'xqP2w~]lAɒ< =tu%%\ ^,K ^,t.'OX x;A~2H fB.'OXZ x?A~2N',skq]<E Jn8RAI$\%OK%s[}] ?(C'xqP{B snOX^H7lh',/hz6z@4hz6~@4hzD'醞-_hͼB#г%?_7/6< pr] =%PK =y|ϡrd< 龜-Fz4F/gKͼaG#ݗ%HfUH"+t_Ζ/EfphG3oHl=  NA#^ˁɄo'L&)I4^lMoFzPbKG.Ul'xqP2-a# HJlFϯ^ oƫz]W-cV,>埃i@+&onЈ]뛫՟7O? b[?/W &e=7FMBۤR-n>`KKlLHI0ҥlۤ,9b4"K/%w@M.q\&ǖK xMrt&RmP/I#xT[@Mj-aƨ)AFY=vF:W BKt#]ٸ6Fԕn>`KKhHI0ҕvFۤ #]Yjll|4aKKmh|4aKK\W\Wh;\Wh;ㅬ :" x oR?^#;C:" H7fm M$Dh :" x;,7UG$!/vt'hF:ḇFOj{hknF:ẇT}m HW#P6@zmMIht5 =55H=5[# ִ/FC[N@>iqm͞pMH' 7 tum nvE:=5W6* tBNFP=$ͮH'l҄H"v@|=,]N ' tqmpͮH' 7 ߗ4ງ42]zjri@j-dF H0KKu4n[O奥lT@Q^ZH0KKhtԕH0KK&Fye.٘AvuM8Hwɲ1QKedQ-7 %l4@ەol]\=a$HHwP?B}&44]7lhI:.Y6?\ B޹/.u풰pAvl?B&,\#) pN_ oـcdyRc<`i#a7RgoHOX\}'4@~P=[DK#ayk)yR%u;l\!"XilpӇDK=Ӈ14˪_xs :G6E#" on~im9774lߠxC6E7(/ސe~ ,7(M/ސͳѾAi xl=/ސmdcl [GDWYj W6'ɥ̈́ wri Х wri;`vC]Lln'H?D4`s?B#z6GHs,a/{'| rp`utFUҷp`rClv),Nz;A>K&. [n'g5`~|M%l B['H\l} M':AH }tBW]mHtsC =-5hlaB. [a'H]&0wKo7hiH_xq4;\‹_p>/ c.}‹_p>/?!}‹_PHp^ t۴ܜːVm dhB/on~y|ϡ3.~/o8HG]_p?旄t:ٸ H]774 vF>"c_ް0b›_Pbp+գa2=aG#`9d;p9dHז:q9h-ufsX[BR@>.A܀|9" +9.sIXX,MrH8ecsyG'4@:,,UVOt9"XXNMrDTYp CvY3 CFckpesȑFc l\|9hB~u `K[Dcm- DcmTԑˆ$-u&ͅ9@}W\4>'{'\ͅ9@}*p7FD( ..Si^0""h|O1vqaDDhbzˆ>鵋 #"rGT ..S  9X*+/HT  !Gp$܀iU #K-@Ֆ _ȑT #  # P't@B4HnUgGm# Pu%|6ҀUwGm# 8 P$܀|6Ҁ) 5{.lT@>ji@)@mQHjjGm,a+@m=Y3Ohm$|b֬'6@>1i^V 'f# 8 PNlgI 'f# *Џ|b6aૹ&T@> Xklj@4֖jh|~5 kKlt@>l|~5 kK8j@4֖:qՀh-ueX[ '-.htz5Q[4?`Gm5hh|6jXo9x!_|$[x=\Qh|^把hr' ^7WT@#.4Qhrh|ķG⻍lē7WT$|6{x븹|F[/hrh|Mlkl4@>ƞTpD}$|-" KKx把}h4>}ȧٸZDV$܀|*8" KաCTpDV:,u~T볱Ѿ$,5zBSIXXTpDV:V^h1qb-GTOG$aq'\|*8" K) 7 HRF-qb[l΄Шsb۽I\F>llg#r|*8Ҁ#r|*8ҀV9@>i@/ 4`/ 4( 4, э4* {4. ֵ`Db*88Mz4* ߠvDm|0hߠnÄFra nIN-ǨocHqv@>&9~=9 #r=^lJ 0"x ܹ'o#r|i^9@ 4($qKBA#FP 0"7M`#r|iY9@ h Fp`DoGۀ`Do# 0"7/8ojx3z6opSo#7_7/h|yh|y\h|yh|yꄑF#FoS`G#FoS@#FoSo#7_Po~7`A|yt4M`D>< N41aD><YXl16͇#8~C Lh6opHIF |0h!*378D`Ree 1@>Tٸ1" +RVrN Pu _Zm G ОP PUO&Zv|09TZ PM:O/-ZYr'\O/-΄ h Н8ATKa= _Z dz$TGMiB/@y|=T['G<*@}|i9l&NO-@oO턽 x>u>/0g#iST>Ҏ@-A;=dz~7|<\?< N4p/ȗSF#0xu gC#0_xu;y/8ȗc:OF>`yT4/S?uGz'xhYW_0c^~ƋxuG>Uy̅~/xuyW_P'(c:OF>`~ !?V%rDω 5 #]ze9qH88aKOٸ8aKO]hωFи6 G$a |Nn@>'N/ω#ጭ ω#|9qD*'4@>'HSks'sl|NQS+' Sw6.@>'4{ Yr,FCN j8w #]zF;䄑.=U 77_>Ks@,fon>G /M@,fon>G /-@,fon>G //4|/4|?xsYz;@`#774 .|_KW@ _on>K4 n|h|,.4F: PLS# P #O-@;; 0Gps{̑(ϧ* 0GP PO5@>`4<|i@+@y>us̑(ϧn@>`4*@yurgω# PdjsHS PdgcsHF>'Ni@ 6@m|ܛ0K{Fy驖{Fy驞ǽ ԙ ǽ ԕǽ ԝǽ Tk87aWj= &SG6n@>CM奧 U[3M| j4JгQ9j% G 0ښLOmvBWW_x]p+/hS[p+/8ȧfrh45 jkՕiW]|W]+/ȧp+/ȧfh|1+.3U\QoKP~5" OIXxL|(|)  ߯F$aQ F$a2-jDZQȇ6-el|*gqoDwǽIXxpqoDV:7juے5K89@>4`D{# HZF7Ҁ^9@>4, Fp`D_# 0"ǽ6nSH^wO8 0"ǽ^{KQW6mF vjΉߠ9hA #9hߠ9@>|4`/ Fp`D_# (HjF5ҀVIXF4, _Fp`D/f# 0"6`oYǻw@4( FP 0"ȇc/7OAx3lAͧ:FoED#FoEB#FoEF#FoE'45"xs,;5"xs,5"xs,|9F>|~AC#FoE_cu?s5"xs,5"xs,sͱhTi7fU: _X6oPeUgU]f6oPE*ee  _l\A`ז72*صQ _G$aq$Fm G 9jO('Ī# JB+@W?A>'VՄ^Xt]'Īp>A>'V wsbh 9N m X't`P N$ iB/@y|Nf gsb5O m ̈́ 9VZm'>Nω[Qr|NJ 9Hn'ȷ||Q|kϧzS:jgϊƄWǢ_p^~wE`G#0:|}ձ4WǢ_Pw:^~AC#0:FC֩xu,'Y}\h;d}p&j%>X ?sYc#+@C?X *Yc/hh]WǢ_KYc7Kв9"ĺGB+4F sℑ'NS% G$aw G$a #]x<8" 8" OSL>'HSm=B#G$a59aK_btsDXޜnN>69/|2mmb1{s9"_8Nɗ 7#/ޜnN|>?xs9"_8ٺb1{s9"_8*غbzs9"_8*غbzs9"_8*غbzs9"_8*tsDpU8S#h}gcO4`+@-HS# 8 ОOU@>`4=j|i@-@{>9ҀV|Hz # 8 ОO݀|iUx4@>`t>ml|iV&-;H4 # 8 ОOU@C4$4@C4&t@C4=:9Ҁ^|;HS7 !GpwȑΧđlh@>'4`/@ӞP8Ҁ # WS-ބQ^jl@>M奧lT@>M奧l4@>M奧lt@>M啧Z ǽ Tٸ7a:qqo(/=Uh {Fy驚{Fy驖PFy驞N 5^|5Λq%44 *vNh;44N[6?xuvzOձhWS#WǢ_p^Ni4tE`C#NCY8h?xu,Gq&?xu,|j;}%?xu,|j;'_̚;F>||ƕpjDj.@_HSmW#T7 6{ȇ6GgIXjP#TP~5" +OP 6-Wu$,5΄IXx͕pjDV:5*4܀KuΕmll|/ ; _G$a|$,=u$BP8"狑qo#r|iY9@>4* Fp`D{mm 0"ǽHqo#r|ji@-|qkB+ F 0"x1}C ,>pVA _{e ހ3ԽQ~ !Gb6hߠF _F5ҀZ9@>|4`D_# HkWF$aO{'hYo {+ _F`D/f# 8 0"Ŭ燳 zW@>|4`D_#7Ǣ_oS]Ag-o_#7Ǣ_p_#7ǢF|9|9|9F>|~AE#FoE_#7Ǣ_ȇc/8ȇc//~.iH_#7ǢF|9DÑߠKp,72o>F  _/A%+o*xtq@ ^ڲq]& _/htY|tdc l@ ^*8*8" KPJ#R;A>'vVKUz.'Įpu|N W.'Į3.euZ+eu'l  9[O(LOωFB-ev|N& 9&\6Oω,,e\Oωf] 9V 9N p8A>'vo G.sbP p ZZ]Z.sbwM| [Y ?Jn@|v_xuԙ'QǧΎF|v4&:|}ձ4WǢ_P>^~AC#!:FCxu,'٧}ձ\hfWǢ_p}:}<|8@pvQk ^|8%xu,=8h_9/c/h!/c/89h\A_wȾw9@>'m g1j7 'tkq7@>'NSw #]y88aKO(|N0ҥJ6* 't驚ωFTFs$~|Bs$,ZF>'HS'|Nω#ԙkҍo͑$8XԨ)AFs|jԔ%\ȳM@,foN7G 7ߓ϶9/|2=N'ӳ7@,foN7G 7L?xs9"_yP͗ϳ 7#/gW@,foN7G 7_>nXޜnn 1|9/|<tsDpU כW9/|:9Ҁ^̑8O݀|iUTi||jαs[Ni  0G[,E Эag:X  4DTJ}?/C40ӝ2z 0{pU9dOs*`.BCmz``jY .4sȶSˢop1`Z}xzԲ{ßrdL|XWXj ar `#ًP!,u|Mhϑ0~R`#ʱ <{:X'Tͼ0~OR$*DŽp4͓uX*:ohՋy? spcu)šo<\P_BLT4^E8C@^GtfRiPKF_rels/PKFWl _rels/.relse 0E%NkADv#[I*f`ܹU0S,AVnk{졩 *E'Kl0QdT̜'˛a@M

CUPS API Programming Guide

Michael R Sweet

Copyright 2007-2017 by Apple Inc.

Contents

Overview

The IPP Sample project provides APIs for IPP client and server applications in the "cups" library. Most library functions are accessed by including the <cups/cups.h> header, while the raster functions are found in the <cups/raster.h> header.

Compiling Programs

The library can be used from any C, C++, or Objective C program. The method of compiling against the library varies depending on the operating system and installation of the IPP Sample project.

The following simple program lists the available printers on the network:

#include <stdio.h>
#include <cups/cups.h>

int main(void)
{
  int i;
  cups_dest_t *dests, *dest;
  int num_dests = cupsGetDests(&dests);

  for (i = num_dests, dest = dests; i > 0; i --, dest ++)
  {
    if (dest->instance)
      printf("%s/%s\n", dest->name, dest->instance);
    else
      puts(dest->name);
  }

  return (0);
}

CUPS API

The CUPS API provides the convenience functions needed to support applications, filters, printer drivers, and backends that need to interface with the CUPS scheduler.

Clients and Servers

CUPS is based on the Internet Printing Protocol ("IPP"), which allows clients (applications) to communicate with a server (the scheduler) to get a list of printers, send print jobs, and so forth. You identify which server you want to communicate with using a pointer to the opaque structure http_t. All of the examples in this document use the CUPS_HTTP_DEFAULT constant, referring to the default connection to the scheduler. The HTTP and IPP APIs document provides more information on server connections.

Printers and Classes

Printers and classes (collections of printers) are accessed through the cups_dest_t structure which includes the name (name), instance (instance - a way of selecting certain saved options/settings), and the options and attributes associated with that destination (num_options and options). Destinations are created using the cupsGetDests function and freed using the cupsFreeDests function. The cupsGetDest function finds a specific destination for printing:

#include <cups/cups.h>

cups_dest_t *dests;
int num_dests = cupsGetDests(&dests);
cups_dest_t *dest = cupsGetDest("name", NULL, num_dests, dests);

/* do something with dest */

cupsFreeDests(num_dests, dests);

Passing NULL to cupsGetDest for the destination name will return the default destination. Similarly, passing a NULL instance will return the default instance for that destination.

Table 1: Printer Attributes
Attribute Name Description
"auth-info-required" The type of authentication required for printing to this destination: "none", "username,password", "domain,username,password", or "negotiate" (Kerberos)
"printer-info" The human-readable description of the destination such as "My Laser Printer".
"printer-is-accepting-jobs" "true" if the destination is accepting new jobs, "false" if not.
"printer-is-shared" "true" if the destination is being shared with other computers, "false" if not.
"printer-location" The human-readable location of the destination such as "Lab 4".
"printer-make-and-model" The human-readable make and model of the destination such as "HP LaserJet 4000 Series".
"printer-state" "3" if the destination is idle, "4" if the destination is printing a job, and "5" if the destination is stopped.
"printer-state-change-time" The UNIX time when the destination entered the current state.
"printer-state-reasons" Additional comma-delimited state keywords for the destination such as "media-tray-empty-error" and "toner-low-warning".
"printer-type" The cups_printer_t value associated with the destination.

Options

Options are stored in arrays of cups_option_t structures. Each option has a name (name) and value (value) associated with it. The cups_dest_t num_options and options members contain the default options for a particular destination, along with several informational attributes about the destination as shown in Table 1. The cupsGetOption function gets the value for the named option. For example, the following code lists the available destinations and their human-readable descriptions:

#include <cups/cups.h>

cups_dest_t *dests;
int num_dests = cupsGetDests(&dests);
cups_dest_t *dest;
int i;
const char *value;

for (i = num_dests, dest = dests; i > 0; i --, dest ++)
  if (dest->instance == NULL)
  {
    value = cupsGetOption("printer-info", dest->num_options, dest->options);
    printf("%s (%s)\n", dest->name, value ? value : "no description");
  }

cupsFreeDests(num_dests, dests);

You can create your own option arrays using the cupsAddOption function, which adds a single named option to an array:

#include <cups/cups.h>

int num_options = 0;
cups_option_t *options = NULL;

/* The returned num_options value is updated as needed */
num_options = cupsAddOption("first", "value", num_options, &options);

/* This adds a second option value */
num_options = cupsAddOption("second", "value", num_options, &options);

/* This replaces the first option we added */
num_options = cupsAddOption("first", "new value", num_options, &options);

Use a for loop to copy the options from a destination:

#include <cups/cups.h>

int i;
int num_options = 0;
cups_option_t *options = NULL;
cups_dest_t *dest;

for (i = 0; i < dest->num_options; i ++)
  num_options = cupsAddOption(dest->options[i].name, dest->options[i].value,
                              num_options, &options);

Use the cupsFreeOptions function to free the options array when you are done using it:

cupsFreeOptions(num_options, options);

Print Jobs

Print jobs are identified by a locally-unique job ID number from 1 to 231-1 and have options and one or more files for printing to a single destination. The cupsPrintFile function creates a new job with one file. The following code prints the CUPS test page file:

#include <cups/cups.h>

cups_dest_t *dest;
int num_options;
cups_option_t *options;
int job_id;

/* Print a single file */
job_id = cupsPrintFile(dest->name, "/usr/share/cups/data/testprint.ps",
                        "Test Print", num_options, options);

The cupsPrintFiles function creates a job with multiple files. The files are provided in a char * array:

#include <cups/cups.h>

cups_dest_t *dest;
int num_options;
cups_option_t *options;
int job_id;
char *files[3] = { "file1.pdf", "file2.pdf", "file3.pdf" };

/* Print three files */
job_id = cupsPrintFiles(dest->name, 3, files, "Test Print", num_options, options);

Finally, the cupsCreateJob function creates a new job with no files in it. Files are added using the cupsStartDocument, cupsWriteRequestData, and cupsFinishDocument functions. The following example creates a job with 10 text files for printing:

#include <cups/cups.h>

cups_dest_t *dest;
int num_options;
cups_option_t *options;
int job_id;
int i;
char buffer[1024];

/* Create the job */
job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, dest->name, "10 Text Files",
                       num_options, options);

/* If the job is created, add 10 files */
if (job_id > 0)
{
  for (i = 1; i <= 10; i ++)
  {
    snprintf(buffer, sizeof(buffer), "file%d.txt", i);

    cupsStartDocument(CUPS_HTTP_DEFAULT, dest->name, job_id, buffer,
                      CUPS_FORMAT_TEXT, i == 10);

    snprintf(buffer, sizeof(buffer),
             "File %d\n"
             "\n"
             "One fish,\n"
             "Two fish,\n
             "Red fish,\n
             "Blue fish\n", i);

    /* cupsWriteRequestData can be called as many times as needed */
    cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, strlen(buffer));

    cupsFinishDocument(CUPS_HTTP_DEFAULT, dest->name);
  }
}

Once you have created a job, you can monitor its status using the cupsGetJobs function, which returns an array of cups_job_t structures. Each contains the job ID (id), destination name (dest), title (title), and other information associated with the job. The job array is freed using the cupsFreeJobs function. The following example monitors a specific job ID, showing the current job state once every 5 seconds until the job is completed:

#include <cups/cups.h>

cups_dest_t *dest;
int job_id;
int num_jobs;
cups_job_t *jobs;
int i;
ipp_jstate_t job_state = IPP_JOB_PENDING;

while (job_state < IPP_JOB_STOPPED)
{
  /* Get my jobs (1) with any state (-1) */
  num_jobs = cupsGetJobs(&jobs, dest->name, 1, -1);

  /* Loop to find my job */
  job_state = IPP_JOB_COMPLETED;

  for (i = 0; i < num_jobs; i ++)
    if (jobs[i].id == job_id)
    {
      job_state = jobs[i].state;
      break;
    }

  /* Free the job array */
  cupsFreeJobs(num_jobs, jobs);

  /* Show the current state */
  switch (job_state)
  {
    case IPP_JOB_PENDING :
        printf("Job %d is pending.\n", job_id);
        break;
    case IPP_JOB_HELD :
        printf("Job %d is held.\n", job_id);
        break;
    case IPP_JOB_PROCESSING :
        printf("Job %d is processing.\n", job_id);
        break;
    case IPP_JOB_STOPPED :
        printf("Job %d is stopped.\n", job_id);
        break;
    case IPP_JOB_CANCELED :
        printf("Job %d is canceled.\n", job_id);
        break;
    case IPP_JOB_ABORTED :
        printf("Job %d is aborted.\n", job_id);
        break;
    case IPP_JOB_COMPLETED :
        printf("Job %d is completed.\n", job_id);
        break;
  }

  /* Sleep if the job is not finished */
  if (job_state < IPP_JOB_STOPPED)
    sleep(5);
}

To cancel a job, use the cupsCancelJob function with the job ID:

#include <cups/cups.h>

cups_dest_t *dest;
int job_id;

cupsCancelJob(dest->name, job_id);

Error Handling

If any of the CUPS API printing functions returns an error, the reason for that error can be found by calling the cupsLastError and cupsLastErrorString functions. cupsLastError returns the last IPP error code (ipp_status_t) that was encountered, while cupsLastErrorString returns a (localized) human-readable string that can be shown to the user. For example, if any of the job creation functions returns a job ID of 0, you can use cupsLastErrorString to show the reason why the job could not be created:

#include <cups/cups.h>

int job_id;

if (job_id == 0)
  puts(cupsLastErrorString());

Passwords and Authentication

CUPS supports authentication of any request, including submission of print jobs. The default mechanism for getting the username and password is to use the login user and a password from the console.

To support other types of applications, in particular Graphical User Interfaces ("GUIs"), the CUPS API provides functions to set the default username and to register a callback function that returns a password string.

The cupsSetPasswordCB function is used to set a password callback in your program. Only one function can be used at any time.

The cupsSetUser function sets the current username for authentication. This function can be called by your password callback function to change the current username as needed.

The following example shows a simple password callback that gets a username and password from the user:

#include <cups/cups.h>

const char *
my_password_cb(const char *prompt)
{
  char	user[65];


  puts(prompt);

  /* Get a username from the user */
  printf("Username: ");
  if (fgets(user, sizeof(user), stdin) == NULL)
    return (NULL);

  /* Strip the newline from the string and set the user */
  user[strlen(user) - 1] = '\0';

  cupsSetUser(user);

  /* Use getpass() to ask for the password... */
  return (getpass("Password: "));
}

cupsSetPasswordCB(my_password_cb);

Similarly, a GUI could display the prompt string in a window with input fields for the username and password. The username should default to the string returned by the cupsUser function.

HTTP and IPP APIs

The CUPS HTTP and IPP APIs provide low-level access to the HTTP and IPP protocols and CUPS scheduler. They are typically used by monitoring and administration programs to perform specific functions not supported by the high-level CUPS API functions.

The HTTP APIs use an opaque structure called http_t to manage connections to a particular HTTP or IPP server. The httpConnectEncrypt function is used to create an instance of this structure for a particular server. The constant CUPS_HTTP_DEFAULT can be used with all of the cups functions to refer to the default CUPS server - the functions create a per-thread http_t as needed.

The IPP APIs use two opaque structures for requests (messages sent to the CUPS scheduler) and responses (messages sent back to your application from the scheduler). The ipp_t type holds a complete request or response and is allocated using the ippNew or ippNewRequest functions and freed using the ippDelete function.

The second opaque structure is called ipp_attribute_t and holds a single IPP attribute which consists of a group tag (ippGetGroupTag), a value type tag (ippGetValueTag), the attribute name (ippGetName), and 1 or more values (ippGetCount, ippGetBoolean, ippGetCollection, ippGetDate, ippGetInteger, ippGetRange, ippGetResolution, and ippGetString). Attributes are added to an ipp_t pointer using one of the ippAdd functions. For example, use ippAddString to add the "printer-uri" and "requesting-user-name" string attributes to a request:

ipp_t *request = ippNewRequest(IPP_GET_JOBS);

ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
             NULL, "ipp://localhost/printers/");
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
             NULL, cupsUser());

Once you have created an IPP request, use the cups functions to send the request to and read the response from the server. For example, the cupsDoRequest function can be used for simple query operations that do not involve files:

#include <cups/cups.h>


ipp_t *get_jobs(void)
{
  ipp_t *request = ippNewRequest(IPP_GET_JOBS);

  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
               NULL, "ipp://localhost/printers/");
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
               NULL, cupsUser());

  return (cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/"));
}

The cupsDoRequest function frees the request and returns an IPP response or NULL pointer if the request could not be sent to the server. Once you have a response from the server, you can either use the ippFindAttribute and ippFindNextAttribute functions to find specific attributes, for example:

ipp_t *response;
ipp_attribute_t *attr;

attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM);

You can also walk the list of attributes with a simple for loop like this:

ipp_t *response;
ipp_attribute_t *attr;

for (attr = ippFirstAttribute(response); attr != NULL; attr = ippNextAttribute(response))
  if (ippGetName(attr) == NULL)
    puts("--SEPARATOR--");
  else
    puts(ippGetName(attr));

The for loop approach is normally used when collecting attributes for multiple objects (jobs, printers, etc.) in a response. Attributes with NULL names indicate a separator between the attributes of each object. For example, the following code will list the jobs returned from our previous get_jobs example code:

ipp_t *response = get_jobs();

if (response != NULL)
{
  ipp_attribute_t *attr;
  const char *attrname;
  int job_id = 0;
  const char *job_name = NULL;
  const char *job_originating_user_name = NULL;

  puts("Job ID  Owner             Title");
  puts("------  ----------------  ---------------------------------");

  for (attr = ippFirstAttribute(response); attr != NULL; attr = ippNextAttribute(response))
  {
   /* Attributes without names are separators between jobs */
    attrname = ippGetName(attr);
    if (attrname == NULL)
    {
      if (job_id > 0)
      {
        if (job_name == NULL)
          job_name = "(withheld)";

        if (job_originating_user_name == NULL)
          job_originating_user_name = "(withheld)";

        printf("%5d  %-16s  %s\n", job_id, job_originating_user_name, job_name);
      }

      job_id = 0;
      job_name = NULL;
      job_originating_user_name = NULL;
      continue;
    }
    else if (!strcmp(attrname, "job-id") && ippGetValueTag(attr) == IPP_TAG_INTEGER)
      job_id = ippGetInteger(attr, 0);
    else if (!strcmp(attrname, "job-name") && ippGetValueTag(attr) == IPP_TAG_NAME)
      job_name = ippGetString(attr, 0, NULL);
    else if (!strcmp(attrname, "job-originating-user-name") &&
             ippGetValueTag(attr) == IPP_TAG_NAME)
      job_originating_user_name = ippGetString(attr, 0, NULL);
  }

  if (job_id > 0)
  {
    if (job_name == NULL)
      job_name = "(withheld)";

    if (job_originating_user_name == NULL)
      job_originating_user_name = "(withheld)";

    printf("%5d  %-16s  %s\n", job_id, job_originating_user_name, job_name);
  }
}

Creating URI Strings

To ensure proper encoding, the httpAssembleURIf function must be used to format a "printer-uri" string for all printer-based requests:

const char *name = "Foo";
char uri[1024];
ipp_t *request;

httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, cupsServer(),
                 ippPort(), "/printers/%s", name);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);

Sending Requests with Files

The cupsDoFileRequest and cupsDoIORequest functions are used for requests involving files. The cupsDoFileRequest function attaches the named file to a request and is typically used when sending a print file or changing a printer's PPD file:

const char *filename = "/usr/share/cups/data/testprint.ps";
const char *name = "Foo";
char uri[1024];
char resource[1024];
ipp_t *request = ippNewRequest(IPP_PRINT_JOB);
ipp_t *response;

/* Use httpAssembleURIf for the printer-uri string */
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, cupsServer(),
                 ippPort(), "/printers/%s", name);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
             NULL, cupsUser());
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
             NULL, "testprint.ps");

/* Use snprintf for the resource path */
snprintf(resource, sizeof(resource), "/printers/%s", name);

response = cupsDoFileRequest(CUPS_HTTP_DEFAULT, request, resource, filename);

The cupsDoIORequest function optionally attaches a file to the request and optionally saves a file in the response from the server. It is used when using a pipe for the request attachment or when using a request that returns a file, currently only CUPS_GET_DOCUMENT and CUPS_GET_PPD. For example, the following code will download the PPD file for the sample HP LaserJet printer driver:

char tempfile[1024];
int tempfd;
ipp_t *request = ippNewRequest(CUPS_GET_PPD);
ipp_t *response;

ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name",
             NULL, "laserjet.ppd");

tempfd = cupsTempFd(tempfile, sizeof(tempfile));

response = cupsDoIORequest(CUPS_HTTP_DEFAULT, request, "/", -1, tempfd);

The example passes -1 for the input file descriptor to specify that no file is to be attached to the request. The PPD file attached to the response is written to the temporary file descriptor we created using the cupsTempFd function.

Asynchronous Request Processing

The cupsSendRequest and cupsGetResponse support asynchronous communications with the server. Unlike the other request functions, the IPP request is not automatically freed, so remember to free your request with the ippDelete function.

File data is attached to the request using the cupsWriteRequestData function, while file data returned from the server is read using the cupsReadResponseData function. We can rewrite the previous CUPS_GET_PPD example to use the asynchronous functions quite easily:

char tempfile[1024];
int tempfd;
ipp_t *request = ippNewRequest(CUPS_GET_PPD);
ipp_t *response;

ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name",
             NULL, "laserjet.ppd");

tempfd = cupsTempFd(tempfile, sizeof(tempfile));

if (cupsSendRequest(CUPS_HTTP_DEFAULT, request, "/") == HTTP_CONTINUE)
{
  response = cupsGetResponse(CUPS_HTTP_DEFAULT, "/");

  if (response != NULL)
  {
    ssize_t bytes;
    char buffer[8192];

    while ((bytes = cupsReadResponseData(CUPS_HTTP_DEFAULT, buffer, sizeof(buffer))) > 0)
      write(tempfd, buffer, bytes);
  }
}

/* Free the request! */
ippDelete(request);

The cupsSendRequest function returns the initial HTTP request status, typically either HTTP_CONTINUE or HTTP_UNAUTHORIZED. The latter status is returned when the request requires authentication of some sort. The cupsDoAuthentication function must be called when your see HTTP_UNAUTHORIZED and the request re-sent. We can add authentication support to our example code by using a do ... while loop:

char tempfile[1024];
int tempfd;
ipp_t *request = ippNewRequest(CUPS_GET_PPD);
ipp_t *response;
http_status_t status;

ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name",
             NULL, "laserjet.ppd");

tempfd = cupsTempFd(tempfile, sizeof(tempfile));

/* Loop for authentication */
do
{
  status = cupsSendRequest(CUPS_HTTP_DEFAULT, request, "/");

  if (status == HTTP_UNAUTHORIZED)
  {
    /* Try to authenticate, break out of the loop if that fails */
    if (cupsDoAuthentication(CUPS_HTTP_DEFAULT, "POST", "/"))
      break;
  }
}
while (status != HTTP_CONTINUE && status != HTTP_UNAUTHORIZED);

if (status == HTTP_CONTINUE)
{
  response = cupsGetResponse(CUPS_HTTP_DEFAULT, "/");

  if (response != NULL)
  {
    ssize_t bytes;
    char buffer[8192];

    while ((bytes = cupsReadResponseData(CUPS_HTTP_DEFAULT, buffer, sizeof(buffer))) > 0)
      write(tempfd, buffer, bytes);
  }
}

/* Free the request! */
ippDelete(request);

Raster API

The CUPS raster API provides a standard interface for reading and writing CUPS raster streams which are used for printing to raster printers. Because the raster format is updated from time to time, it is important to use this API to avoid incompatibilities with newer versions of CUPS.

Two kinds of CUPS filters use the CUPS raster API - raster image processor (RIP) filters such as pstoraster and cgpdftoraster (macOS) that produce CUPS raster files and printer driver filters that convert CUPS raster files into a format usable by the printer. Printer driver filters are by far the most common.

CUPS raster files (application/vnd.cups-raster) consists of a stream of raster page descriptions produced by one of the RIP filters such as pstoraster, imagetoraster, or cgpdftoraster. CUPS raster files are referred to using the cups_raster_t type and are opened using the cupsRasterOpen function. For example, to read raster data from the standard input, open file descriptor 0:

#include <cups/raster.h>>

cups_raster_t *ras = cupsRasterOpen(0, CUPS_RASTER_READ);

Each page of data begins with a page dictionary structure called cups_page_header2_t. This structure contains the colorspace, bits per color, media size, media type, hardware resolution, and so forth used for the page.

You read the page header using the cupsRasterReadHeader2 function:

#include <cups/raster.h>>

cups_raster_t *ras = cupsRasterOpen(0, CUPS_RASTER_READ);
cups_page_header2_t header;

while (cupsRasterReadHeader2(ras, &header))
{
  /* setup this page */

  /* read raster data */

  /* finish this page */
}

After the page dictionary comes the page data which is a full-resolution, possibly compressed bitmap representing the page in the printer's output colorspace. You read uncompressed raster data using the cupsRasterReadPixels function. A for loop is normally used to read the page one line at a time:

#include <cups/raster.h>>

cups_raster_t *ras = cupsRasterOpen(0, CUPS_RASTER_READ);
cups_page_header2_t header;
int page = 0;
int y;
char *buffer;

while (cupsRasterReadHeader2(ras, &header))
{
  /* setup this page */
  page ++;
  fprintf(stderr, "PAGE: %d %d\n", page, header.NumCopies);

  /* allocate memory for 1 line */
  buffer = malloc(header.cupsBytesPerLine);

  /* read raster data */
  for (y = 0; y < header.cupsHeight; y ++)
  {
    if (cupsRasterReadPixels(ras, buffer, header.cupsBytesPerLine) == 0)
      break;

    /* write raster data to printer on stdout */
  }

  /* finish this page */
}

When you are done reading the raster data, call the cupsRasterClose function to free the memory used to read the raster file:

cups_raster_t *ras;

cupsRasterClose(ras);

Functions

cupsAddDest

Add a destination to the list of destinations.

int cupsAddDest (
    const char *name,
    const char *instance,
    int num_dests,
    cups_dest_t **dests
);

Parameters

name
Destination name
instance
Instance name or NULL for none/primary
num_dests
Number of destinations
dests
Destinations

Return Value

New number of destinations

Discussion

This function cannot be used to add a new class or printer queue, it only adds a new container of saved options for the named destination or instance.

If the named destination already exists, the destination list is returned unchanged. Adding a new instance of a destination creates a copy of that destination's options.

Use the cupsSaveDests function to save the updated list of destinations to the user's lpoptions file.

cupsAddOption

Add an option to an option array.

int cupsAddOption (
    const char *name,
    const char *value,
    int num_options,
    cups_option_t **options
);

Parameters

name
Name of option
value
Value of option
num_options
Number of options
options
Pointer to options

Return Value

Number of options

Discussion

New option arrays can be initialized simply by passing 0 for the "num_options" parameter.

cupsCancelDestJob

Include necessary headers...

ipp_status_t cupsCancelDestJob (
    http_t *http,
    cups_dest_t *dest,
    int job_id
);

Parameters

http
Connection to destination
dest
Destination
job_id
Job ID

Return Value

Cancel a job on a destination.

The "job_id" is the number returned by cupsCreateDestJob.

Returns IPP_STATUS_OK on success and IPP_STATUS_ERRPR_NOT_AUTHORIZED or IPP_STATUS_ERROR_FORBIDDEN on failure.

cupsCancelJob

Cancel a print job on the default server.

int cupsCancelJob (
    const char *name,
    int job_id
);

Parameters

name
Name of printer or class
job_id
Job ID, CUPS_JOBID_CURRENT for the current job, or CUPS_JOBID_ALL for all jobs

Return Value

1 on success, 0 on failure

Discussion

Pass CUPS_JOBID_ALL to cancel all jobs or CUPS_JOBID_CURRENT to cancel the current job on the named destination.

Use the cupsLastError and cupsLastErrorString functions to get the cause of any failure.

 CUPS 1.4/macOS 10.6 cupsCancelJob2

Cancel or purge a print job.

ipp_status_t cupsCancelJob2 (
    http_t *http,
    const char *name,
    int job_id,
    int purge
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
name
Name of printer or class
job_id
Job ID, CUPS_JOBID_CURRENT for the current job, or CUPS_JOBID_ALL for all jobs
purge
1 to purge, 0 to cancel

Return Value

IPP status

Discussion

Canceled jobs remain in the job history while purged jobs are removed from the job history.

Pass CUPS_JOBID_ALL to cancel all jobs or CUPS_JOBID_CURRENT to cancel the current job on the named destination.

Use the cupsLastError and cupsLastErrorString functions to get the cause of any failure.

 CUPS 1.6/macOS 10.8 cupsCheckDestSupported

Check that the option and value are supported by the destination.

int cupsCheckDestSupported (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *dinfo,
    const char *option,
    const char *value
);

Parameters

http
Connection to destination
dest
Destination
dinfo
Destination information
option
Option
value
Value

Return Value

1 if supported, 0 otherwise

Discussion

Returns 1 if supported, 0 otherwise.

 CUPS 1.6/macOS 10.8 cupsCloseDestJob

Close a job and start printing.

ipp_status_t cupsCloseDestJob (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *info,
    int job_id
);

Parameters

http
Connection to destination
dest
Destination
info
Destination information
job_id
Job ID

Return Value

IPP status code

Discussion

Use when the last call to cupsStartDocument passed 0 for "last_document". "job_id" is the job ID returned by cupsCreateDestJob. Returns IPP_STATUS_OK on success.

 CUPS 1.6/macOS 10.8 cupsConnectDest

Connect to the server for a destination.

http_t *cupsConnectDest (
    cups_dest_t *dest,
    unsigned flags,
    int msec,
    int *cancel,
    char *resource,
    size_t resourcesize,
    cups_dest_cb_t cb,
    void *user_data
);

Parameters

dest
Destination
flags
Connection flags
msec
Timeout in milliseconds
cancel
Pointer to "cancel" variable
resource
Resource buffer
resourcesize
Size of resource buffer
cb
Callback function
user_data
User data pointer

Return Value

Connection to server or NULL

Discussion

Connect to the destination, returning a new http_t connection object and optionally the resource path to use for the destination. These calls will block until a connection is made, the timeout expires, the integer pointed to by "cancel" is non-zero, or the callback function (or block) returns 0, The caller is responsible for calling httpClose() on the returned object.

 CUPS 1.6/macOS 10.8 cupsConnectDestBlock

Connect to the server for a destination.

http_t *cupsConnectDestBlock (
    cups_dest_t *dest,
    unsigned flags,
    int msec,
    int *cancel,
    char *resource,
    size_t resourcesize,
    cups_dest_block_t block
);

Parameters

dest
Destination
flags
Connection flags
msec
Timeout in milliseconds
cancel
Pointer to "cancel" variable
resource
Resource buffer
resourcesize
Size of resource buffer
block
Callback block

Return Value

Connection to server or NULL

Discussion

Connect to the destination, returning a new http_t connection object and optionally the resource path to use for the destination. These calls will block until a connection is made, the timeout expires, the integer pointed to by "cancel" is non-zero, or the callback function (or block) returns 0, The caller is responsible for calling httpClose() on the returned object.

cupsCopyDest

Callback block

int cupsCopyDest (
    cups_dest_t *dest,
    int num_dests,
    cups_dest_t **dests
);

Parameters

dest
num_dests
dests

Return Value

Copy a destination.

Make a copy of the destination to an array of destinations (or just a single copy) - for use with the cupsEnumDests* functions. The caller is responsible for calling cupsFreeDests() on the returned object(s).

 CUPS 1.6/macOS 10.8 cupsCopyDestConflicts

Get conflicts and resolutions for a new option/value pair.

int cupsCopyDestConflicts (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *dinfo,
    int num_options,
    cups_option_t *options,
    const char *new_option,
    const char *new_value,
    int *num_conflicts,
    cups_option_t **conflicts,
    int *num_resolved,
    cups_option_t **resolved
);

Parameters

http
Connection to destination
dest
Destination
dinfo
Destination information
num_options
Number of current options
options
Current options
new_option
New option
new_value
New value
num_conflicts
Number of conflicting options
conflicts
Conflicting options
num_resolved
Number of options to resolve
resolved
Resolved options

Return Value

1 if there is a conflict, 0 if none, -1 on error

Discussion

"num_options" and "options" represent the currently selected options by the user. "new_option" and "new_value" are the setting the user has just changed.

Returns 1 if there is a conflict, 0 if there are no conflicts, and -1 if there was an unrecoverable error such as a resolver loop.

If "num_conflicts" and "conflicts" are not NULL, they are set to contain the list of conflicting option/value pairs. Similarly, if "num_resolved" and "resolved" are not NULL they will be set to the list of changes needed to resolve the conflict.

If cupsCopyDestConflicts returns 1 but "num_resolved" and "resolved" are set to 0 and NULL, respectively, then the conflict cannot be resolved.

 CUPS 1.6/macOS 10.8 cupsCopyDestInfo

Get the supported values/capabilities for the destination.

cups_dinfo_t *cupsCopyDestInfo (
    http_t *http,
    cups_dest_t *dest
);

Parameters

http
Connection to destination
dest
Destination

Return Value

Destination information

Discussion

The caller is responsible for calling cupsFreeDestInfo on the return value. NULL is returned on error.

 CUPS 1.6/macOS 10.8 cupsCreateDestJob

Create a job on a destination.

ipp_status_t cupsCreateDestJob (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *info,
    int *job_id,
    const char *title,
    int num_options,
    cups_option_t *options
);

Parameters

http
Connection to destination
dest
Destination
info
Destination information
job_id
Job ID or 0 on error
title
Job name
num_options
Number of job options
options
Job options

Return Value

IPP status code

Discussion

Returns IPP_STATUS_OK or IPP_STATUS_OK_SUBST on success, saving the job ID in the variable pointed to by "job_id".

 CUPS 1.4/macOS 10.6 cupsCreateJob

Create an empty job for streaming.

int cupsCreateJob (
    http_t *http,
    const char *name,
    const char *title,
    int num_options,
    cups_option_t *options
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
name
Destination name
title
Title of job
num_options
Number of options
options
Options

Return Value

Job ID or 0 on error

Discussion

Use this function when you want to stream print data using the cupsStartDocument, cupsWriteRequestData, and cupsFinishDocument functions. If you have one or more files to print, use the cupsPrintFile2 or cupsPrintFiles2 function instead.

 CUPS 1.1.20/macOS 10.4 cupsDoAuthentication

Authenticate a request.

int cupsDoAuthentication (
    http_t *http,
    const char *method,
    const char *resource
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
method
Request method ("GET", "POST", "PUT")
resource
Resource path

Return Value

0 on success, -1 on error

Discussion

This function should be called in response to a HTTP_STATUS_UNAUTHORIZED status, prior to resubmitting your request.

cupsDoFileRequest

Do an IPP request with a file.

ipp_t *cupsDoFileRequest (
    http_t *http,
    ipp_t *request,
    const char *resource,
    const char *filename
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
request
IPP request
resource
HTTP resource for POST
filename
File to send or NULL for none

Return Value

Response data

Discussion

This function sends the IPP request and attached file to the specified server, retrying and authenticating as necessary. The request is freed with ippDelete.

 CUPS 1.3/macOS 10.5 cupsDoIORequest

Do an IPP request with file descriptors.

ipp_t *cupsDoIORequest (
    http_t *http,
    ipp_t *request,
    const char *resource,
    int infile,
    int outfile
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
request
IPP request
resource
HTTP resource for POST
infile
File to read from or -1 for none
outfile
File to write to or -1 for none

Return Value

Response data

Discussion

This function sends the IPP request with the optional input file "infile" to the specified server, retrying and authenticating as necessary. The request is freed with ippDelete.

If "infile" is a valid file descriptor, cupsDoIORequest copies all of the data from the file after the IPP request message.

If "outfile" is a valid file descriptor, cupsDoIORequest copies all of the data after the IPP response message to the file.

cupsDoRequest

Do an IPP request.

ipp_t *cupsDoRequest (
    http_t *http,
    ipp_t *request,
    const char *resource
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
request
IPP request
resource
HTTP resource for POST

Return Value

Response data

Discussion

This function sends the IPP request to the specified server, retrying and authenticating as necessary. The request is freed with ippDelete.

cupsEncodeOptions

Encode printer options into IPP attributes.

void cupsEncodeOptions (
    ipp_t *ipp,
    int num_options,
    cups_option_t *options
);

Parameters

ipp
Request to add to
num_options
Number of options
options
Options

Discussion

This function adds operation, job, and then subscription attributes, in that order. Use the cupsEncodeOptions2() function to add attributes for a single group.

 CUPS 1.2/macOS 10.5 cupsEncodeOptions2

Encode printer options into IPP attributes for a group.

void cupsEncodeOptions2 (
    ipp_t *ipp,
    int num_options,
    cups_option_t *options,
    ipp_tag_t group_tag
);

Parameters

ipp
Request to add to
num_options
Number of options
options
Options
group_tag
Group to encode

Discussion

This function only adds attributes for a single group. Call this function multiple times for each group, or use cupsEncodeOptions() to add the standard groups.

cupsEncryption

Get the current encryption settings.

http_encryption_t cupsEncryption (void);

Return Value

Encryption settings

Discussion

The default encryption setting comes from the CUPS_ENCRYPTION environment variable, then the ~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not set, the default is HTTP_ENCRYPTION_IF_REQUESTED.

Note: The current encryption setting is tracked separately for each thread in a program. Multi-threaded programs that override the setting via the cupsSetEncryption function need to do so in each thread for the same setting to be used.

 CUPS 1.6/macOS 10.8 cupsEnumDests

Enumerate available destinations with a callback function.

int cupsEnumDests (
    unsigned flags,
    int msec,
    int *cancel,
    cups_ptype_t type,
    cups_ptype_t mask,
    cups_dest_cb_t cb,
    void *user_data
);

Parameters

flags
Enumeration flags
msec
Timeout in milliseconds, -1 for indefinite
cancel
Pointer to "cancel" variable
type
Printer type bits
mask
Mask for printer type bits
cb
Callback function
user_data
User data

Return Value

1 on success, 0 on failure

Discussion

Destinations are enumerated from one or more sources. The callback function receives the user_data pointer, destination name, instance, number of options, and options which can be used as input to the cupsAddDest function. The function must return 1 to continue enumeration or 0 to stop.

Enumeration happens on the current thread and does not return until all destinations have been enumerated or the callback function returns 0.

 CUPS 1.6/macOS 10.8 cupsEnumDestsBlock

Enumerate available destinations with a block.

int cupsEnumDestsBlock (
    unsigned flags,
    int timeout,
    int *cancel,
    cups_ptype_t type,
    cups_ptype_t mask,
    cups_dest_block_t block
);

Parameters

flags
Enumeration flags
timeout
Timeout in milliseconds, 0 for indefinite
cancel
Pointer to "cancel" variable
type
Printer type bits
mask
Mask for printer type bits
block
Block

Return Value

1 on success, 0 on failure

Discussion

Destinations are enumerated from one or more sources. The block receives the destination name, instance, number of options, and options which can be used as input to the cupsAddDest function. The block must return 1 to continue enumeration or 0 to stop.

Enumeration happens on the current thread and does not return until all destinations have been enumerated or the block returns 0.

 CUPS 1.7/macOS 10.9 cupsFindDestDefault

Find the default value(s) for the given option.

ipp_attribute_t *cupsFindDestDefault (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *dinfo,
    const char *option
);

Parameters

http
Connection to destination
dest
Destination
dinfo
Destination information
option
Option/attribute name

Return Value

Default attribute or NULL for none

Discussion

The returned value is an IPP attribute. Use the ippGetBoolean, ippGetCollection, ippGetCount, ippGetDate, ippGetInteger, ippGetOctetString, ippGetRange, ippGetResolution, ippGetString, and ippGetValueTag functions to inspect the default value(s) as needed.

 CUPS 1.7/macOS 10.9 cupsFindDestReady

Find the default value(s) for the given option.

ipp_attribute_t *cupsFindDestReady (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *dinfo,
    const char *option
);

Parameters

http
Connection to destination
dest
Destination
dinfo
Destination information
option
Option/attribute name

Return Value

Default attribute or NULL for none

Discussion

The returned value is an IPP attribute. Use the ippGetBoolean, ippGetCollection, ippGetCount, ippGetDate, ippGetInteger, ippGetOctetString, ippGetRange, ippGetResolution, ippGetString, and ippGetValueTag functions to inspect the default value(s) as needed.

 CUPS 1.7/macOS 10.9 cupsFindDestSupported

Find the default value(s) for the given option.

ipp_attribute_t *cupsFindDestSupported (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *dinfo,
    const char *option
);

Parameters

http
Connection to destination
dest
Destination
dinfo
Destination information
option
Option/attribute name

Return Value

Default attribute or NULL for none

Discussion

The returned value is an IPP attribute. Use the ippGetBoolean, ippGetCollection, ippGetCount, ippGetDate, ippGetInteger, ippGetOctetString, ippGetRange, ippGetResolution, ippGetString, and ippGetValueTag functions to inspect the default value(s) as needed.

 CUPS 1.6/macOS 10.8 cupsFinishDestDocument

Finish the current document.

ipp_status_t cupsFinishDestDocument (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *info
);

Parameters

http
Connection to destination
dest
Destination
info
Destination information

Return Value

Status of document submission

Discussion

Returns IPP_STATUS_OK or IPP_STATUS_OK_SUBST on success.

 CUPS 1.4/macOS 10.6 cupsFinishDocument

Finish sending a document.

ipp_status_t cupsFinishDocument (
    http_t *http,
    const char *name
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
name
Destination name

Return Value

Status of document submission

Discussion

The document must have been started using cupsStartDocument.

cupsFreeDestInfo

Free destination information obtained using cupsCopyDestInfo.

void cupsFreeDestInfo (
    cups_dinfo_t *dinfo
);

Parameters

dinfo
Destination information

cupsFreeDests

Free the memory used by the list of destinations.

void cupsFreeDests (
    int num_dests,
    cups_dest_t *dests
);

Parameters

num_dests
Number of destinations
dests
Destinations

cupsFreeJobs

Free memory used by job data.

void cupsFreeJobs (
    int num_jobs,
    cups_job_t *jobs
);

Parameters

num_jobs
Number of jobs
jobs
Jobs

cupsFreeOptions

Free all memory used by options.

void cupsFreeOptions (
    int num_options,
    cups_option_t *options
);

Parameters

num_options
Number of options
options
Pointer to options

 DEPRECATED cupsGetClasses

Get a list of printer classes from the default server.

int cupsGetClasses (
    char ***classes
);

Parameters

classes
Classes

Return Value

Number of classes

Discussion

This function is deprecated and no longer returns a list of printer classes - use cupsGetDests instead.

cupsGetDefault

Get the default printer or class for the default server.

const char *cupsGetDefault (void);

Return Value

Default printer or NULL

Discussion

This function returns the default printer or class as defined by the LPDEST or PRINTER environment variables. If these environment variables are not set, the server default destination is returned. Applications should use the cupsGetDests and cupsGetDest functions to get the user-defined default printer, as this function does not support the lpoptions-defined default printer.

 CUPS 1.1.21/macOS 10.4 cupsGetDefault2

Get the default printer or class for the specified server.

const char *cupsGetDefault2 (
    http_t *http
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT

Return Value

Default printer or NULL

Discussion

This function returns the default printer or class as defined by the LPDEST or PRINTER environment variables. If these environment variables are not set, the server default destination is returned. Applications should use the cupsGetDests and cupsGetDest functions to get the user-defined default printer, as this function does not support the lpoptions-defined default printer.

cupsGetDest

Get the named destination from the list.

cups_dest_t *cupsGetDest (
    const char *name,
    const char *instance,
    int num_dests,
    cups_dest_t *dests
);

Parameters

name
Destination name or NULL for the default destination
instance
Instance name or NULL
num_dests
Number of destinations
dests
Destinations

Return Value

Destination pointer or NULL

Discussion

Use the cupsGetDests or cupsGetDests2 functions to get a list of supported destinations for the current user.

 CUPS 1.7/macOS 10.9 cupsGetDestMediaByIndex

Get a media name, dimension, and margins for a specific size.

int cupsGetDestMediaByIndex (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *dinfo,
    int n,
    unsigned flags,
    cups_size_t *size
);

Parameters

http
Connection to destination
dest
Destination
dinfo
Destination information
n
Media size number (0-based)
flags
Media flags
size
Media size information

Return Value

1 on success, 0 on failure

Discussion

The flags parameter determines which set of media are indexed. For example, passing CUPS_MEDIA_FLAGS_BORDERLESS will get the Nth borderless size supported by the printer.

 CUPS 1.6/macOS 10.8 cupsGetDestMediaByName

Get media names, dimensions, and margins.

int cupsGetDestMediaByName (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *dinfo,
    const char *media,
    unsigned flags,
    cups_size_t *size
);

Parameters

http
Connection to destination
dest
Destination
dinfo
Destination information
media
Media name
flags
Media matching flags
size
Media size information

Return Value

1 on match, 0 on failure

Discussion

The "media" string is a PWG media name. "Flags" provides some matching guidance (multiple flags can be combined):

CUPS_MEDIA_FLAGS_DEFAULT = find the closest size supported by the printer, CUPS_MEDIA_FLAGS_BORDERLESS = find a borderless size, CUPS_MEDIA_FLAGS_DUPLEX = find a size compatible with 2-sided printing, CUPS_MEDIA_FLAGS_EXACT = find an exact match for the size, and CUPS_MEDIA_FLAGS_READY = if the printer supports media sensing, find the size amongst the "ready" media.

The matching result (if any) is returned in the "cups_size_t" structure.

Returns 1 when there is a match and 0 if there is not a match.

 CUPS 1.6/macOS 10.8 cupsGetDestMediaBySize

Get media names, dimensions, and margins.

int cupsGetDestMediaBySize (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *dinfo,
    int width,
    int length,
    unsigned flags,
    cups_size_t *size
);

Parameters

http
Connection to destination
dest
Destination
dinfo
Destination information
width
Media width in hundredths of of millimeters
length
Media length in hundredths of of millimeters
flags
Media matching flags
size
Media size information

Return Value

1 on match, 0 on failure

Discussion

"Width" and "length" are the dimensions in hundredths of millimeters. "Flags" provides some matching guidance (multiple flags can be combined):

CUPS_MEDIA_FLAGS_DEFAULT = find the closest size supported by the printer, CUPS_MEDIA_FLAGS_BORDERLESS = find a borderless size, CUPS_MEDIA_FLAGS_DUPLEX = find a size compatible with 2-sided printing, CUPS_MEDIA_FLAGS_EXACT = find an exact match for the size, and CUPS_MEDIA_FLAGS_READY = if the printer supports media sensing, find the size amongst the "ready" media.

The matching result (if any) is returned in the "cups_size_t" structure.

Returns 1 when there is a match and 0 if there is not a match.

 CUPS 1.7/macOS 10.9 cupsGetDestMediaCount

Get the number of sizes supported by a destination.

int cupsGetDestMediaCount (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *dinfo,
    unsigned flags
);

Parameters

http
Connection to destination
dest
Destination
dinfo
Destination information
flags
Media flags

Return Value

Number of sizes

Discussion

The flags parameter determines the set of media sizes that are counted. For example, passing CUPS_MEDIA_FLAGS_BORDERLESS will return the number of borderless sizes.

 CUPS 1.7/macOS 10.9 cupsGetDestMediaDefault

Get the default size for a destination.

int cupsGetDestMediaDefault (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *dinfo,
    unsigned flags,
    cups_size_t *size
);

Parameters

http
Connection to destination
dest
Destination
dinfo
Destination information
flags
Media flags
size
Media size information

Return Value

1 on success, 0 on failure

Discussion

The flags parameter determines which default size is returned. For example, passing CUPS_MEDIA_FLAGS_BORDERLESS will return the default borderless size, typically US Letter or A4, but sometimes 4x6 photo media.

 CUPS 2.0/macOS 10.10 cupsGetDestWithURI

Get a destination associated with a URI.

cups_dest_t *cupsGetDestWithURI (
    const char *name,
    const char *uri
);

Parameters

name
Desired printer name or NULL
uri
URI for the printer

Return Value

Destination or NULL

Discussion

"name" is the desired name for the printer. If NULL, a name will be created using the URI.

"uri" is the "ipp" or "ipps" URI for the printer.

cupsGetDests

Get the list of destinations from the default server.

int cupsGetDests (
    cups_dest_t **dests
);

Parameters

dests
Destinations

Return Value

Number of destinations

Discussion

Starting with CUPS 1.2, the returned list of destinations include the printer-info, printer-is-accepting-jobs, printer-is-shared, printer-make-and-model, printer-state, printer-state-change-time, printer-state-reasons, and printer-type attributes as options. CUPS 1.4 adds the marker-change-time, marker-colors, marker-high-levels, marker-levels, marker-low-levels, marker-message, marker-names, marker-types, and printer-commands attributes as well.

Use the cupsFreeDests function to free the destination list and the cupsGetDest function to find a particular destination.

 CUPS 1.1.21/macOS 10.4 cupsGetDests2

Get the list of destinations from the specified server.

int cupsGetDests2 (
    http_t *http,
    cups_dest_t **dests
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
dests
Destinations

Return Value

Number of destinations

Discussion

Starting with CUPS 1.2, the returned list of destinations include the printer-info, printer-is-accepting-jobs, printer-is-shared, printer-make-and-model, printer-state, printer-state-change-time, printer-state-reasons, and printer-type attributes as options. CUPS 1.4 adds the marker-change-time, marker-colors, marker-high-levels, marker-levels, marker-low-levels, marker-message, marker-names, marker-types, and printer-commands attributes as well.

Use the cupsFreeDests function to free the destination list and the cupsGetDest function to find a particular destination.

 CUPS 1.1.20/macOS 10.4 cupsGetFd

Get a file from the server.

http_status_t cupsGetFd (
    http_t *http,
    const char *resource,
    int fd
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
resource
Resource name
fd
File descriptor

Return Value

HTTP status

Discussion

This function returns HTTP_STATUS_OK when the file is successfully retrieved.

 CUPS 1.1.20/macOS 10.4 cupsGetFile

Get a file from the server.

http_status_t cupsGetFile (
    http_t *http,
    const char *resource,
    const char *filename
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
resource
Resource name
filename
Filename

Return Value

HTTP status

Discussion

This function returns HTTP_STATUS_OK when the file is successfully retrieved.

cupsGetJobs

Get the jobs from the default server.

int cupsGetJobs (
    cups_job_t **jobs,
    const char *name,
    int myjobs,
    int whichjobs
);

Parameters

jobs
Job data
name
NULL = all destinations, otherwise show jobs for named destination
myjobs
0 = all users, 1 = mine
whichjobs
CUPS_WHICHJOBS_ALL, CUPS_WHICHJOBS_ACTIVE, or CUPS_WHICHJOBS_COMPLETED

Return Value

Number of jobs

Discussion

A "whichjobs" value of CUPS_WHICHJOBS_ALL returns all jobs regardless of state, while CUPS_WHICHJOBS_ACTIVE returns jobs that are pending, processing, or held and CUPS_WHICHJOBS_COMPLETED returns jobs that are stopped, canceled, aborted, or completed.

 CUPS 1.1.21/macOS 10.4 cupsGetJobs2

Get the jobs from the specified server.

int cupsGetJobs2 (
    http_t *http,
    cups_job_t **jobs,
    const char *name,
    int myjobs,
    int whichjobs
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
jobs
Job data
name
NULL = all destinations, otherwise show jobs for named destination
myjobs
0 = all users, 1 = mine
whichjobs
CUPS_WHICHJOBS_ALL, CUPS_WHICHJOBS_ACTIVE, or CUPS_WHICHJOBS_COMPLETED

Return Value

Number of jobs

Discussion

A "whichjobs" value of CUPS_WHICHJOBS_ALL returns all jobs regardless of state, while CUPS_WHICHJOBS_ACTIVE returns jobs that are pending, processing, or held and CUPS_WHICHJOBS_COMPLETED returns jobs that are stopped, canceled, aborted, or completed.

 CUPS 1.4/macOS 10.6 cupsGetNamedDest

Get options for the named destination.

cups_dest_t *cupsGetNamedDest (
    http_t *http,
    const char *name,
    const char *instance
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
name
Destination name or NULL for the default destination
instance
Instance name or NULL

Return Value

Destination or NULL

Discussion

This function is optimized for retrieving a single destination and should be used instead of cupsGetDests and cupsGetDest when you either know the name of the destination or want to print to the default destination. If NULL is returned, the destination does not exist or there is no default destination.

If "http" is CUPS_HTTP_DEFAULT, the connection to the default print server will be used.

If "name" is NULL, the default printer for the current user will be returned.

The returned destination must be freed using cupsFreeDests with a "num_dests" value of 1.

cupsGetOption

Get an option value.

const char *cupsGetOption (
    const char *name,
    int num_options,
    cups_option_t *options
);

Parameters

name
Name of option
num_options
Number of options
options
Options

Return Value

Option value or NULL

cupsGetPassword

Get a password from the user.

const char *cupsGetPassword (
    const char *prompt
);

Parameters

prompt
Prompt string

Return Value

Password

Discussion

Uses the current password callback function. Returns NULL if the user does not provide a password.

Note: The current password callback function is tracked separately for each thread in a program. Multi-threaded programs that override the setting via the cupsSetPasswordCB or cupsSetPasswordCB2 functions need to do so in each thread for the same function to be used.

 CUPS 1.4/macOS 10.6 cupsGetPassword2

Get a password from the user using the advanced password callback.

const char *cupsGetPassword2 (
    const char *prompt,
    http_t *http,
    const char *method,
    const char *resource
);

Parameters

prompt
Prompt string
http
Connection to server or CUPS_HTTP_DEFAULT
method
Request method ("GET", "POST", "PUT")
resource
Resource path

Return Value

Password

Discussion

Uses the current password callback function. Returns NULL if the user does not provide a password.

Note: The current password callback function is tracked separately for each thread in a program. Multi-threaded programs that override the setting via the cupsSetPasswordCB or cupsSetPasswordCB2 functions need to do so in each thread for the same function to be used.

 DEPRECATED cupsGetPrinters

Get a list of printers from the default server.

int cupsGetPrinters (
    char ***printers
);

Parameters

printers
Printers

Return Value

Number of printers

Discussion

This function is deprecated and no longer returns a list of printers - use cupsGetDests instead.

 CUPS 1.4/macOS 10.6 cupsGetResponse

Get a response to an IPP request.

ipp_t *cupsGetResponse (
    http_t *http,
    const char *resource
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
resource
HTTP resource for POST

Return Value

Response or NULL on HTTP error

Discussion

Use this function to get the response for an IPP request sent using cupsSendRequest. For requests that return additional data, use cupsReadResponseData after getting a successful response, otherwise call httpFlush to complete the response processing.

 CUPS 2.2/macOS 10.12 cupsHashData

Perform a hash function on the given data.

ssize_t cupsHashData (
    const char *algorithm,
    const void *data,
    size_t datalen,
    unsigned char *hash,
    size_t hashsize
);

Parameters

algorithm
Algorithm name
data
Data to hash
datalen
Length of data to hash
hash
Hash buffer
hashsize
Size of hash buffer

Return Value

Size of hash or -1 on error

Discussion

The "algorithm" argument can be any of the registered, non-deprecated IPP hash algorithms for the "job-password-encryption" attribute, including "sha" for SHA-1, "sha-256" for SHA2-256, etc.

The "hash" argument points to a buffer of "hashsize" bytes and should be at least 64 bytes in length for all of the supported algorithms.

The returned hash is binary data.

cupsLastError

Return the last IPP status code received on the current thread.

ipp_status_t cupsLastError (void);

Return Value

IPP status code from last request

 CUPS 1.2/macOS 10.5 cupsLastErrorString

Return the last IPP status-message received on the current thread.

const char *cupsLastErrorString (void);

Return Value

status-message text from last request

 CUPS 2.0/macOS 10.10 cupsLocalizeDestMedia

Get the localized string for a destination media size.

const char *cupsLocalizeDestMedia (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *dinfo,
    unsigned flags,
    cups_size_t *size
);

Parameters

http
Connection to destination
dest
Destination
dinfo
Destination information
flags
Media flags
size
Media size

Return Value

Localized string

Discussion

The returned string is stored in the destination information and will become invalid if the destination information is deleted.

 CUPS 1.6/macOS 10.8 cupsLocalizeDestOption

Get the localized string for a destination option.

const char *cupsLocalizeDestOption (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *dinfo,
    const char *option
);

Parameters

http
Connection to destination
dest
Destination
dinfo
Destination information
option
Option to localize

Return Value

Localized string

Discussion

The returned string is stored in the destination information and will become invalid if the destination information is deleted.

 CUPS 1.6/macOS 10.8 cupsLocalizeDestValue

Get the localized string for a destination option+value pair.

const char *cupsLocalizeDestValue (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *dinfo,
    const char *option,
    const char *value
);

Parameters

http
Connection to destination
dest
Destination
dinfo
Destination information
option
Option to localize
value
Value to localize

Return Value

Localized string

Discussion

The returned string is stored in the destination information and will become invalid if the destination information is deleted.

 CUPS 1.2/macOS 10.5 cupsNotifySubject

Return the subject for the given notification message.

char *cupsNotifySubject (
    cups_lang_t *lang,
    ipp_t *event
);

Parameters

lang
Language data
event
Event data

Return Value

Subject string or NULL

Discussion

The returned string must be freed by the caller using free.

 CUPS 1.2/macOS 10.5 cupsNotifyText

Return the text for the given notification message.

char *cupsNotifyText (
    cups_lang_t *lang,
    ipp_t *event
);

Parameters

lang
Language data
event
Event data

Return Value

Message text or NULL

Discussion

The returned string must be freed by the caller using free.

cupsParseOptions

Parse options from a command-line argument.

int cupsParseOptions (
    const char *arg,
    int num_options,
    cups_option_t **options
);

Parameters

arg
Argument to parse
num_options
Number of options
options
Options found

Return Value

Number of options found

Discussion

This function converts space-delimited name/value pairs according to the PAPI text option ABNF specification. Collection values ("name={a=... b=... c=...}") are stored with the curley brackets intact - use cupsParseOptions on the value to extract the collection attributes.

cupsPrintFile

Print a file to a printer or class on the default server.

int cupsPrintFile (
    const char *name,
    const char *filename,
    const char *title,
    int num_options,
    cups_option_t *options
);

Parameters

name
Destination name
filename
File to print
title
Title of job
num_options
Number of options
options
Options

Return Value

Job ID or 0 on error

 CUPS 1.1.21/macOS 10.4 cupsPrintFile2

Print a file to a printer or class on the specified server.

int cupsPrintFile2 (
    http_t *http,
    const char *name,
    const char *filename,
    const char *title,
    int num_options,
    cups_option_t *options
);

Parameters

http
Connection to server
name
Destination name
filename
File to print
title
Title of job
num_options
Number of options
options
Options

Return Value

Job ID or 0 on error

cupsPrintFiles

Print one or more files to a printer or class on the default server.

int cupsPrintFiles (
    const char *name,
    int num_files,
    const char **files,
    const char *title,
    int num_options,
    cups_option_t *options
);

Parameters

name
Destination name
num_files
Number of files
files
File(s) to print
title
Title of job
num_options
Number of options
options
Options

Return Value

Job ID or 0 on error

 CUPS 1.1.21/macOS 10.4 cupsPrintFiles2

Print one or more files to a printer or class on the specified server.

int cupsPrintFiles2 (
    http_t *http,
    const char *name,
    int num_files,
    const char **files,
    const char *title,
    int num_options,
    cups_option_t *options
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
name
Destination name
num_files
Number of files
files
File(s) to print
title
Title of job
num_options
Number of options
options
Options

Return Value

Job ID or 0 on error

 CUPS 1.1.20/macOS 10.4 cupsPutFd

Put a file on the server.

http_status_t cupsPutFd (
    http_t *http,
    const char *resource,
    int fd
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
resource
Resource name
fd
File descriptor

Return Value

HTTP status

Discussion

This function returns HTTP_STATUS_CREATED when the file is stored successfully.

 CUPS 1.1.20/macOS 10.4 cupsPutFile

Put a file on the server.

http_status_t cupsPutFile (
    http_t *http,
    const char *resource,
    const char *filename
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
resource
Resource name
filename
Filename

Return Value

HTTP status

Discussion

This function returns HTTP_CREATED when the file is stored successfully.

cupsRasterClose

Close a raster stream.

void cupsRasterClose (
    cups_raster_t *r
);

Parameters

r
Stream to close

Discussion

The file descriptor associated with the raster stream must be closed separately as needed.

 CUPS 1.3/macOS 10.5 cupsRasterErrorString

Return the last error from a raster function.

const char *cupsRasterErrorString (void);

Return Value

Last error

Discussion

If there are no recent errors, NULL is returned.

 CUPS 2.2/macOS 10.12 cupsRasterInitPWGHeader

Initialize a page header for PWG Raster output.

int cupsRasterInitPWGHeader (
    cups_page_header2_t *h,
    pwg_media_t *media,
    const char *type,
    int xdpi,
    int ydpi,
    const char *sides,
    const char *sheet_back
);

Parameters

h
Page header
media
PWG media information
type
PWG raster type string
xdpi
Cross-feed direction (horizontal) resolution
ydpi
Feed direction (vertical) resolution
sides
IPP "sides" option value
sheet_back
Transform for back side or NULL for none

Return Value

1 on success, 0 on failure

Discussion

The "media" argument specifies the media to use.

The "type" argument specifies a "pwg-raster-document-type-supported" value that controls the color space and bit depth of the raster data.

The "xres" and "yres" arguments specify the raster resolution in dots per inch.

The "sheet_back" argument specifies a "pwg-raster-document-sheet-back" value to apply for the back side of a page. Pass NULL for the front side.

cupsRasterOpen

Open a raster stream using a file descriptor.

cups_raster_t *cupsRasterOpen (
    int fd,
    cups_mode_t mode
);

Parameters

fd
File descriptor
mode
Mode - CUPS_RASTER_READ, CUPS_RASTER_WRITE, CUPS_RASTER_WRITE_COMPRESSED, or CUPS_RASTER_WRITE_PWG

Return Value

New stream

Discussion

This function associates a raster stream with the given file descriptor. For most printer driver filters, "fd" will be 0 (stdin). For most raster image processor (RIP) filters that generate raster data, "fd" will be 1 (stdout).

When writing raster data, the CUPS_RASTER_WRITE, CUPS_RASTER_WRITE_COMPRESS, or CUPS_RASTER_WRITE_PWG mode can be used - compressed and PWG output is generally 25-50% smaller but adds a 100-300% execution time overhead.

cupsRasterOpenIO

Open a raster stream using a callback function.

cups_raster_t *cupsRasterOpenIO (
    cups_raster_iocb_t iocb,
    void *ctx,
    cups_mode_t mode
);

Parameters

iocb
Read/write callback
ctx
Context pointer for callback
mode
Mode - CUPS_RASTER_READ, CUPS_RASTER_WRITE, CUPS_RASTER_WRITE_COMPRESSED, or CUPS_RASTER_WRITE_PWG

Return Value

New stream

Discussion

This function associates a raster stream with the given callback function and context pointer.

When writing raster data, the CUPS_RASTER_WRITE, CUPS_RASTER_WRITE_COMPRESS, or CUPS_RASTER_WRITE_PWG mode can be used - compressed and PWG output is generally 25-50% smaller but adds a 100-300% execution time overhead.

 DEPRECATED cupsRasterReadHeader

Read a raster page header and store it in a version 1 page header structure.

unsigned cupsRasterReadHeader (
    cups_raster_t *r,
    cups_page_header_t *h
);

Parameters

r
Raster stream
h
Pointer to header data

Return Value

1 on success, 0 on failure/end-of-file

Discussion

This function is deprecated. Use cupsRasterReadHeader2 instead.

Version 1 page headers were used in CUPS 1.0 and 1.1 and contain a subset of the version 2 page header data. This function handles reading version 2 page headers and copying only the version 1 data into the provided buffer.

 CUPS 1.2/macOS 10.5 cupsRasterReadHeader2

Read a raster page header and store it in a version 2 page header structure.

unsigned cupsRasterReadHeader2 (
    cups_raster_t *r,
    cups_page_header2_t *h
);

Parameters

r
Raster stream
h
Pointer to header data

Return Value

1 on success, 0 on failure/end-of-file

cupsRasterReadPixels

Read raster pixels.

unsigned cupsRasterReadPixels (
    cups_raster_t *r,
    unsigned char *p,
    unsigned len
);

Parameters

r
Raster stream
p
Pointer to pixel buffer
len
Number of bytes to read

Return Value

Number of bytes read

Discussion

For best performance, filters should read one or more whole lines. The "cupsBytesPerLine" value from the page header can be used to allocate the line buffer and as the number of bytes to read.

 DEPRECATED cupsRasterWriteHeader

Write a raster page header from a version 1 page header structure.

unsigned cupsRasterWriteHeader (
    cups_raster_t *r,
    cups_page_header_t *h
);

Parameters

r
Raster stream
h
Raster page header

Return Value

1 on success, 0 on failure

Discussion

This function is deprecated. Use cupsRasterWriteHeader2 instead.

 CUPS 1.2/macOS 10.5 cupsRasterWriteHeader2

Write a raster page header from a version 2 page header structure.

unsigned cupsRasterWriteHeader2 (
    cups_raster_t *r,
    cups_page_header2_t *h
);

Parameters

r
Raster stream
h
Raster page header

Return Value

1 on success, 0 on failure

Discussion

The page header can be initialized using cupsRasterInterpretPPD.

cupsRasterWritePixels

Write raster pixels.

unsigned cupsRasterWritePixels (
    cups_raster_t *r,
    unsigned char *p,
    unsigned len
);

Parameters

r
Raster stream
p
Bytes to write
len
Number of bytes to write

Return Value

Number of bytes written

Discussion

For best performance, filters should write one or more whole lines. The "cupsBytesPerLine" value from the page header can be used to allocate the line buffer and as the number of bytes to write.

 CUPS 1.4/macOS 10.6 cupsReadResponseData

Read additional data after the IPP response.

ssize_t cupsReadResponseData (
    http_t *http,
    char *buffer,
    size_t length
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
buffer
Buffer to use
length
Number of bytes to read

Return Value

Bytes read, 0 on EOF, -1 on error

Discussion

This function is used after cupsGetResponse to read the PPD or document files from CUPS_GET_PPD and CUPS_GET_DOCUMENT requests, respectively.

 CUPS 1.3/macOS 10.5 cupsRemoveDest

Remove a destination from the destination list.

int cupsRemoveDest (
    const char *name,
    const char *instance,
    int num_dests,
    cups_dest_t **dests
);

Parameters

name
Destination name
instance
Instance name or NULL
num_dests
Number of destinations
dests
Destinations

Return Value

New number of destinations

Discussion

Removing a destination/instance does not delete the class or printer queue, merely the lpoptions for that destination/instance. Use the cupsSetDests or cupsSetDests2 functions to save the new options for the user.

 CUPS 1.2/macOS 10.5 cupsRemoveOption

Remove an option from an option array.

int cupsRemoveOption (
    const char *name,
    int num_options,
    cups_option_t **options
);

Parameters

name
Option name
num_options
Current number of options
options
Options

Return Value

New number of options

 CUPS 1.4/macOS 10.6 cupsSendRequest

Send an IPP request.

http_status_t cupsSendRequest (
    http_t *http,
    ipp_t *request,
    const char *resource,
    size_t length
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
request
IPP request
resource
Resource path
length
Length of data to follow or CUPS_LENGTH_VARIABLE

Return Value

Initial HTTP status

Discussion

Use cupsWriteRequestData to write any additional data (document, PPD file, etc.) for the request, cupsGetResponse to get the IPP response, and cupsReadResponseData to read any additional data following the response. Only one request can be sent/queued at a time per http_t connection.

Returns the initial HTTP status code, which will be HTTP_STATUS_CONTINUE on a successful send of the request.

Note: Unlike cupsDoFileRequest, cupsDoIORequest, and cupsDoRequest, the request is NOT freed with ippDelete.

cupsServer

Return the hostname/address of the current server.

const char *cupsServer (void);

Return Value

Server name

Discussion

The default server comes from the CUPS_SERVER environment variable, then the ~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not set, the default is the local system - either "localhost" or a domain socket path.

The returned value can be a fully-qualified hostname, a numeric IPv4 or IPv6 address, or a domain socket pathname.

Note: The current server is tracked separately for each thread in a program. Multi-threaded programs that override the server via the cupsSetServer function need to do so in each thread for the same server to be used.

 CUPS 1.5/macOS 10.7 cupsSetClientCertCB

Set the client certificate callback.

void cupsSetClientCertCB (
    cups_client_cert_cb_t cb,
    void *user_data
);

Parameters

cb
Callback function
user_data
User data pointer

Discussion

Pass NULL to restore the default callback.

Note: The current certificate callback is tracked separately for each thread in a program. Multi-threaded programs that override the callback need to do so in each thread for the same callback to be used.

 CUPS 1.5/macOS 10.7 cupsSetCredentials

Set the default credentials to be used for SSL/TLS connections.

int cupsSetCredentials (
    cups_array_t *credentials
);

Parameters

credentials
Array of credentials

Return Value

Status of call (0 = success)

Discussion

Note: The default credentials are tracked separately for each thread in a program. Multi-threaded programs that override the setting need to do so in each thread for the same setting to be used.

 CUPS 1.3/macOS 10.5 cupsSetDefaultDest

Set the default destination.

void cupsSetDefaultDest (
    const char *name,
    const char *instance,
    int num_dests,
    cups_dest_t *dests
);

Parameters

name
Destination name
instance
Instance name or NULL
num_dests
Number of destinations
dests
Destinations

cupsSetDests

Save the list of destinations for the default server.

void cupsSetDests (
    int num_dests,
    cups_dest_t *dests
);

Parameters

num_dests
Number of destinations
dests
Destinations

Discussion

This function saves the destinations to /etc/cups/lpoptions when run as root and ~/.cups/lpoptions when run as a normal user.

 CUPS 1.1.21/macOS 10.4 cupsSetDests2

Save the list of destinations for the specified server.

int cupsSetDests2 (
    http_t *http,
    int num_dests,
    cups_dest_t *dests
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
num_dests
Number of destinations
dests
Destinations

Return Value

0 on success, -1 on error

Discussion

This function saves the destinations to /etc/cups/lpoptions when run as root and ~/.cups/lpoptions when run as a normal user.

cupsSetEncryption

Set the encryption preference.

void cupsSetEncryption (
    http_encryption_t e
);

Parameters

e
New encryption preference

Discussion

The default encryption setting comes from the CUPS_ENCRYPTION environment variable, then the ~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not set, the default is HTTP_ENCRYPTION_IF_REQUESTED.

Note: The current encryption setting is tracked separately for each thread in a program. Multi-threaded programs that override the setting need to do so in each thread for the same setting to be used.

cupsSetPasswordCB

Set the password callback for CUPS.

void cupsSetPasswordCB (
    cups_password_cb_t cb
);

Parameters

cb
Callback function

Discussion

Pass NULL to restore the default (console) password callback, which reads the password from the console. Programs should call either this function or cupsSetPasswordCB2, as only one callback can be registered by a program per thread.

Note: The current password callback is tracked separately for each thread in a program. Multi-threaded programs that override the callback need to do so in each thread for the same callback to be used.

 CUPS 1.4/macOS 10.6 cupsSetPasswordCB2

Set the advanced password callback for CUPS.

void cupsSetPasswordCB2 (
    cups_password_cb2_t cb,
    void *user_data
);

Parameters

cb
Callback function
user_data
User data pointer

Discussion

Pass NULL to restore the default (console) password callback, which reads the password from the console. Programs should call either this function or cupsSetPasswordCB2, as only one callback can be registered by a program per thread.

Note: The current password callback is tracked separately for each thread in a program. Multi-threaded programs that override the callback need to do so in each thread for the same callback to be used.

cupsSetServer

Set the default server name and port.

void cupsSetServer (
    const char *server
);

Parameters

server
Server name

Discussion

The "server" string can be a fully-qualified hostname, a numeric IPv4 or IPv6 address, or a domain socket pathname. Hostnames and numeric IP addresses can be optionally followed by a colon and port number to override the default port 631, e.g. "hostname:8631". Pass NULL to restore the default server name and port.

Note: The current server is tracked separately for each thread in a program. Multi-threaded programs that override the server need to do so in each thread for the same server to be used.

 CUPS 1.5/macOS 10.7 cupsSetServerCertCB

Set the server certificate callback.

void cupsSetServerCertCB (
    cups_server_cert_cb_t cb,
    void *user_data
);

Parameters

cb
Callback function
user_data
User data pointer

Discussion

Pass NULL to restore the default callback.

Note: The current credentials callback is tracked separately for each thread in a program. Multi-threaded programs that override the callback need to do so in each thread for the same callback to be used.

cupsSetUser

Set the default user name.

void cupsSetUser (
    const char *user
);

Parameters

user
User name

Discussion

Pass NULL to restore the default user name.

Note: The current user name is tracked separately for each thread in a program. Multi-threaded programs that override the user name need to do so in each thread for the same user name to be used.

 CUPS 1.7/macOS 10.9 cupsSetUserAgent

Set the default HTTP User-Agent string.

void cupsSetUserAgent (
    const char *user_agent
);

Parameters

user_agent
User-Agent string or NULL

Discussion

Setting the string to NULL forces the default value containing the CUPS version, IPP version, and operating system version and architecture.

 CUPS 1.6/macOS 10.8 cupsStartDestDocument

Start a new document.

http_status_t cupsStartDestDocument (
    http_t *http,
    cups_dest_t *dest,
    cups_dinfo_t *info,
    int job_id,
    const char *docname,
    const char *format,
    int num_options,
    cups_option_t *options,
    int last_document
);

Parameters

http
Connection to destination
dest
Destination
info
Destination information
job_id
Job ID
docname
Document name
format
Document format
num_options
Number of document options
options
Document options
last_document
1 if this is the last document

Return Value

Status of document creation

Discussion

"job_id" is the job ID returned by cupsCreateDestJob. "docname" is the name of the document/file being printed, "format" is the MIME media type for the document (see CUPS_FORMAT_xxx constants), and "num_options" and "options" are the options do be applied to the document. "last_document" should be 1 if this is the last document to be submitted in the job. Returns HTTP_CONTINUE on success.

 CUPS 1.4/macOS 10.6 cupsStartDocument

Add a document to a job created with cupsCreateJob().

http_status_t cupsStartDocument (
    http_t *http,
    const char *name,
    int job_id,
    const char *docname,
    const char *format,
    int last_document
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
name
Destination name
job_id
Job ID from cupsCreateJob
docname
Name of document
format
MIME type or CUPS_FORMAT_foo
last_document
1 for last document in job, 0 otherwise

Return Value

HTTP status of request

Discussion

Use cupsWriteRequestData to write data for the document and cupsFinishDocument to finish the document and get the submission status.

The MIME type constants CUPS_FORMAT_AUTO, CUPS_FORMAT_PDF, CUPS_FORMAT_POSTSCRIPT, CUPS_FORMAT_RAW, and CUPS_FORMAT_TEXT are provided for the "format" argument, although any supported MIME type string can be supplied.

cupsUser

Return the current user's name.

const char *cupsUser (void);

Return Value

User name

Discussion

Note: The current user name is tracked separately for each thread in a program. Multi-threaded programs that override the user name with the cupsSetUser function need to do so in each thread for the same user name to be used.

 CUPS 1.7/macOS 10.9 cupsUserAgent

Return the default HTTP User-Agent string.

const char *cupsUserAgent (void);

Return Value

User-Agent string

 CUPS 1.4/macOS 10.6 cupsWriteRequestData

Write additional data after an IPP request.

http_status_t cupsWriteRequestData (
    http_t *http,
    const char *buffer,
    size_t length
);

Parameters

http
Connection to server or CUPS_HTTP_DEFAULT
buffer
Bytes to write
length
Number of bytes to write

Return Value

HTTP_STATUS_CONTINUE if OK or HTTP status on error

Discussion

This function is used after cupsSendRequest to provide a PPD and after cupsStartDocument to provide a document file.

get_error_buffer

Return a pointer to thread local storage.

_cups_raster_error_t *get_error_buffer (void);

Return Value

Pointer to error buffer

 CUPS 1.7/macOS 10.9 httpAcceptConnection

Accept a new HTTP client connection from the specified listening socket.

http_t *httpAcceptConnection (
    int fd,
    int blocking
);

Parameters

fd
Listen socket file descriptor
blocking
1 if the connection should be blocking, 0 otherwise

Return Value

HTTP connection or NULL

 CUPS 1.5/macOS 10.7 httpAddCredential

Allocates and adds a single credential to an array.

int httpAddCredential (
    cups_array_t *credentials,
    const void *data,
    size_t datalen
);

Parameters

credentials
Credentials array
data
PEM-encoded X.509 data
datalen
Length of data

Return Value

0 on success, -1 on error

Discussion

Use cupsArrayNew(NULL, NULL) to create a credentials array.

 CUPS 1.2/macOS 10.5 httpAddrAny

Check for the "any" address.

int httpAddrAny (
    const http_addr_t *addr
);

Parameters

addr
Address to check

Return Value

1 if "any", 0 otherwise

 CUPS 2.0/OS 10.10 httpAddrClose

Close a socket created by httpAddrConnect or httpAddrListen.

int httpAddrClose (
    http_addr_t *addr,
    int fd
);

Parameters

addr
Listen address or NULL
fd
Socket file descriptor

Return Value

0 on success, -1 on failure

Discussion

Pass NULL for sockets created with httpAddrConnect and the listen address for sockets created with httpAddrListen. This will ensure that domain sockets are removed when closed.

 CUPS 1.2/macOS 10.5 httpAddrConnect

Connect to any of the addresses in the list.

http_addrlist_t *httpAddrConnect (
    http_addrlist_t *addrlist,
    int *sock
);

Parameters

addrlist
List of potential addresses
sock
Socket

Return Value

Connected address or NULL on failure

 CUPS 1.7/macOS 10.9 httpAddrConnect2

Connect to any of the addresses in the list with a timeout and optional cancel.

http_addrlist_t *httpAddrConnect2 (
    http_addrlist_t *addrlist,
    int *sock,
    int msec,
    int *cancel
);

Parameters

addrlist
List of potential addresses
sock
Socket
msec
Timeout in milliseconds
cancel
Pointer to "cancel" variable

Return Value

Connected address or NULL on failure

 CUPS 1.7/macOS 10.9 httpAddrCopyList

Copy an address list.

http_addrlist_t *httpAddrCopyList (
    http_addrlist_t *src
);

Parameters

src
Source address list

Return Value

New address list or NULL on error

 CUPS 1.2/macOS 10.5 httpAddrEqual

Compare two addresses.

int httpAddrEqual (
    const http_addr_t *addr1,
    const http_addr_t *addr2
);

Parameters

addr1
First address
addr2
Second address

Return Value

1 if equal, 0 if not

httpAddrFamily

Get the address family of an address.

int httpAddrFamily (
    http_addr_t *addr
);

Parameters

addr
Address

Return Value

Address family

 CUPS 1.2/macOS 10.5 httpAddrFreeList

Free an address list.

void httpAddrFreeList (
    http_addrlist_t *addrlist
);

Parameters

addrlist
Address list to free

 CUPS 1.2/macOS 10.5 httpAddrGetList

Get a list of addresses for a hostname.

http_addrlist_t *httpAddrGetList (
    const char *hostname,
    int family,
    const char *service
);

Parameters

hostname
Hostname, IP address, or NULL for passive listen address
family
Address family or AF_UNSPEC
service
Service name or port number

Return Value

List of addresses or NULL

 CUPS 1.2/macOS 10.5 httpAddrLength

Return the length of the address in bytes.

int httpAddrLength (
    const http_addr_t *addr
);

Parameters

addr
Address

Return Value

Length in bytes

 CUPS 1.7/macOS 10.9 httpAddrListen

Create a listening socket bound to the specified address and port.

int httpAddrListen (
    http_addr_t *addr,
    int port
);

Parameters

addr
Address to bind to
port
Port number to bind to

Return Value

Socket or -1 on error

 CUPS 1.2/macOS 10.5 httpAddrLocalhost

Check for the local loopback address.

int httpAddrLocalhost (
    const http_addr_t *addr
);

Parameters

addr
Address to check

Return Value

1 if local host, 0 otherwise

 CUPS 1.2/macOS 10.5 httpAddrLookup

Lookup the hostname associated with the address.

char *httpAddrLookup (
    const http_addr_t *addr,
    char *name,
    int namelen
);

Parameters

addr
Address to lookup
name
Host name buffer
namelen
Size of name buffer

Return Value

Host name

 CUPS 1.7/macOS 10.9 httpAddrPort

Get the port number associated with an address.

int httpAddrPort (
    http_addr_t *addr
);

Parameters

addr
Address

Return Value

Port number

 CUPS 1.2/macOS 10.5 httpAddrString

Convert an address to a numeric string.

char *httpAddrString (
    const http_addr_t *addr,
    char *s,
    int slen
);

Parameters

addr
Address to convert
s
String buffer
slen
Length of string

Return Value

Numeric address string

 CUPS 1.2/macOS 10.5 httpAssembleURI

Assemble a uniform resource identifier from its components.

http_uri_status_t httpAssembleURI (
    http_uri_coding_t encoding,
    char *uri,
    int urilen,
    const char *scheme,
    const char *username,
    const char *host,
    int port,
    const char *resource
);

Parameters

encoding
Encoding flags
uri
URI buffer
urilen
Size of URI buffer
scheme
Scheme name
username
Username
host
Hostname or address
port
Port number
resource
Resource

Return Value

URI status

Discussion

This function escapes reserved characters in the URI depending on the value of the "encoding" argument. You should use this function in place of traditional string functions whenever you need to create a URI string.

 CUPS 1.2/macOS 10.5 httpAssembleURIf

Assemble a uniform resource identifier from its components with a formatted resource.

http_uri_status_t httpAssembleURIf (
    http_uri_coding_t encoding,
    char *uri,
    int urilen,
    const char *scheme,
    const char *username,
    const char *host,
    int port,
    const char *resourcef,
    ...
);

Parameters

encoding
Encoding flags
uri
URI buffer
urilen
Size of URI buffer
scheme
Scheme name
username
Username
host
Hostname or address
port
Port number
resourcef
Printf-style resource
...
Additional arguments as needed

Return Value

URI status

Discussion

This function creates a formatted version of the resource string argument "resourcef" and escapes reserved characters in the URI depending on the value of the "encoding" argument. You should use this function in place of traditional string functions whenever you need to create a URI string.

 CUPS 1.7/macOS 10.9 httpAssembleUUID

Assemble a name-based UUID URN conforming to RFC 4122.

char *httpAssembleUUID (
    const char *server,
    int port,
    const char *name,
    int number,
    char *buffer,
    size_t bufsize
);

Parameters

server
Server name
port
Port number
name
Object name or NULL
number
Object number or 0
buffer
String buffer
bufsize
Size of buffer

Return Value

UUID string

Discussion

This function creates a unique 128-bit identifying number using the server name, port number, random data, and optionally an object name and/or object number. The result is formatted as a UUID URN as defined in RFC 4122.

The buffer needs to be at least 46 bytes in size.

httpBlocking

Set blocking/non-blocking behavior on a connection.

void httpBlocking (
    http_t *http,
    int b
);

Parameters

http
HTTP connection
b
1 = blocking, 0 = non-blocking

httpCheck

Check to see if there is a pending response from the server.

int httpCheck (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

0 = no data, 1 = data available

 CUPS 1.1.19/macOS 10.3 httpClearCookie

Clear the cookie value(s).

void httpClearCookie (
    http_t *http
);

Parameters

http
HTTP connection

httpClearFields

Clear HTTP request fields.

void httpClearFields (
    http_t *http
);

Parameters

http
HTTP connection

httpClose

Close an HTTP connection.

void httpClose (
    http_t *http
);

Parameters

http
HTTP connection

 CUPS 2.0/OS 10.10 httpCompareCredentials

Compare two sets of X.509 credentials.

int httpCompareCredentials (
    cups_array_t *cred1,
    cups_array_t *cred2
);

Parameters

cred1
First set of X.509 credentials
cred2
Second set of X.509 credentials

Return Value

1 if they match, 0 if they do not

 DEPRECATED httpConnect

Connect to a HTTP server.

http_t *httpConnect (
    const char *host,
    int port
);

Parameters

host
Host to connect to
port
Port number

Return Value

New HTTP connection

Discussion

This function is deprecated - use httpConnect2 instead.

 CUPS 1.7/macOS 10.9 httpConnect2

Connect to a HTTP server.

http_t *httpConnect2 (
    const char *host,
    int port,
    http_addrlist_t *addrlist,
    int family,
    http_encryption_t encryption,
    int blocking,
    int msec,
    int *cancel
);

Parameters

host
Host to connect to
port
Port number
addrlist
List of addresses or NULL to lookup
family
Address family to use or AF_UNSPEC for any
encryption
Type of encryption to use
blocking
1 for blocking connection, 0 for non-blocking
msec
Connection timeout in milliseconds, 0 means don't connect
cancel
Pointer to "cancel" variable

Return Value

New HTTP connection

 DEPRECATED httpConnectEncrypt

Connect to a HTTP server using encryption.

http_t *httpConnectEncrypt (
    const char *host,
    int port,
    http_encryption_t encryption
);

Parameters

host
Host to connect to
port
Port number
encryption
Type of encryption to use

Return Value

New HTTP connection

Discussion

This function is now deprecated. Please use the httpConnect2 function instead.

httpCopyCredentials

Local functions...

int httpCopyCredentials (
    http_t *http,
    cups_array_t **credentials
);

Parameters

http
credentials

Return Value

Stubs for when TLS is not supported/available

httpCredentialsAreValidForName

int httpCredentialsAreValidForName (
    cups_array_t *credentials,
    const char *common_name
);

Parameters

credentials
common_name

Return Value

httpCredentialsGetExpiration

time_t httpCredentialsGetExpiration (
    cups_array_t *credentials
);

Parameters

credentials

Return Value

httpCredentialsGetTrust

http_trust_t httpCredentialsGetTrust (
    cups_array_t *credentials,
    const char *common_name
);

Parameters

credentials
common_name

Return Value

httpCredentialsString

size_t httpCredentialsString (
    cups_array_t *credentials,
    char *buffer,
    size_t bufsize
);

Parameters

credentials
buffer
bufsize

Return Value

 DEPRECATED httpDecode64

Base64-decode a string.

char *httpDecode64 (
    char *out,
    const char *in
);

Parameters

out
String to write to
in
String to read from

Return Value

Decoded string

Discussion

This function is deprecated. Use the httpDecode64_2() function instead which provides buffer length arguments.

 CUPS 1.1.21/macOS 10.4 httpDecode64_2

Base64-decode a string.

char *httpDecode64_2 (
    char *out,
    int *outlen,
    const char *in
);

Parameters

out
String to write to
outlen
Size of output string
in
String to read from

Return Value

Decoded string

httpDelete

Send a DELETE request to the server.

int httpDelete (
    http_t *http,
    const char *uri
);

Parameters

http
HTTP connection
uri
URI to delete

Return Value

Status of call (0 = success)

 DEPRECATED httpEncode64

Base64-encode a string.

char *httpEncode64 (
    char *out,
    const char *in
);

Parameters

out
String to write to
in
String to read from

Return Value

Encoded string

Discussion

This function is deprecated. Use the httpEncode64_2() function instead which provides buffer length arguments.

 CUPS 1.1.21/macOS 10.4 httpEncode64_2

Base64-encode a string.

char *httpEncode64_2 (
    char *out,
    int outlen,
    const char *in,
    int inlen
);

Parameters

out
String to write to
outlen
Size of output string
in
String to read from
inlen
Size of input string

Return Value

Encoded string

httpEncryption

Set the required encryption on the link.

int httpEncryption (
    http_t *http,
    http_encryption_t e
);

Parameters

http
HTTP connection
e
New encryption preference

Return Value

-1 on error, 0 on success

httpError

Get the last error on a connection.

int httpError (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Error code (errno) value

httpFieldValue

Return the HTTP field enumeration value for a field name.

http_field_t httpFieldValue (
    const char *name
);

Parameters

name
String name

Return Value

Field index

httpFlush

Flush data from a HTTP connection.

void httpFlush (
    http_t *http
);

Parameters

http
HTTP connection

 CUPS 1.2/macOS 10.5 httpFlushWrite

Flush data in write buffer.

int httpFlushWrite (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Bytes written or -1 on error

httpFreeCredentials

Free an array of credentials.

void httpFreeCredentials (
    cups_array_t *credentials
);

Parameters

credentials
Array of credentials

httpGet

Send a GET request to the server.

int httpGet (
    http_t *http,
    const char *uri
);

Parameters

http
HTTP connection
uri
URI to get

Return Value

Status of call (0 = success)

 CUPS 2.0/OS 10.10 httpGetActivity

Get the most recent activity for a connection.

time_t httpGetActivity (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Time of last read or write

Discussion

The return value is the UNIX time of the last read or write.

 CUPS 2.0/OS 10.10 httpGetAddress

Get the address of the connected peer of a connection.

http_addr_t *httpGetAddress (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Connected address or NULL

Discussion

Returns NULL if the socket is currently unconnected.

 CUPS 1.3/macOS 10.5 httpGetAuthString

Get the current authorization string.

char *httpGetAuthString (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Authorization string

Discussion

The authorization string is set by cupsDoAuthentication() and httpSetAuthString(). Use httpGetAuthString() to retrieve the string to use with httpSetField() for the HTTP_FIELD_AUTHORIZATION value.

 CUPS 1.2/macOS 10.5 httpGetBlocking

Get the blocking/non-block state of a connection.

int httpGetBlocking (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

1 if blocking, 0 if non-blocking

 CUPS 1.7/macOS 10.9 httpGetContentEncoding

Get a common content encoding, if any, between the client and server.

const char *httpGetContentEncoding (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Content-Coding value or NULL for the identity coding.

Discussion

This function uses the value of the Accepts-Encoding HTTP header and must be called after receiving a response from the server or a request from the client. The value returned can be use in subsequent requests (for clients) or in the response (for servers) in order to compress the content stream.

 CUPS 1.1.19/macOS 10.3 httpGetCookie

Get any cookie data from the response.

const char *httpGetCookie (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Cookie data or NULL

 DEPRECATED httpGetDateString

Get a formatted date/time string from a time value.

const char *httpGetDateString (
    time_t t
);

Parameters

t
UNIX time

Return Value

Date/time string

 CUPS 1.2/macOS 10.5 httpGetDateString2

Get a formatted date/time string from a time value.

const char *httpGetDateString2 (
    time_t t,
    char *s,
    int slen
);

Parameters

t
UNIX time
s
String buffer
slen
Size of string buffer

Return Value

Date/time string

httpGetDateTime

Get a time value from a formatted date/time string.

time_t httpGetDateTime (
    const char *s
);

Parameters

s
Date/time string

Return Value

UNIX time

 CUPS 2.0/OS 10.10 httpGetEncryption

Get the current encryption mode of a connection.

http_encryption_t httpGetEncryption (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Current encryption mode

Discussion

This function returns the encryption mode for the connection. Use the httpIsEncrypted function to determine whether a TLS session has been established.

 CUPS 1.7/macOS 10.9 httpGetExpect

Get the value of the Expect header, if any.

http_status_t httpGetExpect (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Expect: status, if any

Discussion

Returns HTTP_STATUS_NONE if there is no Expect header, otherwise returns the expected HTTP status code, typically HTTP_STATUS_CONTINUE.

 CUPS 1.2/macOS 10.5 httpGetFd

Get the file descriptor associated with a connection.

int httpGetFd (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

File descriptor or -1 if none

httpGetField

Get a field value from a request/response.

const char *httpGetField (
    http_t *http,
    http_field_t field
);

Parameters

http
HTTP connection
field
Field to get

Return Value

Field value

 DEPRECATED httpGetHostByName

Lookup a hostname or IPv4 address, and return address records for the specified name.

struct hostent *httpGetHostByName (
    const char *name
);

Parameters

name
Hostname or IP address

Return Value

Host entry

 CUPS 1.2/macOS 10.5 httpGetHostname

Get the FQDN for the connection or local system.

const char *httpGetHostname (
    http_t *http,
    char *s,
    int slen
);

Parameters

http
HTTP connection or NULL
s
String buffer for name
slen
Size of buffer

Return Value

FQDN for connection or system

Discussion

When "http" points to a connected socket, return the hostname or address that was used in the call to httpConnect() or httpConnectEncrypt(), or the address of the client for the connection from httpAcceptConnection(). Otherwise, return the FQDN for the local system using both gethostname() and gethostbyname() to get the local hostname with domain.

 CUPS 2.0/OS 10.10 httpGetKeepAlive

Get the current Keep-Alive state of the connection.

http_keepalive_t httpGetKeepAlive (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Keep-Alive state

 DEPRECATED httpGetLength

Get the amount of data remaining from the content-length or transfer-encoding fields.

int httpGetLength (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Content length

Discussion

This function is deprecated and will not return lengths larger than 2^31 - 1; use httpGetLength2() instead.

 CUPS 1.2/macOS 10.5 httpGetLength2

Get the amount of data remaining from the content-length or transfer-encoding fields.

off_t httpGetLength2 (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Content length

Discussion

This function returns the complete content length, even for content larger than 2^31 - 1.

 CUPS 2.0/OS 10.10 httpGetPending

Get the number of bytes that are buffered for writing.

size_t httpGetPending (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Number of bytes buffered

 CUPS 2.0/OS 10.10 httpGetReady

Get the number of bytes that can be read without blocking.

size_t httpGetReady (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Number of bytes available

 CUPS 2.0/OS 10.10 httpGetRemaining

Get the number of remaining bytes in the message body or current chunk.

size_t httpGetRemaining (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Remaining bytes

Discussion

The httpIsChunked function can be used to determine whether the message body is chunked or fixed-length.

httpGetState

Get the current state of the HTTP request.

http_state_t httpGetState (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

HTTP state

 CUPS 1.2/macOS 10.5 httpGetStatus

Get the status of the last HTTP request.

http_status_t httpGetStatus (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

HTTP status

 DEPRECATED httpGetSubField

Get a sub-field value.

char *httpGetSubField (
    http_t *http,
    http_field_t field,
    const char *name,
    char *value
);

Parameters

http
HTTP connection
field
Field index
name
Name of sub-field
value
Value string

Return Value

Value or NULL

 CUPS 1.2/macOS 10.5 httpGetSubField2

Get a sub-field value.

char *httpGetSubField2 (
    http_t *http,
    http_field_t field,
    const char *name,
    char *value,
    int valuelen
);

Parameters

http
HTTP connection
field
Field index
name
Name of sub-field
value
Value string
valuelen
Size of value buffer

Return Value

Value or NULL

httpGetVersion

Get the HTTP version at the other end.

http_version_t httpGetVersion (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

Version number

httpGets

Get a line of text from a HTTP connection.

char *httpGets (
    char *line,
    int length,
    http_t *http
);

Parameters

line
Line to read into
length
Max length of buffer
http
HTTP connection

Return Value

Line or NULL

httpHead

Send a HEAD request to the server.

int httpHead (
    http_t *http,
    const char *uri
);

Parameters

http
HTTP connection
uri
URI for head

Return Value

Status of call (0 = success)

httpInitialize

Initialize the HTTP interface library and set the default HTTP proxy (if any).

void httpInitialize (void);

 CUPS 2.0/OS 10.10 httpIsChunked

Report whether a message body is chunked.

int httpIsChunked (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

1 if chunked, 0 if not

Discussion

This function returns non-zero if the message body is composed of variable-length chunks.

 CUPS 2.0/OS 10.10 httpIsEncrypted

Report whether a connection is encrypted.

int httpIsEncrypted (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

1 if encrypted, 0 if not

Discussion

This function returns non-zero if the connection is currently encrypted.

httpLoadCredentials

int httpLoadCredentials (
    const char *path,
    cups_array_t **credentials,
    const char *common_name
);

Parameters

path
credentials
common_name

Return Value

httpMD5

Compute the MD5 sum of the username:group:password.

char *httpMD5 (
    const char *username,
    const char *realm,
    const char *passwd,
    char md5[33]
);

Parameters

username
User name
realm
Realm name
passwd
Password string
md5[33]
MD5 string

Return Value

MD5 sum

httpMD5Final

Combine the MD5 sum of the username, group, and password with the server-supplied nonce value, method, and request-uri.

char *httpMD5Final (
    const char *nonce,
    const char *method,
    const char *resource,
    char md5[33]
);

Parameters

nonce
Server nonce value
method
METHOD (GET, POST, etc.)
resource
Resource path
md5[33]
MD5 sum

Return Value

New sum

httpMD5String

Convert an MD5 sum to a character string.

char *httpMD5String (
    const unsigned char *sum,
    char md5[33]
);

Parameters

sum
MD5 sum data
md5[33]
MD5 sum in hex

Return Value

MD5 sum in hex

httpOptions

Send an OPTIONS request to the server.

int httpOptions (
    http_t *http,
    const char *uri
);

Parameters

http
HTTP connection
uri
URI for options

Return Value

Status of call (0 = success)

 CUPS 1.7/macOS 10.9 httpPeek

Peek at data from a HTTP connection.

ssize_t httpPeek (
    http_t *http,
    char *buffer,
    size_t length
);

Parameters

http
HTTP connection
buffer
Buffer for data
length
Maximum number of bytes

Return Value

Number of bytes copied

Discussion

This function copies available data from the given HTTP connection, reading a buffer as needed. The data is still available for reading using httpRead or httpRead2.

For non-blocking connections the usual timeouts apply.

httpPost

Send a POST request to the server.

int httpPost (
    http_t *http,
    const char *uri
);

Parameters

http
HTTP connection
uri
URI for post

Return Value

Status of call (0 = success)

httpPut

Send a PUT request to the server.

int httpPut (
    http_t *http,
    const char *uri
);

Parameters

http
HTTP connection
uri
URI to put

Return Value

Status of call (0 = success)

 DEPRECATED httpRead

Read data from a HTTP connection.

int httpRead (
    http_t *http,
    char *buffer,
    int length
);

Parameters

http
HTTP connection
buffer
Buffer for data
length
Maximum number of bytes

Return Value

Number of bytes read

Discussion

This function is deprecated. Use the httpRead2() function which can read more than 2GB of data.

 CUPS 1.2/macOS 10.5 httpRead2

Read data from a HTTP connection.

ssize_t httpRead2 (
    http_t *http,
    char *buffer,
    size_t length
);

Parameters

http
HTTP connection
buffer
Buffer for data
length
Maximum number of bytes

Return Value

Number of bytes read

 CUPS 1.7/macOS 10.9 httpReadRequest

Read a HTTP request from a connection.

http_state_t httpReadRequest (
    http_t *http,
    char *uri,
    size_t urilen
);

Parameters

http
HTTP connection
uri
URI buffer
urilen
Size of URI buffer

Return Value

New state of connection

 DEPRECATED httpReconnect

Reconnect to a HTTP server.

int httpReconnect (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

0 on success, non-zero on failure

Discussion

This function is deprecated. Please use the httpReconnect2 function instead.

httpReconnect2

Reconnect to a HTTP server with timeout and optional cancel.

int httpReconnect2 (
    http_t *http,
    int msec,
    int *cancel
);

Parameters

http
HTTP connection
msec
Timeout in milliseconds
cancel
Pointer to "cancel" variable

Return Value

0 on success, non-zero on failure

 CUPS 2.0/OS 10.10 httpResolveHostname

Resolve the hostname of the HTTP connection address.

const char *httpResolveHostname (
    http_t *http,
    char *buffer,
    size_t bufsize
);

Parameters

http
HTTP connection
buffer
Hostname buffer
bufsize
Size of buffer

Return Value

Resolved hostname or NULL

httpSaveCredentials

int httpSaveCredentials (
    const char *path,
    cups_array_t *credentials,
    const char *common_name
);

Parameters

path
credentials
common_name

Return Value

 DEPRECATED httpSeparate

Separate a Universal Resource Identifier into its components.

void httpSeparate (
    const char *uri,
    char *scheme,
    char *username,
    char *host,
    int *port,
    char *resource
);

Parameters

uri
Universal Resource Identifier
scheme
Scheme [32] (http, https, etc.)
username
Username [1024]
host
Hostname [1024]
port
Port number to use
resource
Resource/filename [1024]

Discussion

This function is deprecated; use the httpSeparateURI() function instead.

 CUPS 1.1.21/macOS 10.4 httpSeparate2

Separate a Universal Resource Identifier into its components.

void httpSeparate2 (
    const char *uri,
    char *scheme,
    int schemelen,
    char *username,
    int usernamelen,
    char *host,
    int hostlen,
    int *port,
    char *resource,
    int resourcelen
);

Parameters

uri
Universal Resource Identifier
scheme
Scheme (http, https, etc.)
schemelen
Size of scheme buffer
username
Username
usernamelen
Size of username buffer
host
Hostname
hostlen
Size of hostname buffer
port
Port number to use
resource
Resource/filename
resourcelen
Size of resource buffer

Discussion

This function is deprecated; use the httpSeparateURI() function instead.

 CUPS 1.2/macOS 10.5 httpSeparateURI

Separate a Universal Resource Identifier into its components.

http_uri_status_t httpSeparateURI (
    http_uri_coding_t decoding,
    const char *uri,
    char *scheme,
    int schemelen,
    char *username,
    int usernamelen,
    char *host,
    int hostlen,
    int *port,
    char *resource,
    int resourcelen
);

Parameters

decoding
Decoding flags
uri
Universal Resource Identifier
scheme
Scheme (http, https, etc.)
schemelen
Size of scheme buffer
username
Username
usernamelen
Size of username buffer
host
Hostname
hostlen
Size of hostname buffer
port
Port number to use
resource
Resource/filename
resourcelen
Size of resource buffer

Return Value

Result of separation

 CUPS 1.3/macOS 10.5 httpSetAuthString

Set the current authorization string.

void httpSetAuthString (
    http_t *http,
    const char *scheme,
    const char *data
);

Parameters

http
HTTP connection
scheme
Auth scheme (NULL to clear it)
data
Auth data (NULL for none)

Discussion

This function just stores a copy of the current authorization string in the HTTP connection object. You must still call httpSetField() to set HTTP_FIELD_AUTHORIZATION prior to issuing a HTTP request using httpGet(), httpHead(), httpOptions(), httpPost, or httpPut().

 CUPS 1.1.19/macOS 10.3 httpSetCookie

Set the cookie value(s).

void httpSetCookie (
    http_t *http,
    const char *cookie
);

Parameters

http
Connection
cookie
Cookie string

 CUPS 1.5/macOS 10.7 httpSetCredentials

Set the credentials associated with an encrypted connection.

int httpSetCredentials (
    http_t *http,
    cups_array_t *credentials
);

Parameters

http
HTTP connection
credentials
Array of credentials

Return Value

Status of call (0 = success)

 CUPS 1.7/macOS 10.9 httpSetDefaultField

Set the default value of an HTTP header.

void httpSetDefaultField (
    http_t *http,
    http_field_t field,
    const char *value
);

Parameters

http
HTTP connection
field
Field index
value
Value

Discussion

Currently only HTTP_FIELD_ACCEPT_ENCODING, HTTP_FIELD_SERVER, and HTTP_FIELD_USER_AGENT can be set.

 CUPS 1.2/macOS 10.5 httpSetExpect

Set the Expect: header in a request.

void httpSetExpect (
    http_t *http,
    http_status_t expect
);

Parameters

http
HTTP connection
expect
HTTP status to expect (HTTP_STATUS_CONTINUE)

Discussion

Currently only HTTP_STATUS_CONTINUE is supported for the "expect" argument.

httpSetField

Set the value of an HTTP header.

void httpSetField (
    http_t *http,
    http_field_t field,
    const char *value
);

Parameters

http
HTTP connection
field
Field index
value
Value

 CUPS 2.0/OS 10.10 httpSetKeepAlive

Set the current Keep-Alive state of a connection.

void httpSetKeepAlive (
    http_t *http,
    http_keepalive_t keep_alive
);

Parameters

http
HTTP connection
keep_alive
New Keep-Alive value

 CUPS 1.2/macOS 10.5 httpSetLength

Set the content-length and content-encoding.

void httpSetLength (
    http_t *http,
    size_t length
);

Parameters

http
HTTP connection
length
Length (0 for chunked)

 CUPS 1.5/macOS 10.7 httpSetTimeout

Set read/write timeouts and an optional callback.

void httpSetTimeout (
    http_t *http,
    double timeout,
    http_timeout_cb_t cb,
    void *user_data
);

Parameters

http
HTTP connection
timeout
Number of seconds for timeout, must be greater than 0
cb
Callback function or NULL
user_data
User data pointer

Discussion

The optional timeout callback receives both the HTTP connection and a user data pointer and must return 1 to continue or 0 to error (time) out.

 CUPS 2.0/OS 10.10 httpShutdown

Shutdown one side of an HTTP connection.

void httpShutdown (
    http_t *http
);

Parameters

http
HTTP connection

 CUPS 2.0/OS 10.10 httpStateString

Return the string describing a HTTP state value.

const char *httpStateString (
    http_state_t state
);

Parameters

state
HTTP state value

Return Value

State string

httpStatus

Return a short string describing a HTTP status code.

const char *httpStatus (
    http_status_t status
);

Parameters

status
HTTP status code

Return Value

Localized status string

Discussion

The returned string is localized to the current POSIX locale and is based on the status strings defined in RFC 2616.

httpTrace

Send an TRACE request to the server.

int httpTrace (
    http_t *http,
    const char *uri
);

Parameters

http
HTTP connection
uri
URI for trace

Return Value

Status of call (0 = success)

 CUPS 2.0/OS 10.10 httpURIStatusString

Return a string describing a URI status code.

const char *httpURIStatusString (
    http_uri_status_t status
);

Parameters

status
URI status code

Return Value

Localized status string

httpUpdate

Update the current HTTP state for incoming data.

http_status_t httpUpdate (
    http_t *http
);

Parameters

http
HTTP connection

Return Value

HTTP status

 CUPS 1.1.19/macOS 10.3 httpWait

Wait for data available on a connection.

int httpWait (
    http_t *http,
    int msec
);

Parameters

http
HTTP connection
msec
Milliseconds to wait

Return Value

1 if data is available, 0 otherwise

 DEPRECATED httpWrite

Write data to a HTTP connection.

int httpWrite (
    http_t *http,
    const char *buffer,
    int length
);

Parameters

http
HTTP connection
buffer
Buffer for data
length
Number of bytes to write

Return Value

Number of bytes written

Discussion

This function is deprecated. Use the httpWrite2() function which can write more than 2GB of data.

 CUPS 1.2/macOS 10.5 httpWrite2

Write data to a HTTP connection.

ssize_t httpWrite2 (
    http_t *http,
    const char *buffer,
    size_t length
);

Parameters

http
HTTP connection
buffer
Buffer for data
length
Number of bytes to write

Return Value

Number of bytes written

 CUPS 1.7/macOS 10.9 httpWriteResponse

Write a HTTP response to a client connection.

int httpWriteResponse (
    http_t *http,
    http_status_t status
);

Parameters

http
HTTP connection
status
Status code

Return Value

0 on success, -1 on error

ippAddBoolean

Add a boolean attribute to an IPP message.

ipp_attribute_t *ippAddBoolean (
    ipp_t *ipp,
    ipp_tag_t group,
    const char *name,
    char value
);

Parameters

ipp
IPP message
group
IPP group
name
Name of attribute
value
Value of attribute

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

ippAddBooleans

Add an array of boolean values.

ipp_attribute_t *ippAddBooleans (
    ipp_t *ipp,
    ipp_tag_t group,
    const char *name,
    int num_values,
    const char *values
);

Parameters

ipp
IPP message
group
IPP group
name
Name of attribute
num_values
Number of values
values
Values

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

 CUPS 1.1.19/macOS 10.3 ippAddCollection

Add a collection value.

ipp_attribute_t *ippAddCollection (
    ipp_t *ipp,
    ipp_tag_t group,
    const char *name,
    ipp_t *value
);

Parameters

ipp
IPP message
group
IPP group
name
Name of attribute
value
Value

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

 CUPS 1.1.19/macOS 10.3 ippAddCollections

Add an array of collection values.

ipp_attribute_t *ippAddCollections (
    ipp_t *ipp,
    ipp_tag_t group,
    const char *name,
    int num_values,
    const ipp_t **values
);

Parameters

ipp
IPP message
group
IPP group
name
Name of attribute
num_values
Number of values
values
Values

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

ippAddDate

Add a date attribute to an IPP message.

ipp_attribute_t *ippAddDate (
    ipp_t *ipp,
    ipp_tag_t group,
    const char *name,
    const ipp_uchar_t *value
);

Parameters

ipp
IPP message
group
IPP group
name
Name of attribute
value
Value

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

ippAddInteger

Add a integer attribute to an IPP message.

ipp_attribute_t *ippAddInteger (
    ipp_t *ipp,
    ipp_tag_t group,
    ipp_tag_t value_tag,
    const char *name,
    int value
);

Parameters

ipp
IPP message
group
IPP group
value_tag
Type of attribute
name
Name of attribute
value
Value of attribute

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

Supported values include enum (IPP_TAG_ENUM) and integer (IPP_TAG_INTEGER).

ippAddIntegers

Add an array of integer values.

ipp_attribute_t *ippAddIntegers (
    ipp_t *ipp,
    ipp_tag_t group,
    ipp_tag_t value_tag,
    const char *name,
    int num_values,
    const int *values
);

Parameters

ipp
IPP message
group
IPP group
value_tag
Type of attribute
name
Name of attribute
num_values
Number of values
values
Values

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

Supported values include enum (IPP_TAG_ENUM) and integer (IPP_TAG_INTEGER).

 CUPS 1.2/macOS 10.5 ippAddOctetString

Add an octetString value to an IPP message.

ipp_attribute_t *ippAddOctetString (
    ipp_t *ipp,
    ipp_tag_t group,
    const char *name,
    const void *data,
    int datalen
);

Parameters

ipp
IPP message
group
IPP group
name
Name of attribute
data
octetString data
datalen
Length of data in bytes

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

 CUPS 1.6/macOS 10.8 ippAddOutOfBand

Add an out-of-band value to an IPP message.

ipp_attribute_t *ippAddOutOfBand (
    ipp_t *ipp,
    ipp_tag_t group,
    ipp_tag_t value_tag,
    const char *name
);

Parameters

ipp
IPP message
group
IPP group
value_tag
Type of attribute
name
Name of attribute

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

Supported out-of-band values include unsupported-value (IPP_TAG_UNSUPPORTED_VALUE), default (IPP_TAG_DEFAULT), unknown (IPP_TAG_UNKNOWN), no-value (IPP_TAG_NOVALUE), not-settable (IPP_TAG_NOTSETTABLE), delete-attribute (IPP_TAG_DELETEATTR), and admin-define (IPP_TAG_ADMINDEFINE).

ippAddRange

Add a range of values to an IPP message.

ipp_attribute_t *ippAddRange (
    ipp_t *ipp,
    ipp_tag_t group,
    const char *name,
    int lower,
    int upper
);

Parameters

ipp
IPP message
group
IPP group
name
Name of attribute
lower
Lower value
upper
Upper value

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

The lower parameter must be less than or equal to the upper parameter.

ippAddRanges

Add ranges of values to an IPP message.

ipp_attribute_t *ippAddRanges (
    ipp_t *ipp,
    ipp_tag_t group,
    const char *name,
    int num_values,
    const int *lower,
    const int *upper
);

Parameters

ipp
IPP message
group
IPP group
name
Name of attribute
num_values
Number of values
lower
Lower values
upper
Upper values

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

ippAddResolution

Add a resolution value to an IPP message.

ipp_attribute_t *ippAddResolution (
    ipp_t *ipp,
    ipp_tag_t group,
    const char *name,
    ipp_res_t units,
    int xres,
    int yres
);

Parameters

ipp
IPP message
group
IPP group
name
Name of attribute
units
Units for resolution
xres
X resolution
yres
Y resolution

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

ippAddResolutions

Add resolution values to an IPP message.

ipp_attribute_t *ippAddResolutions (
    ipp_t *ipp,
    ipp_tag_t group,
    const char *name,
    int num_values,
    ipp_res_t units,
    const int *xres,
    const int *yres
);

Parameters

ipp
IPP message
group
IPP group
name
Name of attribute
num_values
Number of values
units
Units for resolution
xres
X resolutions
yres
Y resolutions

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

ippAddSeparator

Add a group separator to an IPP message.

ipp_attribute_t *ippAddSeparator (
    ipp_t *ipp
);

Parameters

ipp
IPP message

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

ippAddString

Add a language-encoded string to an IPP message.

ipp_attribute_t *ippAddString (
    ipp_t *ipp,
    ipp_tag_t group,
    ipp_tag_t value_tag,
    const char *name,
    const char *language,
    const char *value
);

Parameters

ipp
IPP message
group
IPP group
value_tag
Type of attribute
name
Name of attribute
language
Language code
value
Value

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

Supported string values include charset (IPP_TAG_CHARSET), keyword (IPP_TAG_KEYWORD), language (IPP_TAG_LANGUAGE), mimeMediaType (IPP_TAG_MIMETYPE), name (IPP_TAG_NAME), nameWithLanguage (IPP_TAG_NAMELANG), text (code IPP_TAG_TEXT@), textWithLanguage (IPP_TAG_TEXTLANG), uri (IPP_TAG_URI), and uriScheme (IPP_TAG_URISCHEME).

The language parameter must be non-NULL for nameWithLanguage and textWithLanguage string values and must be NULL for all other string values.

 CUPS 1.7/macOS 10.9 ippAddStringf

Add a formatted string to an IPP message.

ipp_attribute_t *ippAddStringf (
    ipp_t *ipp,
    ipp_tag_t group,
    ipp_tag_t value_tag,
    const char *name,
    const char *language,
    const char *format,
    ...
);

Parameters

ipp
IPP message
group
IPP group
value_tag
Type of attribute
name
Name of attribute
language
Language code (NULL for default)
format
Printf-style format string
...
Additional arguments as needed

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

Supported string values include charset (IPP_TAG_CHARSET), keyword (IPP_TAG_KEYWORD), language (IPP_TAG_LANGUAGE), mimeMediaType (IPP_TAG_MIMETYPE), name (IPP_TAG_NAME), nameWithLanguage (IPP_TAG_NAMELANG), text (code IPP_TAG_TEXT@), textWithLanguage (IPP_TAG_TEXTLANG), uri (IPP_TAG_URI), and uriScheme (IPP_TAG_URISCHEME).

The language parameter must be non-NULL for nameWithLanguage and textWithLanguage string values and must be NULL for all other string values.

The format parameter uses formatting characters compatible with the printf family of standard functions. Additional arguments follow it as needed. The formatted string is truncated as needed to the maximum length of the corresponding value type.

 CUPS 1.7/macOS 10.9 ippAddStringfv

Add a formatted string to an IPP message.

ipp_attribute_t *ippAddStringfv (
    ipp_t *ipp,
    ipp_tag_t group,
    ipp_tag_t value_tag,
    const char *name,
    const char *language,
    const char *format,
    va_list ap
);

Parameters

ipp
IPP message
group
IPP group
value_tag
Type of attribute
name
Name of attribute
language
Language code (NULL for default)
format
Printf-style format string
ap
Additional arguments

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

Supported string values include charset (IPP_TAG_CHARSET), keyword (IPP_TAG_KEYWORD), language (IPP_TAG_LANGUAGE), mimeMediaType (IPP_TAG_MIMETYPE), name (IPP_TAG_NAME), nameWithLanguage (IPP_TAG_NAMELANG), text (code IPP_TAG_TEXT@), textWithLanguage (IPP_TAG_TEXTLANG), uri (IPP_TAG_URI), and uriScheme (IPP_TAG_URISCHEME).

The language parameter must be non-NULL for nameWithLanguage and textWithLanguage string values and must be NULL for all other string values.

The format parameter uses formatting characters compatible with the printf family of standard functions. Additional arguments are passed in the stdarg pointer ap. The formatted string is truncated as needed to the maximum length of the corresponding value type.

ippAddStrings

Add language-encoded strings to an IPP message.

ipp_attribute_t *ippAddStrings (
    ipp_t *ipp,
    ipp_tag_t group,
    ipp_tag_t value_tag,
    const char *name,
    int num_values,
    const char *language,
    const char *const *values
);

Parameters

ipp
IPP message
group
IPP group
value_tag
Type of attribute
name
Name of attribute
num_values
Number of values
language
Language code (NULL for default)
values
Values

Return Value

New attribute

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

Supported string values include charset (IPP_TAG_CHARSET), keyword (IPP_TAG_KEYWORD), language (IPP_TAG_LANGUAGE), mimeMediaType (IPP_TAG_MIMETYPE), name (IPP_TAG_NAME), nameWithLanguage (IPP_TAG_NAMELANG), text (code IPP_TAG_TEXT@), textWithLanguage (IPP_TAG_TEXTLANG), uri (IPP_TAG_URI), and uriScheme (IPP_TAG_URISCHEME).

The language parameter must be non-NULL for nameWithLanguage and textWithLanguage string values and must be NULL for all other string values.

 CUPS 1.6/macOS 10.8 ippAttributeString

Convert the attribute's value to a string.

size_t ippAttributeString (
    ipp_attribute_t *attr,
    char *buffer,
    size_t bufsize
);

Parameters

attr
Attribute
buffer
String buffer or NULL
bufsize
Size of string buffer

Return Value

Number of bytes less nul

Discussion

Returns the number of bytes that would be written, not including the trailing nul. The buffer pointer can be NULL to get the required length, just like (v)snprintf.

 CUPS 1.7/macOS 10.9 ippContainsInteger

Determine whether an attribute contains the specified value or is within the list of ranges.

int ippContainsInteger (
    ipp_attribute_t *attr,
    int value
);

Parameters

attr
Attribute
value
Integer/enum value

Return Value

1 on a match, 0 on no match

Discussion

Returns non-zero when the attribute contains either a matching integer or enum value, or the value falls within one of the rangeOfInteger values for the attribute.

 CUPS 1.7/macOS 10.9 ippContainsString

Determine whether an attribute contains the specified string value.

int ippContainsString (
    ipp_attribute_t *attr,
    const char *value
);

Parameters

attr
Attribute
value
String value

Return Value

1 on a match, 0 on no match

Discussion

Returns non-zero when the attribute contains a matching charset, keyword, language, mimeMediaType, name, text, URI, or URI scheme value.

 CUPS 1.6/macOS 10.8 ippCopyAttribute

Copy an attribute.

ipp_attribute_t *ippCopyAttribute (
    ipp_t *dst,
    ipp_attribute_t *srcattr,
    int quickcopy
);

Parameters

dst
Destination IPP message
srcattr
Attribute to copy
quickcopy
1 for a referenced copy, 0 for normal

Return Value

New attribute

Discussion

The specified attribute, attr, is copied to the destination IPP message. When quickcopy is non-zero, a "shallow" reference copy of the attribute is created - this should only be done as long as the original source IPP message will not be freed for the life of the destination.

 CUPS 1.6/macOS 10.8 ippCopyAttributes

Copy attributes from one IPP message to another.

int ippCopyAttributes (
    ipp_t *dst,
    ipp_t *src,
    int quickcopy,
    ipp_copycb_t cb,
    void *context
);

Parameters

dst
Destination IPP message
src
Source IPP message
quickcopy
1 for a referenced copy, 0 for normal
cb
Copy callback or NULL for none
context
Context pointer

Return Value

1 on success, 0 on error

Discussion

Zero or more attributes are copied from the source IPP message, src, to the destination IPP message, dst. When quickcopy is non-zero, a "shallow" reference copy of the attribute is created - this should only be done as long as the original source IPP message will not be freed for the life of the destination.

The cb and context parameters provide a generic way to "filter" the attributes that are copied - the function must return 1 to copy the attribute or 0 to skip it. The function may also choose to do a partial copy of the source attribute itself.

 CUPS 1.7/macOS 10.9 ippCreateRequestedArray

Create a CUPS array of attribute names from the given requested-attributes attribute.

cups_array_t *ippCreateRequestedArray (
    ipp_t *request
);

Parameters

request
IPP request

Return Value

CUPS array or NULL if all

Discussion

This function creates a (sorted) CUPS array of attribute names matching the list of "requested-attribute" values supplied in an IPP request. All IANA- registered values are supported in addition to the CUPS IPP extension attributes.

The request parameter specifies the request message that was read from the client. NULL is returned if all attributes should be returned. Otherwise, the result is a sorted array of attribute names, where cupsArrayFind(array, "attribute-name") will return a non-NULL pointer. The array must be freed using the cupsArrayDelete function.

ippDateToTime

Convert from RFC 1903 Date/Time format to UNIX time in seconds.

time_t ippDateToTime (
    const ipp_uchar_t *date
);

Parameters

date
RFC 1903 date info

Return Value

UNIX time value

ippDelete

Delete an IPP message.

void ippDelete (
    ipp_t *ipp
);

Parameters

ipp
IPP message

 CUPS 1.1.19/macOS 10.3 ippDeleteAttribute

Delete a single attribute in an IPP message.

void ippDeleteAttribute (
    ipp_t *ipp,
    ipp_attribute_t *attr
);

Parameters

ipp
IPP message
attr
Attribute to delete

 CUPS 1.6/macOS 10.8 ippDeleteValues

Delete values in an attribute.

int ippDeleteValues (
    ipp_t *ipp,
    ipp_attribute_t **attr,
    int element,
    int count
);

Parameters

ipp
IPP message
attr
Attribute
element
Index of first value to delete (0-based)
count
Number of values to delete

Return Value

1 on success, 0 on failure

Discussion

The element parameter specifies the first value to delete, starting at 0. It must be less than the number of values returned by ippGetCount.

The attr parameter may be modified as a result of setting the value.

Deleting all values in an attribute deletes the attribute.

ippEnumString

Return a string corresponding to the enum value.

const char *ippEnumString (
    const char *attrname,
    int enumvalue
);

Parameters

attrname
Attribute name
enumvalue
Enum value

Return Value

Enum string

ippEnumValue

Return the value associated with a given enum string.

int ippEnumValue (
    const char *attrname,
    const char *enumstring
);

Parameters

attrname
Attribute name
enumstring
Enum string

Return Value

Enum value or -1 if unknown

ippErrorString

Return a name for the given status code.

const char *ippErrorString (
    ipp_status_t error
);

Parameters

error
Error status

Return Value

Text string

 CUPS 1.2/macOS 10.5 ippErrorValue

Return a status code for the given name.

ipp_status_t ippErrorValue (
    const char *name
);

Parameters

name
Name

Return Value

IPP status code

ippFindAttribute

Find a named attribute in a request.

ipp_attribute_t *ippFindAttribute (
    ipp_t *ipp,
    const char *name,
    ipp_tag_t type
);

Parameters

ipp
IPP message
name
Name of attribute
type
Type of attribute

Return Value

Matching attribute

Discussion

Starting with CUPS 2.0, the attribute name can contain a hierarchical list of attribute and member names separated by slashes, for example "media-col/media-size".

ippFindNextAttribute

Find the next named attribute in a request.

ipp_attribute_t *ippFindNextAttribute (
    ipp_t *ipp,
    const char *name,
    ipp_tag_t type
);

Parameters

ipp
IPP message
name
Name of attribute
type
Type of attribute

Return Value

Matching attribute

Discussion

Starting with CUPS 2.0, the attribute name can contain a hierarchical list of attribute and member names separated by slashes, for example "media-col/media-size".

 CUPS 1.6/macOS 10.8 ippFirstAttribute

Return the first attribute in the message.

ipp_attribute_t *ippFirstAttribute (
    ipp_t *ipp
);

Parameters

ipp
IPP message

Return Value

First attribute or NULL if none

 CUPS 1.6/macOS 10.8 ippGetBoolean

Get a boolean value for an attribute.

int ippGetBoolean (
    ipp_attribute_t *attr,
    int element
);

Parameters

attr
IPP attribute
element
Value number (0-based)

Return Value

Boolean value or 0 on error

Discussion

The element parameter specifies which value to get from 0 to ippGetCount(attr) - 1.

 CUPS 1.6/macOS 10.8 ippGetCollection

Get a collection value for an attribute.

ipp_t *ippGetCollection (
    ipp_attribute_t *attr,
    int element
);

Parameters

attr
IPP attribute
element
Value number (0-based)

Return Value

Collection value or NULL on error

Discussion

The element parameter specifies which value to get from 0 to ippGetCount(attr) - 1.

 CUPS 1.6/macOS 10.8 ippGetCount

Get the number of values in an attribute.

int ippGetCount (
    ipp_attribute_t *attr
);

Parameters

attr
IPP attribute

Return Value

Number of values or 0 on error

 CUPS 1.6/macOS 10.8 ippGetDate

Get a date value for an attribute.

const ipp_uchar_t *ippGetDate (
    ipp_attribute_t *attr,
    int element
);

Parameters

attr
IPP attribute
element
Value number (0-based)

Return Value

Date value or NULL

Discussion

The element parameter specifies which value to get from 0 to ippGetCount(attr) - 1.

 CUPS 1.6/macOS 10.8 ippGetGroupTag

Get the group associated with an attribute.

ipp_tag_t ippGetGroupTag (
    ipp_attribute_t *attr
);

Parameters

attr
IPP attribute

Return Value

Group tag or IPP_TAG_ZERO on error

 CUPS 1.6/macOS 10.8 ippGetInteger

Get the integer/enum value for an attribute.

int ippGetInteger (
    ipp_attribute_t *attr,
    int element
);

Parameters

attr
IPP attribute
element
Value number (0-based)

Return Value

Value or 0 on error

Discussion

The element parameter specifies which value to get from 0 to ippGetCount(attr) - 1.

 CUPS 1.6/macOS 10.8 ippGetName

Get the attribute name.

const char *ippGetName (
    ipp_attribute_t *attr
);

Parameters

attr
IPP attribute

Return Value

Attribute name or NULL for separators

 CUPS 1.7/macOS 10.9 ippGetOctetString

Get an octetString value from an IPP attribute.

void *ippGetOctetString (
    ipp_attribute_t *attr,
    int element,
    int *datalen
);

Parameters

attr
IPP attribute
element
Value number (0-based)
datalen
Length of octetString data

Return Value

Pointer to octetString data

Discussion

The element parameter specifies which value to get from 0 to ippGetCount(attr) - 1.

 CUPS 1.6/macOS 10.8 ippGetOperation

Get the operation ID in an IPP message.

ipp_op_t ippGetOperation (
    ipp_t *ipp
);

Parameters

ipp
IPP request message

Return Value

Operation ID or 0 on error

 CUPS 1.6/macOS 10.8 ippGetRange

Get a rangeOfInteger value from an attribute.

int ippGetRange (
    ipp_attribute_t *attr,
    int element,
    int *uppervalue
);

Parameters

attr
IPP attribute
element
Value number (0-based)
uppervalue
Upper value of range

Return Value

Lower value of range or 0

Discussion

The element parameter specifies which value to get from 0 to ippGetCount(attr) - 1.

 CUPS 1.6/macOS 10.8 ippGetRequestId

Get the request ID from an IPP message.

int ippGetRequestId (
    ipp_t *ipp
);

Parameters

ipp
IPP message

Return Value

Request ID or 0 on error

 CUPS 1.6/macOS 10.8 ippGetResolution

Get a resolution value for an attribute.

int ippGetResolution (
    ipp_attribute_t *attr,
    int element,
    int *yres,
    ipp_res_t *units
);

Parameters

attr
IPP attribute
element
Value number (0-based)
yres
Vertical/feed resolution
units
Units for resolution

Return Value

Horizontal/cross feed resolution or 0

Discussion

The element parameter specifies which value to get from 0 to ippGetCount(attr) - 1.

 CUPS 1.6/macOS 10.8 ippGetState

Get the IPP message state.

ipp_state_t ippGetState (
    ipp_t *ipp
);

Parameters

ipp
IPP message

Return Value

IPP message state value

 CUPS 1.6/macOS 10.8 ippGetStatusCode

Get the status code from an IPP response or event message.

ipp_status_t ippGetStatusCode (
    ipp_t *ipp
);

Parameters

ipp
IPP response or event message

Return Value

Status code in IPP message

ippGetString

Return the value...

const char *ippGetString (
    ipp_attribute_t *attr,
    int element,
    const char **language
);

Parameters

attr
IPP attribute
element
Value number (0-based)
language
Language code (NULL for don't care)

Return Value

Get the string and optionally the language code for an attribute.

The element parameter specifies which value to get from 0 to ippGetCount(attr) - 1.

 CUPS 1.6/macOS 10.8 ippGetValueTag

Get the value tag for an attribute.

ipp_tag_t ippGetValueTag (
    ipp_attribute_t *attr
);

Parameters

attr
IPP attribute

Return Value

Value tag or IPP_TAG_ZERO on error

 CUPS 1.6/macOS 10.8 ippGetVersion

Get the major and minor version number from an IPP message.

int ippGetVersion (
    ipp_t *ipp,
    int *minor
);

Parameters

ipp
IPP message
minor
Minor version number or NULL

Return Value

Major version number or 0 on error

ippLength

Compute the length of an IPP message.

size_t ippLength (
    ipp_t *ipp
);

Parameters

ipp
IPP message

Return Value

Size of IPP message

ippNew

Allocate a new IPP message.

ipp_t *ippNew (void);

Return Value

New IPP message

 CUPS 1.2/macOS 10.5 ippNewRequest

Allocate a new IPP request message.

ipp_t *ippNewRequest (
    ipp_op_t op
);

Parameters

op
Operation code

Return Value

IPP request message

Discussion

The new request message is initialized with the attributes-charset and attributes-natural-language attributes added. The attributes-natural-language value is derived from the current locale.

 CUPS 1.7/macOS 10.9 ippNewResponse

Allocate a new IPP response message.

ipp_t *ippNewResponse (
    ipp_t *request
);

Parameters

request
IPP request message

Return Value

IPP response message

Discussion

The new response message is initialized with the same version-number, request-id, attributes-charset, and attributes-natural-language as the provided request message. If the attributes-charset or attributes-natural-language attributes are missing from the request, "utf-8" and a value derived from the current locale are substituted, respectively.

 CUPS 1.6/macOS 10.8 ippNextAttribute

Return the next attribute in the message.

ipp_attribute_t *ippNextAttribute (
    ipp_t *ipp
);

Parameters

ipp
IPP message

Return Value

Next attribute or NULL if none

 CUPS 1.2/macOS 10.5 ippOpString

Return a name for the given operation id.

const char *ippOpString (
    ipp_op_t op
);

Parameters

op
Operation ID

Return Value

Name

 CUPS 1.2/macOS 10.5 ippOpValue

Return an operation id for the given name.

ipp_op_t ippOpValue (
    const char *name
);

Parameters

name
Textual name

Return Value

Operation ID

ippPort

Return the default IPP port number.

int ippPort (void);

Return Value

Port number

ippRead

Read data for an IPP message from a HTTP connection.

ipp_state_t ippRead (
    http_t *http,
    ipp_t *ipp
);

Parameters

http
HTTP connection
ipp
IPP data

Return Value

Current state

 CUPS 1.1.19/macOS 10.3 ippReadFile

Read data for an IPP message from a file.

ipp_state_t ippReadFile (
    int fd,
    ipp_t *ipp
);

Parameters

fd
HTTP data
ipp
IPP data

Return Value

Current state

 CUPS 1.2/macOS 10.5 ippReadIO

Read data for an IPP message.

ipp_state_t ippReadIO (
    void *src,
    ipp_iocb_t cb,
    int blocking,
    ipp_t *parent,
    ipp_t *ipp
);

Parameters

src
Data source
cb
Read callback function
blocking
Use blocking IO?
parent
Parent request, if any
ipp
IPP data

Return Value

Current state

 CUPS 1.6/macOS 10.8 ippSetBoolean

Set a boolean value in an attribute.

int ippSetBoolean (
    ipp_t *ipp,
    ipp_attribute_t **attr,
    int element,
    int boolvalue
);

Parameters

ipp
IPP message
attr
IPP attribute
element
Value number (0-based)
boolvalue
Boolean value

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The attr parameter may be modified as a result of setting the value.

The element parameter specifies which value to set from 0 to ippGetCount(attr).

 CUPS 1.6/macOS 10.8 ippSetCollection

Set a collection value in an attribute.

int ippSetCollection (
    ipp_t *ipp,
    ipp_attribute_t **attr,
    int element,
    ipp_t *colvalue
);

Parameters

ipp
IPP message
attr
IPP attribute
element
Value number (0-based)
colvalue
Collection value

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The attr parameter may be modified as a result of setting the value.

The element parameter specifies which value to set from 0 to ippGetCount(attr).

 CUPS 1.6/macOS 10.8 ippSetDate

Set a date value in an attribute.

int ippSetDate (
    ipp_t *ipp,
    ipp_attribute_t **attr,
    int element,
    const ipp_uchar_t *datevalue
);

Parameters

ipp
IPP message
attr
IPP attribute
element
Value number (0-based)
datevalue
Date value

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The attr parameter may be modified as a result of setting the value.

The element parameter specifies which value to set from 0 to ippGetCount(attr).

 CUPS 1.6/macOS 10.8 ippSetGroupTag

Set the group tag of an attribute.

int ippSetGroupTag (
    ipp_t *ipp,
    ipp_attribute_t **attr,
    ipp_tag_t group_tag
);

Parameters

ipp
IPP message
attr
Attribute
group_tag
Group tag

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The attr parameter may be modified as a result of setting the value.

The group parameter specifies the IPP attribute group tag: none (IPP_TAG_ZERO, for member attributes), document (IPP_TAG_DOCUMENT), event notification (IPP_TAG_EVENT_NOTIFICATION), operation (IPP_TAG_OPERATION), printer (IPP_TAG_PRINTER), subscription (IPP_TAG_SUBSCRIPTION), or unsupported (IPP_TAG_UNSUPPORTED_GROUP).

 CUPS 1.6/macOS 10.8 ippSetInteger

Set an integer or enum value in an attribute.

int ippSetInteger (
    ipp_t *ipp,
    ipp_attribute_t **attr,
    int element,
    int intvalue
);

Parameters

ipp
IPP message
attr
IPP attribute
element
Value number (0-based)
intvalue
Integer/enum value

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The attr parameter may be modified as a result of setting the value.

The element parameter specifies which value to set from 0 to ippGetCount(attr).

 CUPS 1.6/macOS 10.8 ippSetName

Set the name of an attribute.

int ippSetName (
    ipp_t *ipp,
    ipp_attribute_t **attr,
    const char *name
);

Parameters

ipp
IPP message
attr
IPP attribute
name
Attribute name

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The attr parameter may be modified as a result of setting the value.

 CUPS 1.7/macOS 10.9 ippSetOctetString

Set an octetString value in an IPP attribute.

int ippSetOctetString (
    ipp_t *ipp,
    ipp_attribute_t **attr,
    int element,
    const void *data,
    int datalen
);

Parameters

ipp
IPP message
attr
IPP attribute
element
Value number (0-based)
data
Pointer to octetString data
datalen
Length of octetString data

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The attr parameter may be modified as a result of setting the value.

The element parameter specifies which value to set from 0 to ippGetCount(attr).

 CUPS 1.6/macOS 10.8 ippSetOperation

Set the operation ID in an IPP request message.

int ippSetOperation (
    ipp_t *ipp,
    ipp_op_t op
);

Parameters

ipp
IPP request message
op
Operation ID

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

ippSetPort

Set the default port number.

void ippSetPort (
    int p
);

Parameters

p
Port number to use

 CUPS 1.6/macOS 10.8 ippSetRange

Set a rangeOfInteger value in an attribute.

int ippSetRange (
    ipp_t *ipp,
    ipp_attribute_t **attr,
    int element,
    int lowervalue,
    int uppervalue
);

Parameters

ipp
IPP message
attr
IPP attribute
element
Value number (0-based)
lowervalue
Lower bound for range
uppervalue
Upper bound for range

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The attr parameter may be modified as a result of setting the value.

The element parameter specifies which value to set from 0 to ippGetCount(attr).

 CUPS 1.6/macOS 10.8 ippSetRequestId

Set the request ID in an IPP message.

int ippSetRequestId (
    ipp_t *ipp,
    int request_id
);

Parameters

ipp
IPP message
request_id
Request ID

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The request_id parameter must be greater than 0.

 CUPS 1.6/macOS 10.8 ippSetResolution

Set a resolution value in an attribute.

int ippSetResolution (
    ipp_t *ipp,
    ipp_attribute_t **attr,
    int element,
    ipp_res_t unitsvalue,
    int xresvalue,
    int yresvalue
);

Parameters

ipp
IPP message
attr
IPP attribute
element
Value number (0-based)
unitsvalue
Resolution units
xresvalue
Horizontal/cross feed resolution
yresvalue
Vertical/feed resolution

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The attr parameter may be modified as a result of setting the value.

The element parameter specifies which value to set from 0 to ippGetCount(attr).

 CUPS 1.6/macOS 10.8 ippSetState

Set the current state of the IPP message.

int ippSetState (
    ipp_t *ipp,
    ipp_state_t state
);

Parameters

ipp
IPP message
state
IPP state value

Return Value

1 on success, 0 on failure

 CUPS 1.6/macOS 10.8 ippSetStatusCode

Set the status code in an IPP response or event message.

int ippSetStatusCode (
    ipp_t *ipp,
    ipp_status_t status
);

Parameters

ipp
IPP response or event message
status
Status code

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

 CUPS 1.6/macOS 10.8 ippSetString

Set a string value in an attribute.

int ippSetString (
    ipp_t *ipp,
    ipp_attribute_t **attr,
    int element,
    const char *strvalue
);

Parameters

ipp
IPP message
attr
IPP attribute
element
Value number (0-based)
strvalue
String value

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The attr parameter may be modified as a result of setting the value.

The element parameter specifies which value to set from 0 to ippGetCount(attr).

 CUPS 1.7/macOS 10.9 ippSetStringf

Set a formatted string value of an attribute.

int ippSetStringf (
    ipp_t *ipp,
    ipp_attribute_t **attr,
    int element,
    const char *format,
    ...
);

Parameters

ipp
IPP message
attr
IPP attribute
element
Value number (0-based)
format
Printf-style format string
...
Additional arguments as needed

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The attr parameter may be modified as a result of setting the value.

The element parameter specifies which value to set from 0 to ippGetCount(attr).

The format parameter uses formatting characters compatible with the printf family of standard functions. Additional arguments follow it as needed. The formatted string is truncated as needed to the maximum length of the corresponding value type.

 CUPS 1.7/macOS 10.9 ippSetStringfv

Set a formatted string value of an attribute.

int ippSetStringfv (
    ipp_t *ipp,
    ipp_attribute_t **attr,
    int element,
    const char *format,
    va_list ap
);

Parameters

ipp
IPP message
attr
IPP attribute
element
Value number (0-based)
format
Printf-style format string
ap
Pointer to additional arguments

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The attr parameter may be modified as a result of setting the value.

The element parameter specifies which value to set from 0 to ippGetCount(attr).

The format parameter uses formatting characters compatible with the printf family of standard functions. Additional arguments follow it as needed. The formatted string is truncated as needed to the maximum length of the corresponding value type.

 CUPS 1.6/macOS 10.8 ippSetValueTag

Set the value tag of an attribute.

int ippSetValueTag (
    ipp_t *ipp,
    ipp_attribute_t **attr,
    ipp_tag_t value_tag
);

Parameters

ipp
IPP message
attr
IPP attribute
value_tag
Value tag

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The attr parameter may be modified as a result of setting the value.

Integer (IPP_TAG_INTEGER) values can be promoted to rangeOfInteger (IPP_TAG_RANGE) values, the various string tags can be promoted to name (IPP_TAG_NAME) or nameWithLanguage (IPP_TAG_NAMELANG) values, text (IPP_TAG_TEXT) values can be promoted to textWithLanguage (IPP_TAG_TEXTLANG) values, and all values can be demoted to the various out-of-band value tags such as no-value (IPP_TAG_NOVALUE). All other changes will be rejected.

Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language code in the "attributes-natural-language" attribute or, if not present, the language code for the current locale.

 CUPS 1.6/macOS 10.8 ippSetVersion

Set the version number in an IPP message.

int ippSetVersion (
    ipp_t *ipp,
    int major,
    int minor
);

Parameters

ipp
IPP message
major
Major version number (major.minor)
minor
Minor version number (major.minor)

Return Value

1 on success, 0 on failure

Discussion

The ipp parameter refers to an IPP message previously created using the ippNew, ippNewRequest, or ippNewResponse functions.

The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.

 CUPS 2.0/OS 10.10 ippStateString

Return the name corresponding to a state value.

const char *ippStateString (
    ipp_state_t state
);

Parameters

state
State value

Return Value

State name

 CUPS 1.4/macOS 10.6 ippTagString

Return the tag name corresponding to a tag value.

const char *ippTagString (
    ipp_tag_t tag
);

Parameters

tag
Tag value

Return Value

Tag name

Discussion

The returned names are defined in RFC 2911 and 3382.

 CUPS 1.4/macOS 10.6 ippTagValue

Return the tag value corresponding to a tag name.

ipp_tag_t ippTagValue (
    const char *name
);

Parameters

name
Tag name

Return Value

Tag value

Discussion

The tag names are defined in RFC 2911 and 3382.

ippTimeToDate

Convert from UNIX time to RFC 1903 format.

const ipp_uchar_t *ippTimeToDate (
    time_t t
);

Parameters

t
UNIX time value

Return Value

RFC-1903 date/time data

 CUPS 1.7/macOS 10.9 ippValidateAttribute

Validate the contents of an attribute.

int ippValidateAttribute (
    ipp_attribute_t *attr
);

Parameters

attr
Attribute

Return Value

1 if valid, 0 otherwise

Discussion

This function validates the contents of an attribute based on the name and value tag. 1 is returned if the attribute is valid, 0 otherwise. On failure, cupsLastErrorString() is set to a human-readable message.

 CUPS 1.7/macOS 10.9 ippValidateAttributes

Validate all attributes in an IPP message.

int ippValidateAttributes (
    ipp_t *ipp
);

Parameters

ipp
IPP message

Return Value

1 if valid, 0 otherwise

Discussion

This function validates the contents of the IPP message, including each attribute. Like ippValidateAttribute, cupsLastErrorString() is set to a human-readable message on failure.

ippWrite

Write data for an IPP message to a HTTP connection.

ipp_state_t ippWrite (
    http_t *http,
    ipp_t *ipp
);

Parameters

http
HTTP connection
ipp
IPP data

Return Value

Current state

 CUPS 1.1.19/macOS 10.3 ippWriteFile

Write data for an IPP message to a file.

ipp_state_t ippWriteFile (
    int fd,
    ipp_t *ipp
);

Parameters

fd
HTTP data
ipp
IPP data

Return Value

Current state

 CUPS 1.2/macOS 10.5 ippWriteIO

Write data for an IPP message.

ipp_state_t ippWriteIO (
    void *dst,
    ipp_iocb_t cb,
    int blocking,
    ipp_t *parent,
    ipp_t *ipp
);

Parameters

dst
Destination
cb
Write callback function
blocking
Use blocking IO?
parent
Parent IPP message
ipp
IPP data

Return Value

Current state

 CUPS 1.7/macOS 10.9 pwgFormatSizeName

Generate a PWG self-describing media size name.

int pwgFormatSizeName (
    char *keyword,
    size_t keysize,
    const char *prefix,
    const char *name,
    int width,
    int length,
    const char *units
);

Parameters

keyword
Keyword buffer
keysize
Size of keyword buffer
prefix
Prefix for PWG size or NULL for automatic
name
Size name or NULL
width
Width of page in 2540ths
length
Length of page in 2540ths
units
Units - "in", "mm", or NULL for automatic

Return Value

1 on success, 0 on failure

Discussion

This function generates a PWG self-describing media size name of the form "prefix_name_WIDTHxLENGTHunits". The prefix is typically "custom" or "roll" for user-supplied sizes but can also be "disc", "iso", "jis", "jpn", "na", "oe", "om", "prc", or "roc". A value of NULL automatically chooses "oe" or "om" depending on the units.

The size name may only contain lowercase letters, numbers, "-", and ".". If NULL is passed, the size name will contain the formatted dimensions.

The width and length are specified in hundredths of millimeters, equivalent to 1/100000th of a meter or 1/2540th of an inch. The width, length, and units used for the generated size name are calculated automatically if the units string is NULL, otherwise inches ("in") or millimeters ("mm") are used.

 CUPS 1.7/macOS 10.9 pwgInitSize

Initialize a pwg_size_t structure using IPP Job Template attributes.

int pwgInitSize (
    pwg_size_t *size,
    ipp_t *job,
    int *margins_set
);

Parameters

size
Size to initialize
job
Job template attributes
margins_set
1 if margins were set, 0 otherwise

Return Value

1 if size was initialized, 0 otherwise

Discussion

This function initializes a pwg_size_t structure from an IPP "media" or "media-col" attribute in the specified IPP message. 0 is returned if neither attribute is found in the message or the values are not valid.

The "margins_set" variable is initialized to 1 if any "media-xxx-margin" member attribute was specified in the "media-col" Job Template attribute, otherwise it is initialized to 0.

 CUPS 1.7/macOS 10.9 pwgMediaForLegacy

Find a PWG media size by ISO/IPP legacy name.

pwg_media_t *pwgMediaForLegacy (
    const char *legacy
);

Parameters

legacy
Legacy size name

Return Value

Matching size or NULL

Discussion

The "name" argument specifies the legacy ISO media size name, for example "iso-a4" or "na-letter".

 CUPS 1.7/macOS 10.9 pwgMediaForPPD

Find a PWG media size by Adobe PPD name.

pwg_media_t *pwgMediaForPPD (
    const char *ppd
);

Parameters

ppd
PPD size name

Return Value

Matching size or NULL

Discussion

The "ppd" argument specifies an Adobe page size name as defined in Table B.1 of the Adobe PostScript Printer Description File Format Specification Version 4.3.

If the name is non-standard, the returned PWG media size is stored in thread-local storage and is overwritten by each call to the function in the thread. Custom names can be of the form "Custom.WIDTHxLENGTH[units]" or "WIDTHxLENGTH[units]".

 CUPS 1.7/macOS 10.9 pwgMediaForPWG

Find a PWG media size by 5101.1 self-describing name.

pwg_media_t *pwgMediaForPWG (
    const char *pwg
);

Parameters

pwg
PWG size name

Return Value

Matching size or NULL

Discussion

The "pwg" argument specifies a self-describing media size name of the form "prefix_name_WIDTHxLENGTHunits" as defined in PWG 5101.1.

If the name is non-standard, the returned PWG media size is stored in thread-local storage and is overwritten by each call to the function in the thread.

 CUPS 1.7/macOS 10.9 pwgMediaForSize

Get the PWG media size for the given dimensions.

pwg_media_t *pwgMediaForSize (
    int width,
    int length
);

Parameters

width
Width in hundredths of millimeters
length
Length in hundredths of millimeters

Return Value

PWG media name

Discussion

The "width" and "length" are in hundredths of millimeters, equivalent to 1/100000th of a meter or 1/2540th of an inch.

If the dimensions are non-standard, the returned PWG media size is stored in thread-local storage and is overwritten by each call to the function in the thread.

Data Types

cups_adv_t

AdvanceMedia attribute values

typedef enum cups_adv_e cups_adv_t;

cups_bool_t

Boolean type

typedef enum cups_bool_e cups_bool_t;

 CUPS 1.5/macOS 10.7 cups_client_cert_cb_t

Client credentials callback

typedef int (*cups_client_cert_cb_t)(http_t *http, void *tls, cups_array_t *distinguished_names, void *user_data);

cups_cspace_t

cupsColorSpace attribute values

typedef enum cups_cspace_e cups_cspace_t;

cups_cut_t

CutMedia attribute values

typedef enum cups_cut_e cups_cut_t;

 CUPS 1.6/macOS 10.8 cups_dest_block_t

Destination enumeration block

typedef int (*cups_dest_block_t(unsigned flags, cups_dest_t *dest);

 CUPS 1.6/macOS 10.8 cups_dest_cb_t

Destination enumeration callback

typedef int (*cups_dest_cb_t)(void *user_data, unsigned flags, cups_dest_t *dest);

cups_dest_t

Destination

typedef struct cups_dest_s cups_dest_t;

 CUPS 1.6/macOS 10.8 cups_dinfo_t

Destination capability and status information

typedef struct _cups_dinfo_s cups_dinfo_t;

cups_edge_t

LeadingEdge attribute values

typedef enum cups_edge_e cups_edge_t;

cups_interpret_cb_t

cupsRasterInterpretPPD callback function

typedef int (*cups_interpret_cb_t)(cups_page_header2_t *header, int preferred_bits);

cups_job_t

Job

typedef struct cups_job_s cups_job_t;

cups_jog_t

Jog attribute values

typedef enum cups_jog_e cups_jog_t;

cups_mode_t

cupsRasterOpen modes

typedef enum cups_mode_e cups_mode_t;

cups_option_t

Printer Options

typedef struct cups_option_s cups_option_t;

cups_order_t

cupsColorOrder attribute values

typedef enum cups_order_e cups_order_t;

cups_orient_t

Orientation attribute values

typedef enum cups_orient_e cups_orient_t;

 CUPS 1.2/macOS 10.5 cups_page_header2_t

Version 2 page header

typedef struct cups_page_header2_s cups_page_header2_t;

 DEPRECATED cups_page_header_t

Version 1 page header

typedef struct cups_page_header_s cups_page_header_t;

 CUPS 1.4/macOS 10.6 cups_password_cb2_t

New password callback

typedef const char *(*cups_password_cb2_t)(const char *prompt, http_t *http, const char *method, const char *resource, void *user_data);

cups_password_cb_t

Password callback

typedef const char *(*cups_password_cb_t)(const char *prompt);

cups_ptype_t

Printer type/capability bits

typedef unsigned cups_ptype_t;

cups_raster_iocb_t

cupsRasterOpenIO callback function

typedef ssize_t (*cups_raster_iocb_t)(void *ctx, unsigned char *buffer, size_t length);

cups_raster_t

Raster stream data

typedef struct _cups_raster_s cups_raster_t;

 CUPS 1.5/macOS 10.7 cups_server_cert_cb_t

Server credentials callback

typedef int (*cups_server_cert_cb_t)(http_t *http, void *tls, cups_array_t *certs, void *user_data);

 CUPS 1.6/macOS 10.8 cups_size_t

Media Size

typedef struct cups_size_s cups_size_t;

gss_auth_identity_desc

Local functions...

typedef struct gss_auth_identity gss_auth_identity_desc;

 CUPS 1.2/macOS 10.5 http_addr_t

Socket address union, which makes using IPv6 and other address types easier and more portable.

typedef union _http_addr_u / http_addr_t;

 CUPS 1.2/macOS 10.5 http_addrlist_t

Socket address list, which is used to enumerate all of the addresses that are associated with a hostname.

typedef struct http_addrlist_s / http_addrlist_t;

http_auth_t

HTTP authentication types

typedef enum http_auth_e http_auth_t;

 CUPS 1.5/macOS 10.7 http_credential_t

HTTP credential data

typedef struct http_credential_s http_credential_t;

http_encoding_t

HTTP transfer encoding values

typedef enum http_encoding_e http_encoding_t;

http_encryption_t

HTTP encryption values

typedef enum http_encryption_e http_encryption_t;

http_field_t

HTTP field names

typedef enum http_field_e http_field_t;

http_keepalive_t

HTTP keep-alive values

typedef enum http_keepalive_e http_keepalive_t;

http_state_t

HTTP state values; states are server-oriented...

typedef enum http_state_e http_state_t;

http_t

HTTP connection type

typedef struct _http_s http_t;

 CUPS 1.5/macOS 10.7 http_timeout_cb_t

HTTP timeout callback

typedef int (*http_timeout_cb_t)(http_t *http, void *user_data);

 CUPS 2.0/OS 10.10 http_trust_t

Level of trust for credentials

typedef enum http_trust_e http_trust_t;

http_uri_coding_t

URI en/decode flags

typedef enum http_uri_coding_e http_uri_coding_t;

 CUPS 1.2 http_uri_status_t

URI separation status

typedef enum http_uri_status_e http_uri_status_t;

http_version_t

HTTP version numbers

typedef enum http_version_e http_version_t;

ipp_attribute_t

IPP attribute

typedef struct _ipp_attribute_s ipp_attribute_t;

ipp_copycb_t

The following structures are PRIVATE starting with CUPS 1.6/macOS 10.8. Please use the new accessor functions available in CUPS 1.6 and later, as these definitions will be moved to a private header file in a future release.

typedef int (*ipp_copycb_t)(void *context, ipp_t *dst, ipp_attribute_t *attr);

ipp_dstate_t

Document states

typedef enum ipp_dstate_e ipp_dstate_t;

ipp_finish_t

Job collation types

typedef enum ipp_finishings_e ipp_finish_t;

 CUPS 1.2/macOS 10.5 ipp_iocb_t

IPP IO Callback Function

typedef ssize_t (*ipp_iocb_t)(void *context, ipp_uchar_t *buffer, size_t bytes);

ipp_jcollate_t

Job collation types

typedef enum ipp_jcollate_e ipp_jcollate_t;

ipp_orient_t

Orientation values

typedef enum ipp_orient_e ipp_orient_t;

ipp_pstate_t

Printer states

typedef enum ipp_pstate_e ipp_pstate_t;

ipp_quality_t

Qualities

typedef enum ipp_quality_e ipp_quality_t;

ipp_res_t

Resolution units

typedef enum ipp_res_e ipp_res_t;

ipp_state_t

IPP states

typedef enum ipp_state_e ipp_state_t;

ipp_t

IPP request/response data

typedef struct _ipp_s ipp_t;

ipp_uchar_t

Unsigned 8-bit integer/character

typedef unsigned char ipp_uchar_t;

pwg_map_t

Map element - PPD to/from PWG

typedef struct pwg_map_s pwg_map_t;

pwg_media_t

Common media size data

typedef struct pwg_media_s pwg_media_t;

pwg_size_t

Size element - PPD to/from PWG

typedef struct pwg_size_s pwg_size_t;

Structures

cups_dest_s

Destination

struct cups_dest_s {
    char *name, *instance;
    int is_default;
    int num_options;
    cups_option_t *options;
};

Members

instance
Local instance name or NULL
is_default
Is this printer the default?
num_options
Number of options
options
Options

cups_job_s

Job

struct cups_job_s {
    time_t completed_time;
    time_t creation_time;
    char *dest;
    char *format;
    int id;
    int priority;
    time_t processing_time;
    int size;
    ipp_jstate_t state;
    char *title;
    char *user;
};

Members

completed_time
Time the job was completed
creation_time
Time the job was created
dest
Printer or class name
format
Document format
id
The job ID
priority
Priority (1-100)
processing_time
Time the job was processed
size
Size in kilobytes
state
Job state
title
Title/job name
user
User the submitted the job

cups_option_s

Printer Options

struct cups_option_s {
    char *name;
    char *value;
};

Members

name
Name of option
value
Value of option

 CUPS 1.2/macOS 10.5 cups_page_header2_s

Version 2 page header

struct cups_page_header2_s {
    unsigned AdvanceDistance;
    cups_adv_t AdvanceMedia;
    cups_bool_t Collate;
    cups_cut_t CutMedia;
    cups_bool_t Duplex;
    unsigned HWResolution[2];
    unsigned ImagingBoundingBox[4];
    cups_bool_t InsertSheet;
    cups_jog_t Jog;
    cups_edge_t LeadingEdge;
    cups_bool_t ManualFeed;
    unsigned Margins[2];
    char MediaClass[64];
    char MediaColor[64];
    unsigned MediaPosition;
    char MediaType[64];
    unsigned MediaWeight;
    cups_bool_t MirrorPrint;
    cups_bool_t NegativePrint;
    unsigned NumCopies;
    cups_orient_t Orientation;
    cups_bool_t OutputFaceUp;
    char OutputType[64];
    unsigned PageSize[2];
    cups_bool_t Separations;
    cups_bool_t TraySwitch;
    cups_bool_t Tumble;
    unsigned cupsBitsPerColor;
    unsigned cupsBitsPerPixel;
    float cupsBorderlessScalingFactor;
    unsigned cupsBytesPerLine;
    cups_order_t cupsColorOrder;
    cups_cspace_t cupsColorSpace;
    unsigned cupsCompression;
    unsigned cupsHeight;
    float cupsImagingBBox[4];
    unsigned cupsInteger[16];
    char cupsMarkerType[64];
    unsigned cupsMediaType;
    unsigned cupsNumColors;
    char cupsPageSizeName[64];
    float cupsPageSize[2];
    float cupsReal[16];
    char cupsRenderingIntent[64];
    unsigned cupsRowCount;
    unsigned cupsRowFeed;
    unsigned cupsRowStep;
    char cupsString[16][64];
    unsigned cupsWidth;
};

Members

AdvanceDistance
AdvanceDistance value in points
AdvanceMedia
AdvanceMedia value (cups_adv_t)
Collate
Collated copies value
CutMedia
CutMedia value (cups_cut_t)
Duplex
Duplexed (double-sided) value
HWResolution[2]
Resolution in dots-per-inch
ImagingBoundingBox[4]
Pixel region that is painted (points, left, bottom, right, top)
InsertSheet
InsertSheet value
Jog
Jog value (cups_jog_t)
LeadingEdge
LeadingEdge value (cups_edge_t)
ManualFeed
ManualFeed value
Margins[2]
Lower-lefthand margins in points
MediaClass[64]
MediaClass string
MediaColor[64]
MediaColor string
MediaPosition
MediaPosition value
MediaType[64]
MediaType string
MediaWeight
MediaWeight value in grams/m^2
MirrorPrint
MirrorPrint value
NegativePrint
NegativePrint value
NumCopies
Number of copies to produce
Orientation
Orientation value (cups_orient_t)
OutputFaceUp
OutputFaceUp value
OutputType[64]
OutputType string
PageSize[2]
Width and length of page in points
Separations
Separations value
TraySwitch
TraySwitch value
Tumble
Tumble value
cupsBitsPerColor
Number of bits for each color
cupsBitsPerPixel
Number of bits for each pixel
cupsBorderlessScalingFactor  CUPS 1.2/macOS 10.5 
Scaling that was applied to page data
cupsBytesPerLine
Number of bytes per line
cupsColorOrder
Order of colors
cupsColorSpace
True colorspace
cupsCompression
Device compression to use
cupsHeight
Height of page image in pixels
cupsImagingBBox[4]  CUPS 1.2/macOS 10.5 
Floating point ImagingBoundingBox (scaling factor not applied, left, bottom, right, top)
cupsInteger[16]  CUPS 1.2/macOS 10.5 
User-defined integer values
cupsMarkerType[64]  CUPS 1.2/macOS 10.5 
Ink/toner type
cupsMediaType
Media type code
cupsNumColors  CUPS 1.2/macOS 10.5 
Number of color compoents
cupsPageSizeName[64]  CUPS 1.2/macOS 10.5 
PageSize name
cupsPageSize[2]  CUPS 1.2/macOS 10.5 
Floating point PageSize (scaling * factor not applied)
cupsReal[16]  CUPS 1.2/macOS 10.5 
User-defined floating-point values
cupsRenderingIntent[64]  CUPS 1.2/macOS 10.5 
Color rendering intent
cupsRowCount
Rows per band
cupsRowFeed
Feed between bands
cupsRowStep
Spacing between lines
cupsString[16][64]  CUPS 1.2/macOS 10.5 
User-defined string values
cupsWidth
Width of page image in pixels

 DEPRECATED cups_page_header_s

Version 1 page header

struct cups_page_header_s {
    unsigned AdvanceDistance;
    cups_adv_t AdvanceMedia;
    cups_bool_t Collate;
    cups_cut_t CutMedia;
    cups_bool_t Duplex;
    unsigned HWResolution[2];
    unsigned ImagingBoundingBox[4];
    cups_bool_t InsertSheet;
    cups_jog_t Jog;
    cups_edge_t LeadingEdge;
    cups_bool_t ManualFeed;
    unsigned Margins[2];
    char MediaClass[64];
    char MediaColor[64];
    unsigned MediaPosition;
    char MediaType[64];
    unsigned MediaWeight;
    cups_bool_t MirrorPrint;
    cups_bool_t NegativePrint;
    unsigned NumCopies;
    cups_orient_t Orientation;
    cups_bool_t OutputFaceUp;
    char OutputType[64];
    unsigned PageSize[2];
    cups_bool_t Separations;
    cups_bool_t TraySwitch;
    cups_bool_t Tumble;
    unsigned cupsBitsPerColor;
    unsigned cupsBitsPerPixel;
    unsigned cupsBytesPerLine;
    cups_order_t cupsColorOrder;
    cups_cspace_t cupsColorSpace;
    unsigned cupsCompression;
    unsigned cupsHeight;
    unsigned cupsMediaType;
    unsigned cupsRowCount;
    unsigned cupsRowFeed;
    unsigned cupsRowStep;
    unsigned cupsWidth;
};

Members

AdvanceDistance
AdvanceDistance value in points
AdvanceMedia
AdvanceMedia value (cups_adv_t)
Collate
Collated copies value
CutMedia
CutMedia value (cups_cut_t)
Duplex
Duplexed (double-sided) value
HWResolution[2]
Resolution in dots-per-inch
ImagingBoundingBox[4]
Pixel region that is painted (points, left, bottom, right, top)
InsertSheet
InsertSheet value
Jog
Jog value (cups_jog_t)
LeadingEdge
LeadingEdge value (cups_edge_t)
ManualFeed
ManualFeed value
Margins[2]
Lower-lefthand margins in points
MediaClass[64]
MediaClass string
MediaColor[64]
MediaColor string
MediaPosition
MediaPosition value
MediaType[64]
MediaType string
MediaWeight
MediaWeight value in grams/m^2
MirrorPrint
MirrorPrint value
NegativePrint
NegativePrint value
NumCopies
Number of copies to produce
Orientation
Orientation value (cups_orient_t)
OutputFaceUp
OutputFaceUp value
OutputType[64]
OutputType string
PageSize[2]
Width and length of page in points
Separations
Separations value
TraySwitch
TraySwitch value
Tumble
Tumble value
cupsBitsPerColor
Number of bits for each color
cupsBitsPerPixel
Number of bits for each pixel
cupsBytesPerLine
Number of bytes per line
cupsColorOrder
Order of colors
cupsColorSpace
True colorspace
cupsCompression
Device compression to use
cupsHeight
Height of page image in pixels
cupsMediaType
Media type code
cupsRowCount
Rows per band
cupsRowFeed
Feed between bands
cupsRowStep
Spacing between lines
cupsWidth
Width of page image in pixels

 CUPS 1.6/macOS 10.8 cups_size_s

Media Size

struct cups_size_s {
    char media[128];
    int width, length, bottom, left, right, top;
};

Members

media[128]
Media name to use
top
Top margin in hundredths of millimeters

gss_auth_identity

Local functions...

struct gss_auth_identity {
    gss_buffer_t *credentialsRef;
    uint32_t flags;
    char *password;
    char *realm;
    uint32_t type;
    char *username;
};

Members

credentialsRef
flags
password
realm
type
username

 CUPS 1.2/macOS 10.5 http_addrlist_s

Socket address list, which is used to enumerate all of the addresses that are associated with a hostname.

struct http_addrlist_s {
    http_addr_t addr;
    struct http_addrlist_s *next;
};

Members

addr
Address
next
Pointer to next address in list

 CUPS 1.5/macOS 10.7 http_credential_s

HTTP credential data

struct http_credential_s {
    void *data;
    size_t datalen;
};

Members

data
Pointer to credential data
datalen
Credential length

pollfd

User data (unused)

struct pollfd *pollfds, unsigned int num_pollfds, int timeout, void *context) {
    void) context;
    void) timeout;
};

Members

context
timeout

pwg_map_s

Map element - PPD to/from PWG

struct pwg_map_s {
    char *pwg, *ppd;
};

Members

ppd
PPD option keyword

pwg_media_s

Common media size data

struct pwg_media_s {
    int width, length;
    const char *pwg, *legacy, *ppd;
};

Members

length
Length in 2540ths
ppd
Standard Adobe PPD name

pwg_size_s

Size element - PPD to/from PWG

struct pwg_size_s {
    pwg_map_t map;
    int width, length, left, bottom, right, top;
};

Members

map
Map element
top
Top margin in 2540ths

Constants

cups_adv_e

AdvanceMedia attribute values

Constants

CUPS_ADVANCE_FILE
Advance the roll after this file
CUPS_ADVANCE_JOB
Advance the roll after this job
CUPS_ADVANCE_NONE
Never advance the roll
CUPS_ADVANCE_PAGE
Advance the roll after this page
CUPS_ADVANCE_SET
Advance the roll after this set

cups_bool_e

Boolean type

Constants

CUPS_FALSE
Logical false
CUPS_TRUE
Logical true

cups_cspace_e

cupsColorSpace attribute values

Constants

CUPS_CSPACE_ADOBERGB  CUPS 1.4.5 
Red, green, blue (Adobe RGB)
CUPS_CSPACE_CIELab  CUPS 1.1.19/macOS 10.3 
CIE Lab
CUPS_CSPACE_CIEXYZ  CUPS 1.1.19/macOS 10.3 
CIE XYZ
CUPS_CSPACE_CMY
Cyan, magenta, yellow (DeviceCMY)
CUPS_CSPACE_CMYK
Cyan, magenta, yellow, black (DeviceCMYK)
CUPS_CSPACE_DEVICE1  CUPS 1.4.5 
DeviceN, 1 color
CUPS_CSPACE_DEVICE2  CUPS 1.4.5 
DeviceN, 2 colors
CUPS_CSPACE_DEVICE3  CUPS 1.4.5 
DeviceN, 3 colors
CUPS_CSPACE_DEVICE4  CUPS 1.4.5 
DeviceN, 4 colors
CUPS_CSPACE_DEVICE5  CUPS 1.4.5 
DeviceN, 5 colors
CUPS_CSPACE_DEVICE6  CUPS 1.4.5 
DeviceN, 6 colors
CUPS_CSPACE_DEVICE7  CUPS 1.4.5 
DeviceN, 7 colors
CUPS_CSPACE_DEVICE8  CUPS 1.4.5 
DeviceN, 8 colors
CUPS_CSPACE_DEVICE9  CUPS 1.4.5 
DeviceN, 9 colors
CUPS_CSPACE_DEVICEA  CUPS 1.4.5 
DeviceN, 10 colors
CUPS_CSPACE_DEVICEB  CUPS 1.4.5 
DeviceN, 11 colors
CUPS_CSPACE_DEVICEC  CUPS 1.4.5 
DeviceN, 12 colors
CUPS_CSPACE_DEVICED  CUPS 1.4.5 
DeviceN, 13 colors
CUPS_CSPACE_DEVICEE  CUPS 1.4.5 
DeviceN, 14 colors
CUPS_CSPACE_DEVICEF  CUPS 1.4.5 
DeviceN, 15 colors
CUPS_CSPACE_GMCK  DEPRECATED 
Gold, magenta, yellow, black
CUPS_CSPACE_GMCS  DEPRECATED 
Gold, magenta, yellow, silver
CUPS_CSPACE_GOLD  DEPRECATED 
Gold foil
CUPS_CSPACE_ICC1  CUPS 1.1.19/macOS 10.3 
ICC-based, 1 color
CUPS_CSPACE_ICC2  CUPS 1.1.19/macOS 10.3 
ICC-based, 2 colors
CUPS_CSPACE_ICC3  CUPS 1.1.19/macOS 10.3 
ICC-based, 3 colors
CUPS_CSPACE_ICC4  CUPS 1.1.19/macOS 10.3 
ICC-based, 4 colors
CUPS_CSPACE_ICC5  CUPS 1.1.19/macOS 10.3 
ICC-based, 5 colors
CUPS_CSPACE_ICC6  CUPS 1.1.19/macOS 10.3 
ICC-based, 6 colors
CUPS_CSPACE_ICC7  CUPS 1.1.19/macOS 10.3 
ICC-based, 7 colors
CUPS_CSPACE_ICC8  CUPS 1.1.19/macOS 10.3 
ICC-based, 8 colors
CUPS_CSPACE_ICC9  CUPS 1.1.19/macOS 10.3 
ICC-based, 9 colors
CUPS_CSPACE_ICCA  CUPS 1.1.19/macOS 10.3 
ICC-based, 10 colors
CUPS_CSPACE_ICCB  CUPS 1.1.19/macOS 10.3 
ICC-based, 11 colors
CUPS_CSPACE_ICCC  CUPS 1.1.19/macOS 10.3 
ICC-based, 12 colors
CUPS_CSPACE_ICCD  CUPS 1.1.19/macOS 10.3 
ICC-based, 13 colors
CUPS_CSPACE_ICCE  CUPS 1.1.19/macOS 10.3 
ICC-based, 14 colors
CUPS_CSPACE_ICCF  CUPS 1.1.19/macOS 10.3 
ICC-based, 15 colors
CUPS_CSPACE_K
Black (DeviceK)
CUPS_CSPACE_KCMY  DEPRECATED 
Black, cyan, magenta, yellow
CUPS_CSPACE_KCMYcm  DEPRECATED 
Black, cyan, magenta, yellow, light-cyan, light-magenta
CUPS_CSPACE_RGB
Red, green, blue (DeviceRGB, sRGB by default)
CUPS_CSPACE_RGBA
Red, green, blue, alpha (DeviceRGB, sRGB by default)
CUPS_CSPACE_RGBW  CUPS 1.2/macOS 10.5 
Red, green, blue, white (DeviceRGB, sRGB by default)
CUPS_CSPACE_SILVER  DEPRECATED 
Silver foil
CUPS_CSPACE_SRGB  CUPS 1.4.5 
Red, green, blue (sRGB)
CUPS_CSPACE_SW  CUPS 1.4.5 
Luminance (gamma 2.2)
CUPS_CSPACE_W
Luminance (DeviceGray, gamma 2.2 by default)
CUPS_CSPACE_WHITE  DEPRECATED 
White ink (as black)
CUPS_CSPACE_YMC  DEPRECATED 
Yellow, magenta, cyan
CUPS_CSPACE_YMCK  DEPRECATED 
Yellow, magenta, cyan, black

cups_cut_e

CutMedia attribute values

Constants

CUPS_CUT_FILE
Cut the roll after this file
CUPS_CUT_JOB
Cut the roll after this job
CUPS_CUT_NONE
Never cut the roll
CUPS_CUT_PAGE
Cut the roll after this page
CUPS_CUT_SET
Cut the roll after this set

cups_edge_e

LeadingEdge attribute values

Constants

CUPS_EDGE_BOTTOM
Leading edge is the bottom of the page
CUPS_EDGE_LEFT
Leading edge is the left of the page
CUPS_EDGE_RIGHT
Leading edge is the right of the page
CUPS_EDGE_TOP
Leading edge is the top of the page

cups_jog_e

Jog attribute values

Constants

CUPS_JOG_FILE
Move pages after this file
CUPS_JOG_JOB
Move pages after this job
CUPS_JOG_NONE
Never move pages
CUPS_JOG_SET
Move pages after this set

cups_mode_e

cupsRasterOpen modes

Constants

CUPS_RASTER_READ
Open stream for reading
CUPS_RASTER_WRITE
Open stream for writing
CUPS_RASTER_WRITE_COMPRESSED  CUPS 1.3/macOS 10.5 
Open stream for compressed writing
CUPS_RASTER_WRITE_PWG  CUPS 1.5/macOS 10.7 
Open stream for compressed writing in PWG Raster mode

cups_order_e

cupsColorOrder attribute values

Constants

CUPS_ORDER_BANDED
CCC MMM YYY KKK ...
CUPS_ORDER_CHUNKED
CMYK CMYK CMYK ...
CUPS_ORDER_PLANAR
CCC ... MMM ... YYY ... KKK ...

cups_orient_e

Orientation attribute values

Constants

CUPS_ORIENT_0
Don't rotate the page
CUPS_ORIENT_180
Turn the page upside down
CUPS_ORIENT_270
Rotate the page clockwise
CUPS_ORIENT_90
Rotate the page counter-clockwise

cups_ptype_e

Printer type/capability bit constants

Constants

CUPS_PRINTER_AUTHENTICATED  CUPS 1.2/macOS 10.5 
Printer requires authentication
CUPS_PRINTER_BIND
Can bind output
CUPS_PRINTER_BW
Can do B&W printing
CUPS_PRINTER_CLASS
Printer class
CUPS_PRINTER_COLLATE
Can collage copies
CUPS_PRINTER_COLOR
Can do color printing
CUPS_PRINTER_COMMANDS  CUPS 1.2/macOS 10.5 
Printer supports maintenance commands
CUPS_PRINTER_COPIES
Can do copies
CUPS_PRINTER_COVER
Can cover output
CUPS_PRINTER_DEFAULT
Default printer on network
CUPS_PRINTER_DELETE  CUPS 1.2/macOS 10.5 
Delete printer
CUPS_PRINTER_DUPLEX
Can do duplexing
CUPS_PRINTER_FAX
Fax queue
CUPS_PRINTER_LARGE
Can do D/E/A1/A0
CUPS_PRINTER_LOCAL
Local printer or class
CUPS_PRINTER_MEDIUM
Can do Tabloid/B/C/A3/A2
CUPS_PRINTER_MFP  CUPS 1.4/macOS 10.6 
Printer with scanning capabilities
CUPS_PRINTER_NOT_SHARED  CUPS 1.2/macOS 10.5 
Printer is not shared
CUPS_PRINTER_PUNCH
Can punch output
CUPS_PRINTER_REJECTING
Printer is rejecting jobs
CUPS_PRINTER_REMOTE
Remote printer or class
CUPS_PRINTER_SCANNER  CUPS 1.4/macOS 10.6 
Scanner-only device
CUPS_PRINTER_SMALL
Can do Letter/Legal/A4
CUPS_PRINTER_SORT
Can sort output
CUPS_PRINTER_STAPLE
Can staple output
CUPS_PRINTER_VARIABLE
Can do variable sizes

http_auth_e

HTTP authentication types

Constants

HTTP_AUTH_BASIC
Basic authentication in use
HTTP_AUTH_MD5
Digest authentication in use
HTTP_AUTH_MD5_INT
Digest authentication in use for body
HTTP_AUTH_MD5_SESS
MD5-session authentication in use
HTTP_AUTH_MD5_SESS_INT
MD5-session authentication in use for body
HTTP_AUTH_NEGOTIATE  CUPS 1.3/macOS 10.5 
GSSAPI authentication in use
HTTP_AUTH_NONE
No authentication in use

http_encoding_e

HTTP transfer encoding values

Constants

HTTP_ENCODING_CHUNKED
Data is chunked
HTTP_ENCODING_FIELDS
Sending HTTP fields
HTTP_ENCODING_LENGTH
Data is sent with Content-Length

http_encryption_e

HTTP encryption values

Constants

HTTP_ENCRYPTION_ALWAYS
Always encrypt (SSL)
HTTP_ENCRYPTION_IF_REQUESTED
Encrypt if requested (TLS upgrade)
HTTP_ENCRYPTION_NEVER
Never encrypt
HTTP_ENCRYPTION_REQUIRED
Encryption is required (TLS upgrade)

http_field_e

HTTP field names

Constants

HTTP_FIELD_ACCEPT_ENCODING  CUPS 1.7/macOS 10.9 
Accepting-Encoding field
HTTP_FIELD_ACCEPT_LANGUAGE
Accept-Language field
HTTP_FIELD_ACCEPT_RANGES
Accept-Ranges field
HTTP_FIELD_ALLOW  CUPS 1.7/macOS 10.9 
Allow field
HTTP_FIELD_AUTHORIZATION
Authorization field
HTTP_FIELD_CONNECTION
Connection field
HTTP_FIELD_CONTENT_ENCODING
Content-Encoding field
HTTP_FIELD_CONTENT_LANGUAGE
Content-Language field
HTTP_FIELD_CONTENT_LENGTH
Content-Length field
HTTP_FIELD_CONTENT_LOCATION
Content-Location field
HTTP_FIELD_CONTENT_MD5
Content-MD5 field
HTTP_FIELD_CONTENT_RANGE
Content-Range field
HTTP_FIELD_CONTENT_TYPE
Content-Type field
HTTP_FIELD_CONTENT_VERSION
Content-Version field
HTTP_FIELD_DATE
Date field
HTTP_FIELD_HOST
Host field
HTTP_FIELD_IF_MODIFIED_SINCE
If-Modified-Since field
HTTP_FIELD_IF_UNMODIFIED_SINCE
If-Unmodified-Since field
HTTP_FIELD_KEEP_ALIVE
Keep-Alive field
HTTP_FIELD_LAST_MODIFIED
Last-Modified field
HTTP_FIELD_LINK
Link field
HTTP_FIELD_LOCATION
Location field
HTTP_FIELD_MAX
Maximum field index
HTTP_FIELD_RANGE
Range field
HTTP_FIELD_REFERER
Referer field
HTTP_FIELD_RETRY_AFTER
Retry-After field
HTTP_FIELD_SERVER  CUPS 1.7/macOS 10.9 
Server field
HTTP_FIELD_TRANSFER_ENCODING
Transfer-Encoding field
HTTP_FIELD_UNKNOWN
Unknown field
HTTP_FIELD_UPGRADE
Upgrade field
HTTP_FIELD_USER_AGENT
User-Agent field
HTTP_FIELD_WWW_AUTHENTICATE
WWW-Authenticate field

http_keepalive_e

HTTP keep-alive values

Constants

HTTP_KEEPALIVE_OFF
No keep alive support
HTTP_KEEPALIVE_ON
Use keep alive

http_state_e

HTTP state values; states are server-oriented...

Constants

HTTP_STATE_CONNECT
CONNECT command, waiting for blank line
HTTP_STATE_DELETE
DELETE command, waiting for blank line
HTTP_STATE_ERROR
Error on socket
HTTP_STATE_GET
GET command, waiting for blank line
HTTP_STATE_GET_SEND
GET command, sending data
HTTP_STATE_HEAD
HEAD command, waiting for blank line
HTTP_STATE_OPTIONS
OPTIONS command, waiting for blank line
HTTP_STATE_POST
POST command, waiting for blank line
HTTP_STATE_POST_RECV
POST command, receiving data
HTTP_STATE_POST_SEND
POST command, sending data
HTTP_STATE_PUT
PUT command, waiting for blank line
HTTP_STATE_PUT_RECV
PUT command, receiving data
HTTP_STATE_STATUS
Command complete, sending status
HTTP_STATE_TRACE
TRACE command, waiting for blank line
HTTP_STATE_UNKNOWN_METHOD  CUPS 1.7/macOS 10.9 
Unknown request method, waiting for blank line
HTTP_STATE_UNKNOWN_VERSION  CUPS 1.7/macOS 10.9 
Unknown request method, waiting for blank line
HTTP_STATE_WAITING
Waiting for command

http_status_e

HTTP status codes

Constants

HTTP_STATUS_ACCEPTED
DELETE command was successful
HTTP_STATUS_BAD_GATEWAY
Bad gateway
HTTP_STATUS_BAD_REQUEST
Bad request
HTTP_STATUS_CONFLICT
Request is self-conflicting
HTTP_STATUS_CONTINUE
Everything OK, keep going...
HTTP_STATUS_CREATED
PUT command was successful
HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED  CUPS 1.4 
User canceled authorization
HTTP_STATUS_CUPS_PKI_ERROR  CUPS 1.5/macOS 10.7 
Error negotiating a secure connection
HTTP_STATUS_ERROR
An error response from httpXxxx()
HTTP_STATUS_EXPECTATION_FAILED
The expectation given in an Expect header field was not met
HTTP_STATUS_FORBIDDEN
Forbidden to access this URI
HTTP_STATUS_GATEWAY_TIMEOUT
Gateway connection timed out
HTTP_STATUS_GONE
Server has gone away
HTTP_STATUS_LENGTH_REQUIRED
A content length or encoding is required
HTTP_STATUS_METHOD_NOT_ALLOWED
Method is not allowed
HTTP_STATUS_MOVED_PERMANENTLY
Document has moved permanently
HTTP_STATUS_MOVED_TEMPORARILY
Document has moved temporarily
HTTP_STATUS_MULTIPLE_CHOICES
Multiple files match request
HTTP_STATUS_NONE  CUPS 1.7/macOS 10.9 
No Expect value
HTTP_STATUS_NOT_ACCEPTABLE
Not Acceptable
HTTP_STATUS_NOT_AUTHORITATIVE
Information isn't authoritative
HTTP_STATUS_NOT_FOUND
URI was not found
HTTP_STATUS_NOT_IMPLEMENTED
Feature not implemented
HTTP_STATUS_NOT_MODIFIED
File not modified
HTTP_STATUS_NOT_SUPPORTED
HTTP version not supported
HTTP_STATUS_NO_CONTENT
Successful command, no new data
HTTP_STATUS_OK
OPTIONS/GET/HEAD/POST/TRACE command was successful
HTTP_STATUS_PARTIAL_CONTENT
Only a partial file was received/sent
HTTP_STATUS_PAYMENT_REQUIRED
Payment required
HTTP_STATUS_PRECONDITION
Precondition failed
HTTP_STATUS_PROXY_AUTHENTICATION
Proxy Authentication is Required
HTTP_STATUS_REQUESTED_RANGE
The requested range is not satisfiable
HTTP_STATUS_REQUEST_TIMEOUT
Request timed out
HTTP_STATUS_REQUEST_TOO_LARGE
Request entity too large
HTTP_STATUS_RESET_CONTENT
Content was reset/recreated
HTTP_STATUS_SEE_OTHER
See this other link...
HTTP_STATUS_SERVER_ERROR
Internal server error
HTTP_STATUS_SERVICE_UNAVAILABLE
Service is unavailable
HTTP_STATUS_SWITCHING_PROTOCOLS
HTTP upgrade to TLS/SSL
HTTP_STATUS_UNAUTHORIZED
Unauthorized to access host
HTTP_STATUS_UNSUPPORTED_MEDIATYPE
The requested media type is unsupported
HTTP_STATUS_UPGRADE_REQUIRED
Upgrade to SSL/TLS required
HTTP_STATUS_URI_TOO_LONG
URI too long
HTTP_STATUS_USE_PROXY
Must use a proxy to access this URI

 CUPS 2.0/OS 10.10 http_trust_e

Level of trust for credentials

Constants

HTTP_TRUST_CHANGED
Credentials have changed
HTTP_TRUST_EXPIRED
Credentials are expired
HTTP_TRUST_INVALID
Credentials are invalid
HTTP_TRUST_OK
Credentials are OK/trusted
HTTP_TRUST_RENEWED
Credentials have been renewed
HTTP_TRUST_UNKNOWN
Credentials are unknown/new

http_uri_coding_e

URI en/decode flags

Constants

HTTP_URI_CODING_ALL
En/decode everything
HTTP_URI_CODING_HOSTNAME
En/decode the hostname portion
HTTP_URI_CODING_MOST
En/decode all but the query
HTTP_URI_CODING_NONE
Don't en/decode anything
HTTP_URI_CODING_QUERY
En/decode the query portion
HTTP_URI_CODING_RESOURCE
En/decode the resource portion
HTTP_URI_CODING_RFC6874
Use RFC 6874 address format
HTTP_URI_CODING_USERNAME
En/decode the username portion

 CUPS 1.2 http_uri_status_e

URI separation status

Constants

HTTP_URI_STATUS_BAD_ARGUMENTS
Bad arguments to function (error)
HTTP_URI_STATUS_BAD_HOSTNAME
Bad hostname in URI (error)
HTTP_URI_STATUS_BAD_PORT
Bad port number in URI (error)
HTTP_URI_STATUS_BAD_RESOURCE
Bad resource in URI (error)
HTTP_URI_STATUS_BAD_SCHEME
Bad scheme in URI (error)
HTTP_URI_STATUS_BAD_URI
Bad/empty URI (error)
HTTP_URI_STATUS_BAD_USERNAME
Bad username in URI (error)
HTTP_URI_STATUS_MISSING_RESOURCE
Missing resource in URI (warning)
HTTP_URI_STATUS_MISSING_SCHEME
Missing scheme in URI (warning)
HTTP_URI_STATUS_OK
URI decoded OK
HTTP_URI_STATUS_OVERFLOW
URI buffer for httpAssembleURI is too small
HTTP_URI_STATUS_UNKNOWN_SCHEME
Unknown scheme in URI (warning)

http_version_e

HTTP version numbers

Constants

HTTP_VERSION_0_9
HTTP/0.9
HTTP_VERSION_1_0
HTTP/1.0
HTTP_VERSION_1_1
HTTP/1.1

ipp_dstate_e

Document states

Constants

IPP_DOCUMENT_ABORTED
Document is aborted
IPP_DOCUMENT_CANCELED
Document is canceled
IPP_DOCUMENT_COMPLETED
Document is completed
IPP_DOCUMENT_PENDING
Document is pending
IPP_DOCUMENT_PROCESSING
Document is processing

ipp_finishings_e

Finishings

Constants

IPP_FINISHINGS_BALE
Bale (any type)
IPP_FINISHINGS_BIND
Bind
IPP_FINISHINGS_BIND_BOTTOM
Bind on bottom
IPP_FINISHINGS_BIND_LEFT
Bind on left
IPP_FINISHINGS_BIND_RIGHT
Bind on right
IPP_FINISHINGS_BIND_TOP
Bind on top
IPP_FINISHINGS_BOOKLET_MAKER
Fold to make booklet
IPP_FINISHINGS_COAT
Apply protective liquid or powder coating
IPP_FINISHINGS_COVER
Add cover
IPP_FINISHINGS_CUPS_FOLD_ACCORDIAN
Accordian-fold the paper vertically into four sections
IPP_FINISHINGS_CUPS_FOLD_DOUBLE_GATE
Fold the top and bottom quarters of the paper towards the midline, then fold in half vertically
IPP_FINISHINGS_CUPS_FOLD_GATE
Fold the top and bottom quarters of the paper towards the midline
IPP_FINISHINGS_CUPS_FOLD_HALF
Fold the paper in half vertically
IPP_FINISHINGS_CUPS_FOLD_HALF_Z
Fold the paper in half horizontally, then Z-fold the paper vertically
IPP_FINISHINGS_CUPS_FOLD_LEFT_GATE
Fold the top quarter of the paper towards the midline
IPP_FINISHINGS_CUPS_FOLD_LETTER
Fold the paper into three sections vertically; sometimes also known as a C fold
IPP_FINISHINGS_CUPS_FOLD_PARALLEL
Fold the paper in half vertically two times, yielding four sections
IPP_FINISHINGS_CUPS_FOLD_POSTER
Fold the paper in half horizontally and vertically; sometimes also called a cross fold
IPP_FINISHINGS_CUPS_FOLD_RIGHT_GATE
Fold the bottom quarter of the paper towards the midline
IPP_FINISHINGS_CUPS_FOLD_Z
Fold the paper vertically into three sections, forming a Z
IPP_FINISHINGS_CUPS_PUNCH_BOTTOM_LEFT
Punch 1 hole bottom left
IPP_FINISHINGS_CUPS_PUNCH_BOTTOM_RIGHT
Punch 1 hole bottom right
IPP_FINISHINGS_CUPS_PUNCH_DUAL_BOTTOM
Punch 2 holes bottom edge
IPP_FINISHINGS_CUPS_PUNCH_DUAL_LEFT
Punch 2 holes left side
IPP_FINISHINGS_CUPS_PUNCH_DUAL_RIGHT
Punch 2 holes right side
IPP_FINISHINGS_CUPS_PUNCH_DUAL_TOP
Punch 2 holes top edge
IPP_FINISHINGS_CUPS_PUNCH_QUAD_BOTTOM
Punch 4 holes bottom edge
IPP_FINISHINGS_CUPS_PUNCH_QUAD_LEFT
Punch 4 holes left side
IPP_FINISHINGS_CUPS_PUNCH_QUAD_RIGHT
Punch 4 holes right side
IPP_FINISHINGS_CUPS_PUNCH_QUAD_TOP
Punch 4 holes top edge
IPP_FINISHINGS_CUPS_PUNCH_TOP_LEFT
Punch 1 hole top left
IPP_FINISHINGS_CUPS_PUNCH_TOP_RIGHT
Punch 1 hole top right
IPP_FINISHINGS_CUPS_PUNCH_TRIPLE_BOTTOM
Punch 3 holes bottom edge
IPP_FINISHINGS_CUPS_PUNCH_TRIPLE_LEFT
Punch 3 holes left side
IPP_FINISHINGS_CUPS_PUNCH_TRIPLE_RIGHT
Punch 3 holes right side
IPP_FINISHINGS_CUPS_PUNCH_TRIPLE_TOP
Punch 3 holes top edge
IPP_FINISHINGS_EDGE_STITCH
Stitch along any side
IPP_FINISHINGS_EDGE_STITCH_BOTTOM
Stitch along bottom edge
IPP_FINISHINGS_EDGE_STITCH_LEFT
Stitch along left side
IPP_FINISHINGS_EDGE_STITCH_RIGHT
Stitch along right side
IPP_FINISHINGS_EDGE_STITCH_TOP
Stitch along top edge
IPP_FINISHINGS_FOLD
Fold (any type)
IPP_FINISHINGS_FOLD_ACCORDIAN
Accordian-fold the paper vertically into four sections
IPP_FINISHINGS_FOLD_DOUBLE_GATE
Fold the top and bottom quarters of the paper towards the midline, then fold in half vertically
IPP_FINISHINGS_FOLD_ENGINEERING_Z
Fold the paper vertically into two small sections and one larger, forming an elongated Z
IPP_FINISHINGS_FOLD_GATE
Fold the top and bottom quarters of the paper towards the midline
IPP_FINISHINGS_FOLD_HALF
Fold the paper in half vertically
IPP_FINISHINGS_FOLD_HALF_Z
Fold the paper in half horizontally, then Z-fold the paper vertically
IPP_FINISHINGS_FOLD_LEFT_GATE
Fold the top quarter of the paper towards the midline
IPP_FINISHINGS_FOLD_LETTER
Fold the paper into three sections vertically; sometimes also known as a C fold
IPP_FINISHINGS_FOLD_PARALLEL
Fold the paper in half vertically two times, yielding four sections
IPP_FINISHINGS_FOLD_POSTER
Fold the paper in half horizontally and vertically; sometimes also called a cross fold
IPP_FINISHINGS_FOLD_RIGHT_GATE
Fold the bottom quarter of the paper towards the midline
IPP_FINISHINGS_FOLD_Z
Fold the paper vertically into three sections, forming a Z
IPP_FINISHINGS_JOG_OFFSET
Offset for binding (any type)
IPP_FINISHINGS_LAMINATE
Apply protective (solid) material
IPP_FINISHINGS_NONE
No finishing
IPP_FINISHINGS_PUNCH
Punch (any location/count)
IPP_FINISHINGS_PUNCH_BOTTOM_LEFT
Punch 1 hole bottom left
IPP_FINISHINGS_PUNCH_BOTTOM_RIGHT
Punch 1 hole bottom right
IPP_FINISHINGS_PUNCH_DUAL_BOTTOM
Punch 2 holes bottom edge
IPP_FINISHINGS_PUNCH_DUAL_LEFT
Punch 2 holes left side
IPP_FINISHINGS_PUNCH_DUAL_RIGHT
Punch 2 holes right side
IPP_FINISHINGS_PUNCH_DUAL_TOP
Punch 2 holes top edge
IPP_FINISHINGS_PUNCH_MULTIPLE_BOTTOM
Pucnh multiple holes bottom edge
IPP_FINISHINGS_PUNCH_MULTIPLE_LEFT
Pucnh multiple holes left side
IPP_FINISHINGS_PUNCH_MULTIPLE_RIGHT
Pucnh multiple holes right side
IPP_FINISHINGS_PUNCH_MULTIPLE_TOP
Pucnh multiple holes top edge
IPP_FINISHINGS_PUNCH_QUAD_BOTTOM
Punch 4 holes bottom edge
IPP_FINISHINGS_PUNCH_QUAD_LEFT
Punch 4 holes left side
IPP_FINISHINGS_PUNCH_QUAD_RIGHT
Punch 4 holes right side
IPP_FINISHINGS_PUNCH_QUAD_TOP
Punch 4 holes top edge
IPP_FINISHINGS_PUNCH_TOP_LEFT
Punch 1 hole top left
IPP_FINISHINGS_PUNCH_TOP_RIGHT
Punch 1 hole top right
IPP_FINISHINGS_PUNCH_TRIPLE_BOTTOM
Punch 3 holes bottom edge
IPP_FINISHINGS_PUNCH_TRIPLE_LEFT
Punch 3 holes left side
IPP_FINISHINGS_PUNCH_TRIPLE_RIGHT
Punch 3 holes right side
IPP_FINISHINGS_PUNCH_TRIPLE_TOP
Punch 3 holes top edge
IPP_FINISHINGS_SADDLE_STITCH
Staple interior
IPP_FINISHINGS_STAPLE
Staple (any location)
IPP_FINISHINGS_STAPLE_BOTTOM_LEFT
Staple bottom left corner
IPP_FINISHINGS_STAPLE_BOTTOM_RIGHT
Staple bottom right corner
IPP_FINISHINGS_STAPLE_DUAL_BOTTOM
Two staples on bottom
IPP_FINISHINGS_STAPLE_DUAL_LEFT
Two staples on left
IPP_FINISHINGS_STAPLE_DUAL_RIGHT
Two staples on right
IPP_FINISHINGS_STAPLE_DUAL_TOP
Two staples on top
IPP_FINISHINGS_STAPLE_TOP_LEFT
Staple top left corner
IPP_FINISHINGS_STAPLE_TOP_RIGHT
Staple top right corner
IPP_FINISHINGS_STAPLE_TRIPLE_BOTTOM
Three staples on bottom
IPP_FINISHINGS_STAPLE_TRIPLE_LEFT
Three staples on left
IPP_FINISHINGS_STAPLE_TRIPLE_RIGHT
Three staples on right
IPP_FINISHINGS_STAPLE_TRIPLE_TOP
Three staples on top
IPP_FINISHINGS_TRIM
Trim (any type)
IPP_FINISHINGS_TRIM_AFTER_COPIES
Trim output after each copy
IPP_FINISHINGS_TRIM_AFTER_DOCUMENTS
Trim output after each document
IPP_FINISHINGS_TRIM_AFTER_JOB
Trim output after job
IPP_FINISHINGS_TRIM_AFTER_PAGES
Trim output after each page

ipp_jcollate_e

Job collation types

Constants

IPP_JCOLLATE_COLLATED_DOCUMENTS
IPP_JCOLLATE_UNCOLLATED_DOCUMENTS
IPP_JCOLLATE_UNCOLLATED_SHEETS

ipp_jstate_e

Job states

Constants

IPP_JSTATE_ABORTED
Job has aborted due to error
IPP_JSTATE_CANCELED
Job has been canceled
IPP_JSTATE_COMPLETED
Job has completed successfully
IPP_JSTATE_HELD
Job is held for printing
IPP_JSTATE_PENDING
Job is waiting to be printed
IPP_JSTATE_PROCESSING
Job is currently printing
IPP_JSTATE_STOPPED
Job has been stopped

ipp_op_e

IPP operations

Constants

IPP_OP_ACKNOWLEDGE_DOCUMENT
Acknowledge-Document
IPP_OP_ACKNOWLEDGE_IDENTIFY_PRINTER
Acknowledge-Identify-Printer
IPP_OP_ACKNOWLEDGE_JOB
Acknowledge-Job
IPP_OP_ACTIVATE_PRINTER
Start a printer
IPP_OP_ADD_DOCUMENT_IMAGES
Add-Document-Images
IPP_OP_CANCEL_CURRENT_JOB
Cancel the current job
IPP_OP_CANCEL_DOCUMENT
Cancel-Document
IPP_OP_CANCEL_JOB
Cancel a job
IPP_OP_CANCEL_JOBS
Cancel-Jobs
IPP_OP_CANCEL_MY_JOBS
Cancel-My-Jobs
IPP_OP_CANCEL_SUBSCRIPTION  CUPS 1.2/macOS 10.5 
Cancel a subscription
IPP_OP_CLOSE_JOB
Close-Job
IPP_OP_CREATE_JOB
Create an empty print job
IPP_OP_CREATE_JOB_SUBSCRIPTIONS  CUPS 1.2/macOS 10.5 
Create one of more job subscriptions
IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS  CUPS 1.2/macOS 10.5 
Create one or more printer subscriptions
IPP_OP_CUPS_ACCEPT_JOBS
Accept new jobs on a printer
IPP_OP_CUPS_ADD_MODIFY_CLASS
Add or modify a class
IPP_OP_CUPS_ADD_MODIFY_PRINTER
Add or modify a printer
IPP_OP_CUPS_AUTHENTICATE_JOB  CUPS 1.2/macOS 10.5 
Authenticate a job
IPP_OP_CUPS_CREATE_LOCAL_PRINTER  CUPS 2.2 
Create a local (temporary) printer
IPP_OP_CUPS_DELETE_CLASS
Delete a class
IPP_OP_CUPS_DELETE_PRINTER
Delete a printer
IPP_OP_CUPS_GET_CLASSES  DEPRECATED 
Get a list of classes
IPP_OP_CUPS_GET_DEFAULT
Get the default printer
IPP_OP_CUPS_GET_DEVICES  DEPRECATED 
Get a list of supported devices
IPP_OP_CUPS_GET_DOCUMENT  CUPS 1.4/macOS 10.6 
Get a document file
IPP_OP_CUPS_GET_PPD  DEPRECATED 
Get a PPD file
IPP_OP_CUPS_GET_PPDS  DEPRECATED 
Get a list of supported drivers
IPP_OP_CUPS_GET_PRINTERS
Get a list of printers and/or classes
IPP_OP_CUPS_INVALID
Invalid operation name for ippOpValue
IPP_OP_CUPS_MOVE_JOB
Move a job to a different printer
IPP_OP_CUPS_REJECT_JOBS
Reject new jobs on a printer
IPP_OP_CUPS_SET_DEFAULT
Set the default printer
IPP_OP_DEACTIVATE_PRINTER
Stop a printer
IPP_OP_DELETE_DOCUMENT
Delete-Document
IPP_OP_DEREGISTER_OUTPUT_DEVICE
Deregister-Output-Device
IPP_OP_DISABLE_PRINTER
Stop a printer
IPP_OP_ENABLE_PRINTER
Start a printer
IPP_OP_FETCH_DOCUMENT
Fetch-Document
IPP_OP_FETCH_JOB
Fetch-Job
IPP_OP_GET_DOCUMENTS
Get-Documents
IPP_OP_GET_DOCUMENT_ATTRIBUTES
Get-Document-Attributes
IPP_OP_GET_JOBS
Get a list of jobs
IPP_OP_GET_JOB_ATTRIBUTES
Get job attributes
IPP_OP_GET_NEXT_DOCUMENT_DATA
Get-Next-Document-Data
IPP_OP_GET_NOTIFICATIONS  CUPS 1.2/macOS 10.5 
Get notification events
IPP_OP_GET_OUTPUT_DEVICE_ATTRIBUTES
Get-Output-Device-Attributes
IPP_OP_GET_PRINTER_ATTRIBUTES
Get printer attributes
IPP_OP_GET_PRINTER_SUPPORTED_VALUES
Get supported attribute values
IPP_OP_GET_SUBSCRIPTIONS  CUPS 1.2/macOS 10.5 
Get list of subscriptions
IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES  CUPS 1.2/macOS 10.5 
Get subscription attributes
IPP_OP_HOLD_JOB
Hold a job for printing
IPP_OP_HOLD_NEW_JOBS
Hold new jobs
IPP_OP_IDENTIFY_PRINTER
Identify-Printer
IPP_OP_PAUSE_PRINTER
Stop a printer
IPP_OP_PAUSE_PRINTER_AFTER_CURRENT_JOB
Stop printer after the current job
IPP_OP_PRINT_JOB
Print a single file
IPP_OP_PRINT_URI
Print a single URL
IPP_OP_PROMOTE_JOB
Promote a job to print sooner
IPP_OP_PURGE_JOBS
Cancel all jobs
IPP_OP_RELEASE_HELD_NEW_JOBS
Release new jobs
IPP_OP_RELEASE_JOB
Release a job for printing
IPP_OP_RENEW_SUBSCRIPTION  CUPS 1.2/macOS 10.5 
Renew a printer subscription
IPP_OP_REPROCESS_JOB
Reprint a job
IPP_OP_RESTART_JOB
Reprint a job
IPP_OP_RESTART_PRINTER
Restart a printer
IPP_OP_RESUBMIT_JOB
Resubmit-Job
IPP_OP_RESUME_JOB
Resume the current job
IPP_OP_RESUME_PRINTER
Start a printer
IPP_OP_SCHEDULE_JOB_AFTER
Schedule a job to print after another
IPP_OP_SEND_DOCUMENT
Add a file to a job
IPP_OP_SEND_URI
Add a URL to a job
IPP_OP_SET_DOCUMENT_ATTRIBUTES
Set-Document-Attributes
IPP_OP_SET_JOB_ATTRIBUTES
Set job attributes
IPP_OP_SET_PRINTER_ATTRIBUTES
Set printer attributes
IPP_OP_SHUTDOWN_PRINTER
Turn a printer off
IPP_OP_STARTUP_PRINTER
Turn a printer on
IPP_OP_SUSPEND_CURRENT_JOB
Suspend the current job
IPP_OP_UPDATE_ACTIVE_JOBS
Update-Active-Jobs
IPP_OP_UPDATE_DOCUMENT_STATUS
Update-Document-Status
IPP_OP_UPDATE_JOB_STATUS
Update-Job-Status
IPP_OP_UPDATE_OUTPUT_DEVICE_ATTRIBUTES
Update-Output-Device-Attributes
IPP_OP_VALIDATE_DOCUMENT
Validate-Document
IPP_OP_VALIDATE_JOB
Validate job options

ipp_orient_e

Orientation values

Constants

IPP_ORIENT_LANDSCAPE
90 degrees counter-clockwise
IPP_ORIENT_NONE
No rotation
IPP_ORIENT_PORTRAIT
No rotation
IPP_ORIENT_REVERSE_LANDSCAPE
90 degrees clockwise
IPP_ORIENT_REVERSE_PORTRAIT
180 degrees

ipp_pstate_e

Printer states

Constants

IPP_PSTATE_IDLE
Printer is idle
IPP_PSTATE_PROCESSING
Printer is working
IPP_PSTATE_STOPPED
Printer is stopped

ipp_quality_e

Qualities

Constants

IPP_QUALITY_DRAFT
Draft quality
IPP_QUALITY_HIGH
High quality
IPP_QUALITY_NORMAL
Normal quality

ipp_res_e

Resolution units

Constants

IPP_RES_PER_CM
Pixels per centimeter
IPP_RES_PER_INCH
Pixels per inch

ipp_state_e

IPP states

Constants

IPP_STATE_ATTRIBUTE
One or more attributes need to be sent/received
IPP_STATE_DATA
IPP request data needs to be sent/received
IPP_STATE_ERROR
An error occurred
IPP_STATE_HEADER
The request header needs to be sent/received
IPP_STATE_IDLE
Nothing is happening/request completed

ipp_status_e

IPP status codes

Constants

IPP_STATUS_CUPS_INVALID
Invalid status name for ippErrorValue
IPP_STATUS_CUPS_SEE_OTHER
cups-see-other
IPP_STATUS_ERROR_ACCOUNT_AUTHORIZATION_FAILED
client-error-account-authorization-failed
IPP_STATUS_ERROR_ACCOUNT_CLOSED
client-error-account-closed
IPP_STATUS_ERROR_ACCOUNT_INFO_NEEDED
client-error-account-info-needed
IPP_STATUS_ERROR_ACCOUNT_LIMIT_REACHED
client-error-account-limit-reached
IPP_STATUS_ERROR_ATTRIBUTES_NOT_SETTABLE
client-error-attributes-not-settable
IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES
client-error-attributes-or-values-not-supported
IPP_STATUS_ERROR_BAD_REQUEST
client-error-bad-request
IPP_STATUS_ERROR_BUSY
server-error-busy
IPP_STATUS_ERROR_CHARSET
client-error-charset-not-supported
IPP_STATUS_ERROR_COMPRESSION_ERROR
client-error-compression-error
IPP_STATUS_ERROR_COMPRESSION_NOT_SUPPORTED
client-error-compression-not-supported
IPP_STATUS_ERROR_CONFLICTING
client-error-conflicting-attributes
IPP_STATUS_ERROR_CUPS_ACCOUNT_AUTHORIZATION_FAILED  DEPRECATED 
cups-error-account-authorization-failed
IPP_STATUS_ERROR_CUPS_ACCOUNT_CLOSED
cups-error-account-closed @deprecate@
IPP_STATUS_ERROR_CUPS_ACCOUNT_INFO_NEEDED  DEPRECATED 
cups-error-account-info-needed
IPP_STATUS_ERROR_CUPS_ACCOUNT_LIMIT_REACHED  DEPRECATED 
cups-error-account-limit-reached
IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED  CUPS 1.5/macOS 10.7 
cups-authentication-canceled - Authentication canceled by user
IPP_STATUS_ERROR_CUPS_PKI  CUPS 1.5/macOS 10.7 
cups-pki-error - Error negotiating a secure connection
IPP_STATUS_ERROR_CUPS_UPGRADE_REQUIRED
cups-upgrade-required - TLS upgrade required
IPP_STATUS_ERROR_DEVICE
server-error-device-error
IPP_STATUS_ERROR_DOCUMENT_ACCESS
client-error-document-access-error
IPP_STATUS_ERROR_DOCUMENT_FORMAT_ERROR
client-error-document-format-error
IPP_STATUS_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED
client-error-document-format-not-supported
IPP_STATUS_ERROR_DOCUMENT_PASSWORD
client-error-document-password-error
IPP_STATUS_ERROR_DOCUMENT_PERMISSION
client-error-document-permission-error
IPP_STATUS_ERROR_DOCUMENT_SECURITY
client-error-document-security-error
IPP_STATUS_ERROR_DOCUMENT_UNPRINTABLE
client-error-document-unprintable-error
IPP_STATUS_ERROR_FORBIDDEN
client-error-forbidden
IPP_STATUS_ERROR_GONE
client-error-gone
IPP_STATUS_ERROR_IGNORED_ALL_SUBSCRIPTIONS
client-error-ignored-all-subscriptions
IPP_STATUS_ERROR_INTERNAL
server-error-internal-error
IPP_STATUS_ERROR_JOB_CANCELED
server-error-job-canceled
IPP_STATUS_ERROR_MULTIPLE_JOBS_NOT_SUPPORTED
server-error-multiple-document-jobs-not-supported
IPP_STATUS_ERROR_NOT_ACCEPTING_JOBS
server-error-not-accepting-jobs
IPP_STATUS_ERROR_NOT_AUTHENTICATED
client-error-not-authenticated
IPP_STATUS_ERROR_NOT_AUTHORIZED
client-error-not-authorized
IPP_STATUS_ERROR_NOT_FETCHABLE
client-error-not-fetchable
IPP_STATUS_ERROR_NOT_FOUND
client-error-not-found
IPP_STATUS_ERROR_NOT_POSSIBLE
client-error-not-possible
IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED
server-error-operation-not-supported
IPP_STATUS_ERROR_PRINTER_IS_DEACTIVATED
server-error-printer-is-deactivated
IPP_STATUS_ERROR_REQUEST_ENTITY
client-error-request-entity-too-large
IPP_STATUS_ERROR_REQUEST_VALUE
client-error-request-value-too-long
IPP_STATUS_ERROR_SERVICE_UNAVAILABLE
server-error-service-unavailable
IPP_STATUS_ERROR_TEMPORARY
server-error-temporary-error
IPP_STATUS_ERROR_TIMEOUT
client-error-timeout
IPP_STATUS_ERROR_TOO_MANY_DOCUMENTS
server-error-too-many-documents
IPP_STATUS_ERROR_TOO_MANY_JOBS
server-error-too-many-jobs
IPP_STATUS_ERROR_TOO_MANY_SUBSCRIPTIONS
client-error-too-many-subscriptions
IPP_STATUS_ERROR_URI_SCHEME
client-error-uri-scheme-not-supported
IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED
server-error-version-not-supported
IPP_STATUS_OK
successful-ok
IPP_STATUS_OK_CONFLICTING
successful-ok-conflicting-attributes
IPP_STATUS_OK_EVENTS_COMPLETE
successful-ok-events-complete
IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED
successful-ok-ignored-or-substituted-attributes
IPP_STATUS_OK_IGNORED_SUBSCRIPTIONS
successful-ok-ignored-subscriptions
IPP_STATUS_OK_TOO_MANY_EVENTS
successful-ok-too-many-events

ipp_tag_e

Format tags for attributes

Constants

IPP_TAG_ADMINDEFINE
Admin-defined value
IPP_TAG_BEGIN_COLLECTION
Beginning of collection value
IPP_TAG_BOOLEAN
Boolean value
IPP_TAG_CHARSET
Character set value
IPP_TAG_CUPS_INVALID
Invalid tag name for ippTagValue
IPP_TAG_DATE
Date/time value
IPP_TAG_DEFAULT
Default value
IPP_TAG_DELETEATTR
Delete-attribute value
IPP_TAG_DOCUMENT
Document group
IPP_TAG_END
End-of-attributes
IPP_TAG_END_COLLECTION
End of collection value
IPP_TAG_ENUM
Enumeration value
IPP_TAG_EVENT_NOTIFICATION
Event group
IPP_TAG_EXTENSION
Extension point for 32-bit tags
IPP_TAG_INTEGER
Integer value
IPP_TAG_JOB
Job group
IPP_TAG_KEYWORD
Keyword value
IPP_TAG_LANGUAGE
Language value
IPP_TAG_MEMBERNAME
Collection member name value
IPP_TAG_MIMETYPE
MIME media type value
IPP_TAG_NAME
Name value
IPP_TAG_NAMELANG
Name-with-language value
IPP_TAG_NOTSETTABLE
Not-settable value
IPP_TAG_NOVALUE
No-value value
IPP_TAG_OPERATION
Operation group
IPP_TAG_PRINTER
Printer group
IPP_TAG_RANGE
Range value
IPP_TAG_RESOLUTION
Resolution value
IPP_TAG_STRING
Octet string value
IPP_TAG_SUBSCRIPTION
Subscription group
IPP_TAG_TEXT
Text value
IPP_TAG_TEXTLANG
Text-with-language value
IPP_TAG_UNKNOWN
Unknown value
IPP_TAG_UNSUPPORTED_GROUP
Unsupported attributes group
IPP_TAG_UNSUPPORTED_VALUE
Unsupported value
IPP_TAG_URI
URI value
IPP_TAG_URISCHEME
URI scheme value
IPP_TAG_ZERO
Zero tag - used for separators
ippsample/doc/Dependencies0000644000175000017500000000017713240604116014622 0ustar tilltillmantohtml.o: mantohtml.c ../cups/string-private.h ../config.h \ ../cups/array-private.h ../cups/array.h ../cups/versioning.h ippsample/doc/ippproxy.man0000644000175000017500000000422013240604116014671 0ustar tilltill.\" .\" ippproxy man page. .\" .\" Copyright 2014-2016 by Apple Inc. .\" .\" These coded instructions, statements, and computer programs are the .\" property of Apple Inc. and are protected by Federal copyright .\" law. Distribution and use rights are outlined in the file "LICENSE.txt" .\" which should have been included with this file. If this file is .\" file is missing or damaged, see the license at "http://www.cups.org/". .\" .TH ippproxy 8 "ippsample" "18 November 2016" "Apple Inc." .SH NAME ippproxy \- a simple ipp proxy client .SH SYNOPSIS .B ippproxy [ .B \-\-help ] [ .B \-d .I device-uri ] [ .B \-p .I password ] [ .B \-u .I user ] [ .B \-v[vv] ] .I infrastructure-printer-uri .SH DESCRIPTION .B ippproxy is a simple IPP proxy client conforming to the IPP Shared Infrastructure Extensions (INFRA) specification. It can be used to proxy access to a local IPP printer through an Infrastructure Printer such as .BR ippserver (1). .SH OPTIONS The following options are recognized by .B ippproxy: .TP 5 .B \-\-help Show program help. .TP 5 \fB\-d \fIdevice-uri\fR Specifies the local device using its URI. .B ippproxy supports "ipp", "ipps", and "socket" URIs. .TP 5 \fB\-p \fIpassword\fR Specifies the password to use when authenticating with the Infrastructure Printer. .TP 5 \fB\-u \fIuser\fR Specifies the user name to use when authenticating with the Infrastructure Printer. .TP 5 .B \-v[vvv] Be (very) verbose when logging activity to the standard output. .SH EXIT STATUS The .B ippproxy program returns 1 if it is unable to process the command-line arguments or connect to either the infrastructure or local printers. Otherwise .B ippproxy will run continuously until terminated. .SH CONFORMING TO The .B ippproxy program conforms to PWG Candidate Standard 5100.18: IPP Shared Infrastructure Extensions (INFRA). .SH EXAMPLE Run .B ippproxy with an infrastructure URI of "ipps://host.example.com/ipp/print" and a local URI of "ipp://10.0.1.42/ipp/print": .nf ippproxy -d ipp://10.0.1.42/ipp/print ipps://host.example.com/ipp/print .fi .SH SEE ALSO PWG Internet Printing Protocol Workgroup (http://www.pwg.org/ipp) .SH COPYRIGHT Copyright \[co] 2007-2016 by Apple Inc. ippsample/doc/api.epub0000644000175000017500000013503613240604116013742 0ustar tilltillPK Joa,mimetypeapplication/epub+zipPK J META-INF/PK  JMETA-INF/container.xmlUA 0E=EѝZәФ)uozpb J㸫`LmCV8cs`t0MFq#v쉓1Δ*:OVYyt|:^:}`GTO<U!xg1M-n&?YWR/wPK JOEBPS/PK  JOEBPS/body.xhtmlw㸱(翂=I,3}v83//LJ!iTHn''WUXP{6!,P(;ayw鱨at4ilyW^Q?<$02spރw4wʲ t/~?M7]m;d:oyowh߃ݲPXO? юQ$F(0Bku?kYtpF?xx`On3^7'?x{߳bC]/βx R}_fMR?&4 ~ 6I4 덠*6$D`iyċ:)TLp#?s!Jp;/n;π$de}aڟ),YVLmRc6?=#LlDwhxA%~f )2 ,kO#5C8Pp=o7 ˼eG~?7MB`AN>{mğ9N?34X@]"{ X?{SFD C?Fz]9^?Q/47>'"'%_(JNRN{T ` 8ZA?tƬ!8'6ԪZ6g0*Y!Kq4 ~ <pBaG}!VN7?$K)GS[Q=oΕlMAq~Z(ja&/F:~0iӫ_N|s]aΛ vz]^z]cN {Hqz)kB0z|dAw$0%~}L~y 0YIQ4E$N~w5v6{> +G $~ lׯ蔯=xy=A<#\A:k"}`̛I<}w~ǃ&w;Ɲ><@]ئԿC8ir<.`6a-i̗ LL[шuV{ޏ%(hS/L,v:=_ `s4=-3۴+T#܅I#yo]˧kvL7%;?A9Iˆu1h~G/4]<ĕ4 ˜cC/76`8dau, 鐃z7@NM}A@(S'e';5zXlmPK(^!RQ*ym髰-x )ioHjnTwHk*,"1"p67:A%x_Q 4%MbEP5 sa} D# >oPq.}yGořk)2dF7?___ޜ;Ztɻ`% [QU"/9VTB^pa '=԰2Xӫ^Ah-㉌XpQMƂGrUs`Y(yyuv~ xH8y=|?FJeHizHzl6-'(1M8viٵ"sL|3Eo@_]@{OM6ϒ wH|tMS6sBo?˒7$Xx, N)IP.$<a{;;` N0兕L_Zu u~>UaU2{UA<ԄA7ˉ`Wz|7XDI7z,Wߘ'ˠye." tv {v'6* ~q)}/8 UyAG$߬@l>#@#:*yp 2d2B̯ͭMqY M&]2^XCI'sM\pz)YwgزW,joTo9qQ(u+Uk1os ސ݄s&,؄gPEO5?Q.ȷo9@7 $$$#" F7y3bqXexk4{0;tGF~@m8J:E16?>x@L=f`f S쎁\ Ŗ$P˹|1/pG/U!K0wh,\7bA>5'7U; „h?[c6w[>Z t.$ )3< GtwapG:>iĠĥa'7Iv&#I~O"طf _ EC4Ku鈿n! ,|g5ʏ T\47/..λo.5|wq$t l$ eaU1N}`^xuW&~bYFs/?On⋎B" & LAx(B~XKiV"#ܥ|\"}%%Uߌ;\!Ȋ{-_+~q|{zC?dVMd %3|AZ/NHTGO?ѥ4WVi6Po`t9A")4ٹm]RsH[K 61*J+tP;xHgo 8K''`Tae)-q*Ȥ+bq_"S?L^`눟yCD@/;;0ᘹ%DI l#ˑCw J-.q)hx$l2BkJ303E d%Z2#ϿQOkPUG[7v3]i/3O-n$9ouYHE%!MzjVԛCЪ>]Hoj+UaFC$uJòW0O !@K ˛Tx+Z< ξuy!UJ{as2ܟ>ihpf~{ts6o^:SE6?`IZ&+v@hBf5om~(\8w?]/WY[ROP ^0q*^$i`+ $x$vop6}z>IFN5,:1)D($՚tɎlNaۛ}?eE|~PgTp C7MأcI,kU_ϧNv;d˫nw!I0 ۹|wÂ2r^dPKB䜋z16vF1^:P0Baq'ﰷ|&ocR*V+N) +/#3RE26jfz)A`@* '\OT>ׇP;^Df\'-ErKLIK@2oO3RHUodu3t4]}@5[ xs6/2mmp7(Sn#]X l_ӌ` ,b_A@̂E@h d9^')+Ct+IY9`t3 I#oYص=(ɡGW'܏ϧgGhlʑa;IkEݘo`; i:Cu@o8f-Ln Ґ'GmHpG43c/HhEfMGtYO \ gjpfq3{j~IՆT'I!Z-3Ybxߋ0 K|RjzDٛT+oȇR{4.!`3E4ҭ67r~oK }<K?oU:0)n..J-}_p6가 mL,D8(߃ N4m Mz SLɍKh Eޝ~Ye0 qHn(* zt|880|~fmKHz>3d{\sJT hSuaQ=f ѨqnoLWRmyHxh.Bk T{b&Mpqh:Y ?Mc~kv1jfb$ JEݣipxgx `^Al# + <z(`egY wҐ(Tټrb-u}#ejwqĒӵ o<(zeod+O?t5:%$T"V L=슊!D1ܪl& 6 2*ߟrCmCkk PM7Wɋ>]혋Sk!6I;7l_4\MΌݩMUZO1of8C1oo$ ,n~ dޜNyjV[AƠwqɃ FpSd0Gw´o{\\;7/„I:&>L@%*Q(! foF]YU*B>c¡؞bbEUVC"~엚LcU) ӶHDP~ŨވLZbGp*GOOϯˑU*R'Q,ީ$WIjFjfɰ9)gl<%pXհgmd#.?P$ K"\ǻ`K."nY5j*W{4~n>p\=T٥@1&/ rĂݡ$52Br- }fS 8*r_9A ŷY 5{~ŧ5_Wo҇?LbK0m2QZ|![ReN.SiZH8>;tYf_{*17D ISɼMY?w.Tx"U-XjzZĈ#p^pC 7MSc˱N>w;q|QK2Υ;BF1 %6~tWg4)"lHi WK^B!T9b>OUvLoFRt24%TIIibhX<Ɂ% +VL7Ar84y Hf(ϖo&e_CAL,WO^^q^9`:L jPEwVba#:[>ʴXM3ˋ0Q(q#?K *'},.ۼ:^^m.MT[GUzQ҃g뽤2H6p{ee,EJ7 L_&C]: ;y7!&FC^ˏ^8Sa(r*ClJ; 2QIWrW~ca{Fr[5] 7,#ԬUNA筱߿0F0훠2 R)x Ud- 툭?)\Ůq犗qLiqE47m. vw%.x3qÿ%2:Rɭ ~b/( _¢Io7U!Ξ,,9ݑ{kB98J\V_MMnbVМ L:p͆]ʜ&6,[~JlVbvx(NXoNNn)ڐ PnHrT iQ7WLBY'mDk=b?I:=A#'n!(toĥ#2){ߖ"Y}?U O7KX@+}p=g$ ̍;VSNJyXPgf eҖ  T5vu̜ ;F΀cEE*(r )4#[}‹12Fi5"ߪ ŷjfxQ82nByk Ӓq'~=8\`_=xvf,0!Ekޡ;b:{q< Y.Szc򽧡$ac%:©ŋ%K>@e_= mG-: CnYQM rAj*TvEz>O{qOY{8֯-j]ap:gQ2Wⅉdv_2-Hޑ_y1>RIMyy}Xf|'doe3 H6hJ90UI>IO*=/qp`-hco-8ԗAU1-\@sgm1N.2^6\ajG3U[sRއ\~d2tD.9Ti H>ZCyr9tuR`1_pS~ PdL%x'Vdw!z*%'Lg\Lm|Vg$6dͪ2Ǫhd 6"G\w֦ >ܲnԔ7}9s)Խ:OY)WWW77'8qYyޞk4a{^ t"W[b {y[?<Mx 6em9tu>Kݧe'.vGBjh:; yŔ Iz8nÃ?M*ѺS+b4e:^8 taSq1airEMM:H@bH SdWd4̇䮌+ȽTnOؔHY驉 ]>fs%ȞT[ w.Åkv V]e+G:XnݒrJ#m`ÔTPel^{F^1=?!_,a/6 ?y~t˄7(k ɔ1cxWɁ~i5oSoS.8.!5-6Yviw56gQ[.^w,h Z_[JM>0.gv<-ce"]U.Us6MQg{:i% 9]j]q9wD1rxjvZ<NQm j; 2,텚em-|#0^(^ Bbݍ]-Gfu+*9 ye,# -zMA.7X%HVz;)#F )62s!DO}uIDR/Ϫw"B 7>{,~>Uͪ x!P[ZD/Q>- xa53 BÓ'x bS^ܡ ykbAM=0'ȚxUU< Rt\\< ! PFf` nW= 0SUԐ:r5 Ln6'<^d|y5)Ej(3[LRe$Zټ@Z0Ds!o;C0z[HAeY<-Ooe*@|:0%E7d֩_tYU,HQpжKExo~~~^ p0 j% :5\ս=޳T5=qJ*,ϝfľZھ]3LSr|i6]=޶@c<׽@rr/Zs;lgDAJUV*Mu)wU Ws^G2K]L O7Vjڈp>ԂwUp`*z>]5_XB!eud5X&((IqQ~(p *2DZ_ڏHR\`lN7)|.B#Owe~5 n>}Ó]Tz<wh%PnNl5buK]Az"2X1_j?3ͭYEkXףi0_l1Q?A(*_sqV_IgDgjHej֟}N lL*&9vNnTg=VcJa\43)bK FM ^8jء@9C[B9\׋KA|JQxbIq[ˑe%$Sʉj $ pNКߙUg)˳V(v&^(0M5 ]\T@NOx;^w0'ekWa~bP8K0)"_>;/o7Gj;^u_NUՎ/>^~8>=iӨic0Β\BY5Z3MhĉsdR'Yf 'U1Oi*/L+cquN'ld"|_x K>Nr,pTLD\EiN>&r& u1xݶ,2ȁ:4<}`CՔi>ѣS?v: c^ޭ"iNS,Kc :rYv eT^VTh  )2j<҃|ywH.(9-ag?9/kd J[SCCω*rKQOI\GqfñD[Т0:b*\ &jPHV/ $ pۆUp 4IV4ybY5. [W7dwԿ-Ɇ =wO7|lL}ɚKC1ܕ̔s؟bi! wݘ+E.(kʹ@ ЩV(d6Z`,CyT֜FFp+ۣ󧪉&5[ӺI.-h̡5[u{yzFQ;dʛEmؗ),!&퉽fw%g)C,QPsUӢ`2^n]n8/pjpױ( 499?꺞f5RB/FM&j|~ˆy~r;7xuGw{Hn~2;XL<'bODŽ 4 Z~ͱls_@iBr9;Y(@ZA!\da6L2gd%HdwBi5V/4INlqR$)N @Sm7j9rV4 \s'ę*KZ.#w#2S #>e45' م;|b-h8(FOR{fnɳtҢvF^\OPY<|(.}3n`*$rÿeސ:~x^<&EpA(2 bސ#v}w8%6,avyMe7,aɣ9ǢZxzJ[;\~FXAG{a$00NQ揶Ov45!}]g?_BXI"5уns4&~+ l @EqĞN"cHmFrQK_@,L(X~9tG,5 36)'/'1m@&_nMu~N!B^p;kM3|} 3o삩|Cuڇ5eŜKNIՅDGVr׿R t%¶f=[$gQvlJFj*JȠT`|M RBB__(-3/uCg +pEB`u} x9qKڑRhBq!f!e>5W[rVlMԦ ݳ)lxky.~UڵgE~3;-{gcIEo-| (_eIE+vۚ6ZXiPXy+ R$5#]+HBf\ep#%qI>Iol/NӋw;;09ao&Zc/2vP",sS委[ [ lԳRF?1kB%Ī h.lbN" o \LP`) vYD$|ӵk6viʦx+W$ oYJ*MWޠ4g9Z ´?旣N|RyK$n< >\`3R\-^|72{e7u9l~B1KrBǃGI eSV]UA|F*5,g79.c够CbӧT] v0#qi,E/o-[SUHy ? evJؙ'Ơ)uNrk#h ;s4-p%''-OH)\ǤʌI3f(i#(0Vp}x/Wkz`|#4<Ƀ4 z@#w>hC/"l]O6;'jwмyGJe!XlK>c,o=2q|ܛdN-`b3;λ)7%SJM5^+\KF8,A*\9K bj.BFiÇ,BmSS J|XY !6"OP(vPKq1'?!NETR{7 ٥~D˭M\ƿ]: ֏^3.6ٺ $S b-ŖE Ksqw& nEs <~R0ӍDUre:8Yp䱄Di!؅j|SKZDAԃi}X0++8N\Oa6c 3uqBJsTntj KHPɎqP*S\wWoq\ZZd#2r)8 5}~ttj^Ҭ y7Ϣm}a٥]'- Fۢ.U+*.m-V.y+ 3eX[3VӎˊOݵ"es@^]__V([_m_oYvC5o2n)r(ąɆmS)yotga@}SnE1::}6r^,0PC|"\f9}I=- ړpi̲gq" Z=x$Z8ۑ@܁06d_+4Mi$r;_z= ƷF8h†Ƹts^VݱPÐ 2[c{g@˹QPX>y0fl!F*@  䖶D IsEMʱ92W1WN&+ЎOS_6o~.(;& '.X*yvt޽<=֮'bݲB-:u%k>9} 5R 3Xٿ"|qr;JzV|'࿺!׋ HYbC"Oa8X{^H˦EG8,U{jBo2𯕾o~@K <4E5:q('i P<-.||qytAt ~[# nVs? e>@.ueH-\=rwD@s,^r6va/(԰= .PqԚhq'tP'3Obs| +{;ʹ\|3#?3rM *k[KŗFr@+uB}u{#L~^`o9*O< §Snan$0twPbp_!x (ʆ1?qVxrV:DΰQdž]Y 5E>*jBW [<'O_nې/:OPNx a0ߛd(9O80lE fw<}G~~R;s YqVm=6h5El@ (HMPx7ހzZn>ײ%;n_5>=32""'W[(F5 wyE84ǥf}4 OPX;js;Zmi(٫EFB$:5ka+ҾJbJ똇ڮ&lH^(tY t_h<9y%\hV1W x_N.䤉œPc{|ru<]_9q=-_(AԾ:bEXg3c7 @^KōhLsOw q<(L)6HiHƆxە&~]2f^g`|Fb[>t y7鬑<.y:ud~8:pqM!;a7[j!Y#G1ry[F+y,}5"}Ǹ%'*0Be$sdX" SDؒC|6!w]ڿe~!5әNEԑ4V͉W㾣#PsMKtm/Q~&r_WQ.R &OQIZxӞ:" HioW{$1u#=J1=7i"G3NĻM/SE_-o]cLG+pS5QU|ǁEw - n&E%;yY7=v2hH}ro-H[/VE&S\>N(}B ;9yd@hmDLE% hQҤn֦O%꧅4e3 !5RϧG'B5`X c5}Ht5sN_-5M36 >%~ `_-n06*$hEz R10 fFSޗRԥaդ,X@gj^vK}v1BX8 cf)8d B Ƌ2^eŒ|?~P :U(l(PW'ɉXaQ S=(O8%f vp N| $N~@8  ؍ Jq\6x J2۷}9v8fh Z;[Rȕ iK )r/m6MxD@]R9א]L%7"8 7aP q}܆hn8 h1IhR)zT-owyх,_[=qԦ鸵dGkP. `a071e*5%L4@%t:$;gdVP[j BTJȻ>8R1׺źXn3 ia}g5ae|qjFd˪ c#zpQ'os'#O:*1𰂱J,$kam,3^Ʃsc^jqKl* OS7SwTkkY{2^F.+w򤇕kɮVposthBhצ)"['NHˌ4Zh\#{nsCB~ }þ^;|  5lR8sp,ӂRnEHb Zp 'Gs} =EMKb,hR)ll0%:צvWqs!v]\M#oFaKyWbFv1~8{;? jtNBvPi` =M*_JlV+ZdJL'`%KO]ӯPؐyUזͫUoZ /}嗃֕7IS?- ] 0K'q BܴCffmř:PXvv]*匽oTR GKhFo;萢=NK)i1vx p9&]JXI&+0em1qi~:EcΓbj5>kY׺s[n,:ɘluV.=>6)pL».j1r{gxdò;3o5:C2%? ]ya-!M?] @*EJAzx\GcYDCLd\<_#2sBGmZec}~ϯg~5%CfD4=9d3Wwke\]~M\rYJdbk+9j]# 37  ɌG@n.ok:UhSnXfZ7]/nEXw\pDU5P8JOF;fhRV(w߰64ZzfxtUzdXqpd]b|I0'<RP2b?`ҮNYG{4]Hb:ɔ*s8rDA8`UKČ1Ka߉ oǛSPo!Xarz,>Z󬯒gPuK)uR~u-R~YXXHd/G]h oёR.d-׷n,ɛЊUMX¯O"g#aWu [ķW>fkb9%|3oz~H&5,ouCkEES8=/< U_&ߊ)$aWOA1즇ڽgI/g(>'ܦ{Bp- M400T3_vBJ*׊НA< 5{!mnRvy|nS9]+5kR[2bH{#.mi$&:wc\.;7_P&eXYsGoGzY3ry OVxP˽)}V~E}@<HCGW+8+rD혲2ĉ{eף8$7]t{YH*o-vBJtHVnAĭ ZMK^d?YċQF-hXXoo^Xw2ұӴP+K+|S?Osx4@qYnB*}8^l--SATأt:+?Ji,Aj gVmݰ6ݹDDh+ ɻr=V.+#F"yɮDX|Qf#BFaڰ/ |oشa3$шCvkn_+?XrA2 q< $] ď8&04(<2'KeeOG9jbez e!B!NZc eأzλ7R$RҷOhz}+JVKiwiQ[<|a|hulgw8īe85q8|[sJV); 3IhZf i0bn 3 "]: E\?1g^H/9ݳ`wkoF!'k65IRK>[gjr87[g66n'OyeYtXqQtYf#%f8F$8!K@9f&ˮ9A? Q58>R38Z=Lf9I K0<$`wcPn h ,yJd쏞ٴLW#av ǔJR:8Ғpωf<唊<~ɞZT4NZ$T4v2" j\\lT:] |`)Q2^L,8HT`b1l4W'A6cLł];-:IzC#E/ŗXѭZ}7h]"j4QcTҒ)…w}G}y쯔sR`-!ZnᵂyԲP4$VB-X?1!?nX}O5s7l-&_U(s/[HWcӚnY MDc-؉Ne0\nW9lF*.ZhXo"nR_#br &C׈5 Mb)fq#RS vkbĘseT7JSlvuXo@5淧y"Eu.2oP 7noBL\Y<1Ez2=yiiRDK^ʯ/~l:}4J[QV Wupb[csaoxCBr@EltG2@Z#DW4rt&U&[Ԛ;a[D%"moGnGFN|Ͳ"l$;۵ѱڿ(,YQVz`vlBzם.G=Xa;X|/)wv_NPc%$8bijk&Zs'mmB_pæSEn]U/26xwu(؜ͦ7zB\~> %KKIeG83XNmc㉒H-^Ze_k7O$?/18*Fj/8̓ҀzSkrDZ NgY:% E3 9O\-4%\@&];'p͇\/Q%YGƂʤdhX_hgW|UosyPald[ANO;tƞšu"Az oЏi5jj->ZGV xMf<` xZ+&'UFF({Z>-hy;(·,@n=ℱP 2UY @Wj/my,^,bKTmKi- r+h {9TqAtlö*u[٩C ]u|1a fq]L4Œh$Dnv&9S>~NA2/luo]6-p4c?وcP2ޗqy Qɋ<>$Lq!ڑ/sl|n8LȆMj~ [Ɍƴ?܆YFocV/Wm85OtR:i5'pG:APl 7jXdm=Pwv5mg q[ 0G<2 v.͟A\-%[')%pOHK2Ŵ4˲l]w_P˼TW^w(TzBYjkFGVDp9 ,B5`f0PȗĪ;# -tk5V5q%ڱK]&Roj-Xyabqtcqt8\zڱsI鲦բ(s >Es[#H׈9BFY7zdЬ2m|V='/$)])]m@DO!K&+\/*È ,(G8 =?ROn=,x|3ܭYCɃӿzmqlW&P5vKP]B(O؃ |Dl](̠/m+Jh*>zW2kU-`\@٪n:=t91̢TڞV< W(MIu"ip8GpmveM6?Z**w9 [U7Pzv(8|ؼC]el{hxsqƮ/K n\:WV^U_Mbk#qEd/*(,*n8AI`oㄥY& .iFT߾(H,߾{0-JE"tT5R6 =ܭ1 BÜ]su&;Ya΄%},<}D0c]:/l,tM0/׉ѕ=/}tDm?*E:Yv j#o-z4;;{<֋ u "+LpQFp4K}XMS:Kx2sV Í3$b '#%0JoRԑ%*T[S m Q&HĬz$h3hZP!yښJ% >[@hYSٻ0 %{5 *&yP/>ć@:=q8xчA *)YLL\X\^hQ]5.أ L&Kcv@bQ&~ypt%j_`X'|_Ҡ;)v@|Q^n2f mJq3]/FpN aAp4 eK\,:ns P1#dao +r\?Le'oP?6PmIzw&Y;?3B&-)=a/b!V4p*^o2nDMXNf.Ndt8[x@vk7|L.ܵ;9:=>>=d5VZ\iF"p[LެW{ەEWɓ,cI_WfZY6 cfbsu7@6*`3 ]mXO9l_fU eZ.)$]ԓSnAη|xn_g) `|?\.bԘ,tQcb$᪴,oq n)SjvQVkUW1?3d),4ބo1`b)B1̫]D?V{R1biqhǻRewR|ՆI=!ށ`c'Nnr޾y1lX3 {Z:jfCĕ>ta6)4#zkN+,̓|nˏ$ EazmfKf>>ӁL 8Rg_/[r? A/JiXP(M:K(̓?p"`N:yƍe]`w`+/%$*$5spV E*$ew}%z$p2Uu+ˑ8'A<>Vּo}̋)gxAz QQ]FkbXz UMvpYR TnP֔WOVW%?O7&Q>1'fA%jTV&͚xrrNn)RLZV{b`1EY{Z`0+[# N1jetEF٧3*Y˳\xU%JڐJ UʿRN+k_y^ 5W5RI|D{8WKuFg"hT?CwDɞK'5gcHq  rVx<|)e`Ѽ79t,[z씋`ԣ/--eC{2@ȢEPqK I\`1HϷ-xj?hm*igsJ֋fX;SZ ZQ#B3 8MNy8-R %jI>7s 9sC R!ddZZ7څJ6 (7O^j<81%qfYiT?hmZV0三0fY]KC{eMt-EײcAH5W<_pzN9FQ'UAgZ: خl5+@*JlLz" н8pւݪyY波7x",b 4)عSPĝ7K" '*w޲xq~-8Z_iƗ-<9 IIı&&b!x(6MTfhmsZ&s}忋m oyzNlxvZ. B?h*d}ٴ+CLLx[o_K'?+4?kX<^z@E&c:C1(ޛE䊅!B5!'`K\{4B]epGGtEywȪ Ϟ>doXO$v6Bl,Z,9&0F!8o_J36J4'ܖq tf@=.qxHI]A`3`7ZmzoUJdIf5cy Gt"NU{OΣpi6j4lc.s|THܙyR.f% 6oy՟s/ťz(D WwIo1"2U_o0FAE>84Q($dsJ "4pQ8yspNJJm3sNRls[έ.I̍55kjԈ_S#F]S#f6>)HHHHHHHHHH%5|w4M,OZ4-yy'VLv)h]97o7D#,>(-e@k۸u 0\~Z%TI"t]{i>B3!R+sPe?0BU/?ef[6D$C6X;oFu,`A&#% *ʸ @RT>ʯpRi)WG{lNWרod bV.EW!UOk=P|I[3 #;p+%$bW(j%E7q3҇f[ߖ=*FRcp#˨BSy+ƚ+jC\TTyja]ֈ=+.^OPz>Ӿ90x!b\˻SnUM?vjb`QQ2m+52q h뭡k?/bj%"t 3wD5{l_ G2|tH}R NjnAQO1Cun [ ."W}-1O)Q5wHOͻS9^v"rnrTɓ~0^iO#i/T$Dyو>`ߡ[Kcƞođ+M,Bc6qywljqyljs|ǡcS=Mj~<65?rġF?{!=:9,q;:9,yl@Dv?jg$Z.`Ui9-U<&HvA fDӹSht#'i L%{2a?ȄxZ~$i L~bL){C{b¿wb81et?1eDOW]kM~3J7 U(B-cnD30\ػb;iz]s,̷} }Xh8 Gl8ߜ鯛@[]}@~Y 3'CwD{;6菛%{} C0*X&YԹ]ҞN#ɽyyɨ{ئ*m|09w1C&i3ם-Q)/thW0I3 AApi>@rgqg&2'*GIVJbOm|b߃~:a+r Ty+;RW~Q?Q٥&x?['YQ {QU N$i+ SޣhԄ1*y'jb̯i#rMep}lnt' zk'[.4V>9pQɻAyWg1߲i z+Vp n}̓&ct^2iO [7aC]Cuߋx;_<ΖcJ1W5u_{Jrڴ3x}crf_*^L %3ao#1wZ\Ў ]hټAtL;*I8.(-c4lbxާzk6?7O-n }6KShRMo˖ֈ裋  n1DDcKöiL{AN]_39^9\$]5з gO~+!>t/.t?BH[QGDt=Wn[IusLцr@RfFoYL7 [?u#-Dzm%\#Q^x>_&#U䪂!z*)ylZ8«r3f"InW=Bƕ~M kwRzAg"茳vT`/;V7?ۜG( !ΧJiwD mofU_ Bm4eAvm /J\=".J}'e!+2즘,&e,Ҍ ~ˋ ~KSB__7dq&,|I $v/y;ނ…h8}>7{=j?ƟyիĉmƔɪk ^](yUMhSO2ӽ\H^~^TnZW´h[I+ĥwVb~W~rAMdž=G\/V)^Ρ {5cmsX,؋Fkƴ{i]rlx R2Ť{P%FWElP(r3텑9䐊I@0)FN(nHքl/J1VhΛC8Cy:/*(@⃉@gW3*fا/R]Y3cG Yh3ٕDzWBS*>6w903pfn>`ՂrO[z16X/gILi;!Fy7{BJ,5ꙌX! yrf8_˓%&M\0NJVxH[YPfRn*գe.h6ii5N1\)2ODz&y'^lq cjI~P:l$9%FOCY XByUCX:2O\`\̠B{9U=ȃwΕv/!W:Zs dy`qIe-YSj5= QAF0P5ˮ!="{ PݽW A@Oy mu* ڊ/0Ol @Vց[p+f`#6w6ᥛOfgO3ۙWRl.ծA ಇ'GFA([G`#$y{ n ftCzܶDv3WUԌ6KU)w k'L,&5LkbwmT/Uwa6~D|~"J~k?)w?ﱟWkQrB-\[x6C^wpm -sq99.QR=^4mj<<Ω0N#ejS:Tљ#q4>w\lcta Æޡ, VZۄC+ { `)&='U_wxU}7_Wqn@Rߧ/no2a\}h,j"^eFbEı.mҗqv{ICsJӟq:~SN]R"nv 䬭܀bޮn5g7 f)mxJ '.S{Oa>d=^L6B_q. ]3߹D`IB*O{@Ÿm6_a-Y*hDr`Lg3oufyQ2yib7y+~a+fnny-ż$q$\C7]xi8.rl`uz;5/c.՛lŢ;mC_.@UeoZQarB`t6f +qŇ-HɹӕKLvJ&km;n%*U0_A:G_[E)dD"Y[Dk:N屢ӁY*c 6Ԃ }wA@vU 5!Akhi߬RCPe r)hԏ_+ ]T#^,gn7:QVgIaMȴcPnYxB֟0L蚼I@g~4ֶ^fn%PzQs&?28qV-=doXWp@l7"+-oD@kNUYZk'`hkh8ZDiEW$]3Ua`7R! [^"FJ9hƹ'P<\Dmda\r,3ulqu=\EBT%.{;q;4P,2DZ|mo2PAT{1_$^]5F=v{0:3k>]+RS c"9Lik8tCGvx*s9q{PT*xRzȐxOvpڨ-j’d<,@.rzY 3<?;[qa9"= Ew}GGqLGa-+O̹iS/I+RO) (_Bn.6yturK^ksq ~+8Y>?6-_!=q#5 `{`uύ$9"ã@ h>u TranxFQE6ψQM{ny'dSEϱ'n 1bgy61Rp:ry@P;nEG%t3n ux3Vu!=SqƼYRN`=ݓӿ #):;^tj)B t>";kw* 5G7ݕ@jJQo%j%C[-TgkV_ނU=Y9V21W^+d B@Rn=[9Sg6Ė{h䍧OP}h%өjECz8C4͜@89M-8nt)Ѷp cؘ\3ts8Me{BA3Cm#V<6'O94I+Ztꓓ;§2J8:VS [)0s)cձ*r'݋`,Ȓ9Ԅw1bDxzR=i"A#Pr%X{ԺA^).V` eR6 (QsdH]FTr|ひܿƈ4"E[F^ػ_Իvtڽ6Dz?ڰk x_s}t1/2cw+ 9 pX@Ι,vris ~{X :Xy{i]Af̨ EoZ8zEA{'7QW8}p1JRshǵF%TKM%&ķi7 kJOT_ 8uw&#>L]IZ6-+\dLGҴUlC^4!cYe30w@*J "M*PeD N/g7 t.ܔ4PK  JOEBPS/package.opfn0rQ&( i^VG'TŤ"n\ָiw"GW] #B/V';J|x#$^li'# {Bn&+5`)i5d;h\hOPK  JOEBPS/nav.xhtml[w۸)Ty]EmmI-,&%H;jO{jw3×~=YV?~՛?\/Wѡ9xՂzwqOowPO_fi6]_.Mp5}Xţj>Zsa6KBk֜xGkSFEY?F$BSH^FD܍'2Ene2:԰?v}li>{_-dzy\]^?ݺ~_Mc墟 56s[&NۘwczɃ5#j Zas|:Z֩Ivp͐f5_W%& ̖sq}XϷꭘ.5yQ}Fm<[\ zY'|sߋiC!~iI5Mf$y1[/ˇXv^Ngq ;C]eq=ˆ_Ob~> g9Cb&M[#k+6Ikޛc`NU睡H˙&r~J'xk' @tћn UĞ&%M+v0!/w_zNS9(&2g5,&+:w 1 D*scO$*/p=ءhkt5@'Q_M]Jc>Q8"Rlܠy#`YШIM y'(DE$s"#Y4/RΡ>g9Kl!T? yǣJ4"y,FD>2oRøI)~A`MDFA(!N;B1 1$- `E=et:”@`U٤,.;I$H[X}š.&1$sdN*I,wI`)j(ẓ!JNreOqI4z0acIfU4q^ٵ֘dN"2$zX(jG는v[kGzGOqE֬oxK>.Rt|KM[u(5:UrbJ>YApWr ; [U &nvP5hwҟS4BWO! P;p$q8$) `E=XDUyM 6u4)6T v Suss(iHP8&D2P=4W~i+&l iUNEط$C}'+XZwڌ~!9$|Q*dj%v&hba(w<(ӷn$"i/jg/f ID2WiCR6nu-d"hq4u2R'2 >N K&(akYwdXMbC[|c9j$#`Yevee~MVw`L,ZX @%wD ]ۤW Օ[tݵ9kքFԉlR\Ku=aI228B뮻hx¼hYd @>-wnyړY?$EjhZIl3 AmZw^Zeq֩Vi,o*Pg1{2%PIǺ՞Z(rIV0wa4"i/yQeq#"ߨbOH'u$Hv/rXS$A5KऀdC8s͚ZXoSHNGS|mDOESkC'c:{Kk9S({3.PۺlM)Ɠ\aM f M RUN apt-get -y update && apt-get install -y net-tools iputils-ping vim gcc git make libavahi-client-dev avahi-daemon gdb tcpdump RUN /bin/echo 'colorscheme blue' > ~/.vimrc RUN /bin/echo "LS_COLORS=\$LS_COLORS:'di=0;31:' ; export LS_COLORS" >> /root/.bashrc RUN /usr/bin/git clone https://github.com/istopwg/ippsample /root/ippsample RUN cd /root/ippsample; ./configure; make; make install # Make changes necessary to run bonjour RUN sed -ie 's/rlimit-nproc=3/rlimit-nproc=8/' /etc/avahi/avahi-daemon.conf RUN update-rc.d dbus defaults RUN update-rc.d avahi-daemon defaults # RUN service dbus start; service avahi-daemon start # Once running start the services needed for Bonjour # a. service dbus start # b. service avahi-daemon start ippsample/TESTING.md0000644000175000017500000000073513240604116013203 0ustar tilltillTesting the IPP Sample Code =========================== The `test` directory contains a test configuration for the `ippserver` program. To use this test configuration, run the `start-server.sh` script from the top- level directory: test/start-server.sh To modify its configuration: - Change the parameters to ippserver: change the arguments in "start-server.sh". - Change the printer configurations: edit the .conf files in the "print" and "print3d" subdirectories. ippsample/SCRIPTING.md0000644000175000017500000000646313240604116013434 0ustar tilltillScripting with ippserver ======================== `ippserver` supports a simple (unauthenticated and totally insecure) REST interface for controlling the media and supply levels of printers. This interface is provided for scripted testing environments where you want to control these values for specific tests. The REST interface is implemented using HTTP GET requests with the (web form) variables passed in the URL. For example, if the printer URI is "ipp://example.local:8501/ipp/print" the corresponding REST URLs are "http://example.local:8501/ipp/print/media" for media requests and "http://example.local:8501/ipp/print/supplies" for supply requests. For "ipps" printer URIs use "https" for the REST URLs. Setting media and supply levels directly affects the corresponding printer attributes ("media-ready", "printer-supply", etc.) and indirectly affects the "printer-state-reasons" attribute. Controlling Media ----------------- `ippserver` printers typically have a single media source called `main`, but can be configured with any number of sources using the "media-source-supported" attribute. The following variables are supported (where N starts at 0): - `sizeN`: The PWG media size name for the source, e.g., `na_letter_8.5x11in`. - `typeN`: The PWG media type name for the source, e.g., `stationery`. - `levelN`: The number of sheets remaining in the tray from 0 to 250. Omitting the size for a source will remove it from the "media-ready" and "media-col-ready" attributes. Setting the level to 0 will trigger the `media-empty` and (if a job is printing) `media-needed` state reasons. Setting the level from 1 to 25 will trigger the `media-low` state reason. For example, the following `curl` command will unload all media from the `main` tray and trigger the `media-empty` and `media-needed` state reasons: curl "http://example.local:8501/ipp/print/media?level0=0" >/dev/null While the following command loads 20 sheets of US Letter media and triggers the `media-low` state reason: curl "http://example.local:8501/ipp/print/media?size0=na_letter_8.5x11in&level0=20" >/dev/null Controlling Supply Levels ------------------------- `ippserver` printers typically have two or five marker supplies: waste toner, black toner, cyan toner, magenta toner, and yellow toner. The color toners are only available when the printer supports color printing. The following variables are supported: - `level0`: The level for the waste toner bin, from 0 (empty) to 100 (full). - `level1`: The level for the black toner, from 0 (empty) to 100 (full). - `level2`: The level for the cyan toner, from 0 (empty) to 100 (full). - `level3`: The level for the magenta toner, from 0 (empty) to 100 (full). - `level4`: The level for the yellow toner, from 0 (empty) to 100 (full). Setting the waste toner level (`level0`) to 100 will trigger the `marker-waste-full` state reason, while setting it to 91-99 will trigger the `marker-waste-almost-full` state reason. Setting any of the toner levels (`level1` to `level4`) to 0 will trigger the `toner-empty` state reason, while setting it to 1-9 will trigger the `toner-low` state reason. For example, the following `curl` command will set the toner levels to 0 and trigger the `toner-empty` state reason: curl "http://example.local:8501/ipp/print/supplies?level1=0&level2=0&level3=0&level4=0" >/dev/null ippsample/config.h.in0000644000175000017500000001407713240604116013573 0ustar tilltill/* * Configuration file for the IPP sample code. * * Copyright 2014-2017 by the IEEE-ISTO Printer Working Group. * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ #ifndef _CUPS_CONFIG_H_ #define _CUPS_CONFIG_H_ /* * Version of software... */ #define CUPS_SVERSION "" #define CUPS_MINIMAL "" /* * Default IPP port... */ #define CUPS_DEFAULT_IPP_PORT 631 /* * Do we have domain socket support, and if so what is the default one? */ #undef CUPS_DEFAULT_DOMAINSOCKET /* * Where are files stored? * * Note: These are defaults, which can be overridden by environment * variables at run-time... */ #define CUPS_CACHEDIR "/var/cache/cups" #define CUPS_DATADIR "/usr/share/cups" #define CUPS_LOCALEDIR "/usr/share/locale" #define CUPS_SERVERBIN "" #define CUPS_SERVERROOT "/etc/cups" #define CUPS_STATEDIR "/var/run/cups" /* * Do we have posix_spawn? */ #undef HAVE_POSIX_SPAWN /* * Do we have ZLIB? */ #undef HAVE_LIBZ #undef HAVE_INFLATECOPY /* * Use ? */ #undef HAVE_STDINT_H /* * Use , , and/or ? */ #undef HAVE_STRING_H #undef HAVE_STRINGS_H #undef HAVE_BSTRING_H /* * Do we have the long long type? */ #undef HAVE_LONG_LONG #ifdef HAVE_LONG_LONG # define CUPS_LLFMT "%lld" # define CUPS_LLCAST (long long) #else # define CUPS_LLFMT "%ld" # define CUPS_LLCAST (long) #endif /* HAVE_LONG_LONG */ /* * Do we have the strtoll() function? */ #undef HAVE_STRTOLL #ifndef HAVE_STRTOLL # define strtoll(nptr,endptr,base) strtol((nptr), (endptr), (base)) #endif /* !HAVE_STRTOLL */ /* * Do we have the strXXX() functions? */ #undef HAVE_STRDUP #undef HAVE_STRLCAT #undef HAVE_STRLCPY /* * Do we have the (v)snprintf() functions? */ #undef HAVE_SNPRINTF #undef HAVE_VSNPRINTF /* * What signal functions to use? */ #undef HAVE_SIGSET #undef HAVE_SIGACTION /* * What wait functions to use? */ #undef HAVE_WAITPID #undef HAVE_WAIT3 /* * Do we have the langinfo.h header file? */ #undef HAVE_LANGINFO_H /* * Which encryption libraries do we have? */ #undef HAVE_CDSASSL #undef HAVE_GNUTLS #undef HAVE_SSPISSL #undef HAVE_SSL /* * Do we have the gnutls_transport_set_pull_timeout_function function? */ #undef HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION /* * Do we have the gnutls_priority_set_direct function? */ #undef HAVE_GNUTLS_PRIORITY_SET_DIRECT /* * What Security framework headers do we have? */ #undef HAVE_AUTHORIZATION_H #undef HAVE_SECBASEPRIV_H #undef HAVE_SECCERTIFICATE_H #undef HAVE_SECIDENTITYSEARCHPRIV_H #undef HAVE_SECITEM_H #undef HAVE_SECITEMPRIV_H #undef HAVE_SECPOLICY_H #undef HAVE_SECPOLICYPRIV_H #undef HAVE_SECURETRANSPORTPRIV_H /* * Do we have the cssmErrorString function? */ #undef HAVE_CSSMERRORSTRING /* * Do we have the SecGenerateSelfSignedCertificate function? */ #undef HAVE_SECGENERATESELFSIGNEDCERTIFICATE /* * Do we have the SecKeychainOpen function? */ #undef HAVE_SECKEYCHAINOPEN /* * Do we have (a working) SSLSetEnabledCiphers function? */ #undef HAVE_SSLSETENABLEDCIPHERS /* * Do we have mDNSResponder for DNS Service Discovery (aka Bonjour)? */ #undef HAVE_DNSSD /* * Do we have Avahi for DNS Service Discovery (aka Bonjour)? */ #undef HAVE_AVAHI /* * Does the "stat" structure contain the "st_gen" member? */ #undef HAVE_ST_GEN /* * Does the "tm" structure contain the "tm_gmtoff" member? */ #undef HAVE_TM_GMTOFF /* * Do we have getaddrinfo()? */ #undef HAVE_GETADDRINFO /* * Do we have getnameinfo()? */ #undef HAVE_GETNAMEINFO /* * Do we have getifaddrs()? */ #undef HAVE_GETIFADDRS /* * Do we have hstrerror()? */ #undef HAVE_HSTRERROR /* * Do we have res_init()? */ #undef HAVE_RES_INIT /* * Do we have */ #undef HAVE_RESOLV_H /* * Do we have the header file? */ #undef HAVE_SYS_SOCKIO_H /* * Does the sockaddr structure contain an sa_len parameter? */ #undef HAVE_STRUCT_SOCKADDR_SA_LEN /* * Do we have pthread support? */ #undef HAVE_PTHREAD_H /* * Do we have CoreFoundation public and private headers? */ #undef HAVE_COREFOUNDATION_H #undef HAVE_CFPRIV_H #undef HAVE_CFBUNDLEPRIV_H /* * Do we have ApplicationServices public headers? */ #undef HAVE_APPLICATIONSERVICES_H /* * Do we have the MuPDF library? */ #undef HAVE_MUPDF /* * Select/poll interfaces... */ #undef HAVE_POLL #undef HAVE_EPOLL #undef HAVE_KQUEUE /* * Do we have ? */ #undef HAVE_SYS_PARAM_H /* * Do we have ? */ #undef HAVE_SYS_UCRED_H /* * Do we have removefile()? */ #undef HAVE_REMOVEFILE /* * Which random number generator function to use... */ #undef HAVE_ARC4RANDOM #undef HAVE_RANDOM #undef HAVE_LRAND48 #ifdef HAVE_ARC4RANDOM # define CUPS_RAND() arc4random() # define CUPS_SRAND(v) #elif defined(HAVE_RANDOM) # define CUPS_RAND() random() # define CUPS_SRAND(v) srandom(v) #elif defined(HAVE_LRAND48) # define CUPS_RAND() lrand48() # define CUPS_SRAND(v) srand48(v) #else # define CUPS_RAND() rand() # define CUPS_SRAND(v) srand(v) #endif /* HAVE_ARC4RANDOM */ /* * Do we have ? */ #undef HAVE_ICONV_H /* * Do we have statfs or statvfs and one of the corresponding headers? */ #undef HAVE_STATFS #undef HAVE_STATVFS #undef HAVE_SYS_MOUNT_H #undef HAVE_SYS_STATFS_H #undef HAVE_SYS_STATVFS_H #undef HAVE_SYS_VFS_H /* * Location of macOS localization bundle, if any. */ #undef CUPS_BUNDLEDIR /* * Do we have the C99 abs() function? */ #undef HAVE_ABS #if !defined(HAVE_ABS) && !defined(abs) # if defined(__GNUC__) || __STDC_VERSION__ >= 199901L # define abs(x) _cups_abs(x) static inline int _cups_abs(int i) { return (i < 0 ? -i : i); } # elif defined(_MSC_VER) # define abs(x) _cups_abs(x) static __inline int _cups_abs(int i) { return (i < 0 ? -i : i); } # else # define abs(x) ((x) < 0 ? -(x) : (x)) # endif /* __GNUC__ || __STDC_VERSION__ */ #endif /* !HAVE_ABS && !abs */ /* * Do we have the Cura software? */ #undef CURAENGINE #endif /* !_CUPS_CONFIG_H_ */ ippsample/install-sh0000755000175000017500000001270413240604116013547 0ustar tilltill#!/bin/sh # # Install a program, script, or datafile. # # Copyright 2008-2012 by Apple Inc. # # This script is not compatible with BSD (or any other) install program, as it # allows owner and group changes to fail with a warning and makes sure that the # destination directory permissions are as specified - BSD install and the # original X11 install script did not change permissions of existing # directories. It also does not support the transform options since CUPS does # not use them... # # Original script from X11R5 (mit/util/scripts/install.sh) # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # Force umask to 022... umask 022 # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" gzipprog="${GZIPPROG-gzip}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" gzipcp() { # gzipcp from to $gzipprog -9 <"$1" >"$2" } while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue ;; -d) dir_arg=true shift continue ;; -m) chmodcmd="$chmodprog $2" shift shift continue ;; -o) chowncmd="$chownprog $2" shift shift continue ;; -g) chgrpcmd="$chgrpprog $2" shift shift continue ;; -s) stripcmd="$stripprog" shift continue ;; -z) instcmd="gzipcp" shift continue ;; *) if [ x"$src" = x ]; then src="$1" else dst="$1" fi shift continue ;; esac done if [ x"$src" = x ]; then echo "install-sh: No input file specified" exit 1 fi if [ x"$dir_arg" != x ]; then dst="$src" src="" if [ -d "$dst" ]; then instcmd=: else instcmd=$mkdirprog fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ ! -f "$src" -a ! -d "$src" ]; then echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ]; then echo "install: No destination specified" exit 1 fi # If destination is a directory, append the input filename. if [ -d "$dst" ]; then dst="$dst/`basename $src`" fi fi ## this sed command emulates the dirname command dstdir="`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`" # Make sure that the destination directory exists. # This part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ]; then $doit $mkdirprog "${pathcomp}"; fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ]; then # Make a directory... $doit $instcmd $dst || exit 1 # Allow chown/chgrp to fail, but log a warning if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst || echo "warning: Unable to change owner of $dst!"; fi if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst || echo "warning: Unable to change group of $dst!"; fi if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst || exit 1; fi else # Install a file... dstfile="`basename $dst`" # Check the destination file - for libraries just use the "-x" option # to strip... case "$dstfile" in *.a | *.dylib | *.sl | *.sl.* | *.so | *.so.*) stripopt="-x" ;; *) stripopt="" ;; esac # Make a temp file name in the proper directory. dsttmp="$dstdir/#inst.$$#" # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp || exit 1 # Update permissions and strip as needed, then move to the final name. # If the chmod, strip, rm, or mv commands fail, remove the installed # file... if [ x"$stripcmd" != x ]; then $doit $stripcmd $stripopt "$dsttmp" || echo "warning: Unable to strip $dst!"; fi if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp" || echo "warning: Unable to change owner of $dst!"; fi if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp" || echo "warning: Unable to change group of $dst!"; fi trap "rm -f ${dsttmp}" 0 && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; fi && $doit $rmcmd -f "$dstdir/$dstfile" && $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" fi exit 0