home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / install / printercfg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-09-02  |  46.3 KB  |  1,842 lines

  1. /* Text based printer configuration for the RHS install program */
  2. /* Michael Fulbright - 1997                                     */
  3. /*                                                              */
  4. /* Heavily hacked by ewt for post-Red Hat 5.0 releases        */
  5.  
  6. #include <alloca.h>
  7. #include <ctype.h>
  8. #include <errno.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <unistd.h>
  13. #include <ctype.h>
  14. #include <fcntl.h>
  15. #include <grp.h>
  16. #include <sys/types.h>
  17. #include <sys/wait.h>
  18. #include <sys/stat.h>
  19.  
  20. #include <newt.h>
  21.  
  22. #include "devices.h"
  23. #include "install.h"
  24. #include "intl.h"
  25. #include "log.h"
  26. #include "printercfg.h"
  27.  
  28. /* db of all entries in the printerdb file */
  29. /* we reallocate as we read entries, so we keep numread and numallocated */
  30. DBEntry **thedb;
  31. int numdb, numdb_alloc;
  32.  
  33. /* root_path is the base of any path we use. During install the actual */
  34. /* system is mounted under something like /mnt, so we have to take this */
  35. /* into account when creating system files for the final, installed sys */
  36. char *root_path;
  37.  
  38. /* keep up with whether we actually accomplished anything or not */
  39. int install_return_code;
  40.  
  41. #define NUM_PAPERSIZES 5
  42. static char *PaperSizes[NUM_PAPERSIZES] = {
  43.   "letter", "legal", "ledger", "a3", "a4" };
  44.  
  45. /* not sure what we're calling these yet */
  46. #define NEXT_LABEL "Next"
  47. #define PREV_LABEL "Previous"
  48.  
  49. /*******************************************/
  50. /* Some useful utility routines come first */
  51. /*******************************************/
  52.  
  53. /* convert the character sequence '\' \n' into a true '\n' */
  54. /* handy for treating a string which contains the continuation char '\' */
  55. static void insert_newlines( char *s ) {
  56.     char *p, *q;
  57.     char *tmp;
  58.     
  59.     if (strlen(s)<2)
  60.     return;
  61.     
  62.     tmp = strdup( s );
  63.     for (p=tmp, q=s; *(p+1); p++, q++)
  64.     if (*p == '\\' && *(p+1)=='n') {
  65.         *q = '\n';
  66.         p++;
  67.     } else
  68.         *q = *p;
  69.     
  70.     *q = '\000';
  71.     free(tmp);
  72. }
  73.     
  74.  
  75. /* clean up that string */
  76. static void trim_whitespace( char *s ) {
  77.     char *f, *l, *p, *q;
  78.  
  79.     if (!(*s))
  80.     return;
  81.     
  82.     for (f=s; *f && isspace(*f); f++) ;
  83.  
  84.     if (!*f) {
  85.     *s = '\0';
  86.     return;
  87.     }
  88.     
  89.     for (l=f+strlen(f)-1; isspace(*l) ; l--)
  90.     *l = '\0';
  91.     
  92.     q = s, p = f;
  93.     while (*p)
  94.     *q++ = *p++;
  95.     
  96.     *q = '\0';
  97. }
  98.  
  99.  
  100. /* set all values of a PCEntry to sane values */
  101. void initialize_PCEntry( PCEntry *pcentry ) {
  102.     memset(pcentry, 0, sizeof(*pcentry));
  103. }
  104.  
  105. /* allocate a new PrintCap Entry */
  106. static PCEntry *new_PCEntry() {
  107.     PCEntry *pcentry;
  108.     
  109.     pcentry = malloc(sizeof(PCEntry));
  110.     initialize_PCEntry( pcentry );
  111.  
  112.     return pcentry;
  113. }
  114.  
  115. static char * safestrdup(char * item) {
  116.     return item ? strdup(item) : NULL;
  117. }
  118.  
  119. /* duplicate an existing PrintCap Entry */
  120. /* all strings are REALLOCATED, so new PCEntry is not dependent on original */
  121. static PCEntry *dup_PCEntry( PCEntry *orig ) {
  122.     PCEntry *pcentry;
  123.     
  124.     pcentry = new_PCEntry();
  125.     
  126.     pcentry->Queue = safestrdup(orig->Queue);
  127.     pcentry->SpoolDir = safestrdup(orig->SpoolDir);
  128.     pcentry->Device = safestrdup(orig->Device);
  129.     pcentry->IF = safestrdup(orig->IF);
  130.     pcentry->AF = safestrdup(orig->AF);
  131.     pcentry->Type = orig->Type;
  132.     pcentry->db = orig->db;
  133.     pcentry->Resolution = safestrdup(orig->Resolution);
  134.     pcentry->PaperSize = safestrdup(orig->PaperSize);
  135.     pcentry->BitsPerPixel = safestrdup(orig->BitsPerPixel);
  136.     pcentry->CRLF = orig->CRLF;
  137.     pcentry->RemoteHost = safestrdup(orig->RemoteHost);
  138.     pcentry->RemoteQueue = safestrdup(orig->RemoteQueue);
  139.     pcentry->SMBHost = safestrdup(orig->SMBHost);
  140.     pcentry->SMBHostIP = safestrdup(orig->SMBHostIP);
  141.     pcentry->SMBShare = safestrdup(orig->SMBShare);
  142.     pcentry->SMBUser = safestrdup(orig->SMBUser);
  143.     pcentry->SMBPasswd = safestrdup(orig->SMBPasswd);
  144.     
  145.     return pcentry;
  146. }
  147.  
  148.  
  149.  
  150. /* Free an existing PrintCap Entry */
  151. static void free_PCEntry( PCEntry *pcentry) {
  152.     free(pcentry->Queue);
  153.     free(pcentry->SpoolDir);
  154.     free(pcentry->Device);
  155.     free(pcentry->IF);
  156.     free(pcentry->AF);
  157.     free(pcentry->Resolution);
  158.     free(pcentry->PaperSize);
  159.     free(pcentry->BitsPerPixel);
  160.     free(pcentry->RemoteHost);
  161.     free(pcentry->RemoteQueue);
  162.     free(pcentry->SMBHost);
  163.     free(pcentry->SMBHostIP);
  164.     free(pcentry->SMBShare);
  165.     free(pcentry->SMBUser);
  166.     free(pcentry->SMBPasswd);
  167.     free(pcentry);
  168. }
  169.  
  170.  
  171. /* Read lines from file, ignoring lines starting with a '#' and */
  172. /* observing continuation lines (lines which end with a '\')    */
  173. /* All leading and trailing spaces are removed, as well as \n   */
  174. /* Returns zero if no more input available                      */
  175. static char *pc_getline(FILE *file) {
  176.     int done;
  177.     char buf[256];
  178.     char *fresult;
  179.     char *line;
  180.     int len;
  181.     
  182.     line = NULL;
  183.     done=0;
  184.     while (!done) {
  185.     fresult=fgets( buf, 256, file );
  186.     if (!fresult)
  187.         return NULL;
  188.     
  189.     trim_whitespace( buf );
  190.     
  191.     if (! (*buf) )
  192.         continue;
  193.     
  194.     if (*buf == '#')
  195.         continue;
  196.     
  197.     len = strlen( buf );
  198.     if ( *(buf+len-1) != '\\' )
  199.         done = 1;
  200.     else {
  201.         /* silly rule - make sure line ends with a space */
  202.         if ( len > 2 && *(buf+len-2) != ' ' ) {
  203.         *(buf+len-1) = ' ';
  204.         *(buf+len) = '\000';
  205.         } else
  206.         *(buf+len-1) = '\000';
  207.     }
  208.  
  209.     if (!line)
  210.         line = strdup(buf);
  211.     else {
  212.         line = (char *) realloc( line, strlen(line) + strlen (buf) + 1 );
  213.         strcpy( line+strlen(line), buf );
  214.     }
  215.     }
  216.     
  217.     return line;
  218. }
  219.  
  220. /* strips out the value of a Parameter in the printer db file */
  221. static char *getfield( char *s ) {
  222.     char *f, *p;
  223.     
  224.     f = strchr(s, ':');
  225.     if (!f)
  226.     return NULL;
  227.     
  228.     p = strdup(f+1);
  229.     trim_whitespace(p);
  230.     
  231.     if (! (*p))
  232.     return NULL;
  233.     else
  234.     return p;
  235. }
  236.  
  237. /* looks for exactly flds fields, with each field enclosed in a {} pair. */
  238. static int parsefields( char *s, char **flds) {
  239.     char *f, *l;
  240.     char *p;
  241.     int n;
  242.     int i;
  243.     
  244.     flds[0] = NULL;
  245.     flds[1] = NULL;
  246.     flds[2] = NULL;
  247.     n = 0;
  248.     
  249.     p = s;
  250.     for (i=0; i<3; i++) {
  251.     f = strchr(p, '{');
  252.     if (!f)
  253.         return n;
  254.     
  255.     l = strchr(f, '}');
  256.     if (!l)
  257.         return n;
  258.     
  259.     flds[n] = (char *) malloc( l-f+2 );
  260.     strncpy( flds[n], f+1, l-f-1 );
  261.     *((flds[n])+(l-f)-1) = '\000';
  262.     
  263.     p = l+1;
  264.     n++;
  265.     }
  266.     return n;
  267. }
  268.  
  269. static int dbCompare(const void * a, const void * b) {
  270.     const DBEntry * const *first = a;
  271.     const DBEntry * const *second = b;
  272.  
  273.     return strcmp((*first)->Descr, (*second)->Descr);
  274. }
  275.  
  276. /* Read the printer database dbpath into memory */
  277. /* returns non-zero on error */
  278. static int read_printer_db( char *dbpath ) {
  279.     FILE *dbfile;
  280.     char *line;
  281.     char *tmpstr;
  282.     char *fields[3];
  283.     int nfield;
  284.     DBEntry *entry;
  285.     int nbpp, nres;
  286.     int nbpp_alloc, nres_alloc;
  287.     
  288.     tmpstr=malloc(strlen(dbpath)+strlen(root_path)+2);
  289.     strcpy(tmpstr,root_path);
  290.     strcat(tmpstr,dbpath);
  291.     if ((dbfile=fopen(tmpstr, "r")) == NULL) {
  292.     free(tmpstr);
  293.     return -1;
  294.     }
  295.     free(tmpstr);
  296.  
  297.     /* loop till we find the start of an entry */
  298.     /* we obviously want to ignore any comments on the way */
  299.     numdb = numdb_alloc = 0;
  300.     while ((line=pc_getline(dbfile))) {
  301.     if (!strncmp(line, "StartEntry:", 11)) {
  302.         entry = (DBEntry *) malloc( sizeof(DBEntry) );
  303.         entry->Entry = getfield(line);
  304.         entry->GSDriver = NULL;
  305.         entry->Descr = NULL;
  306.         entry->About = NULL;
  307.         entry->Resolution = NULL;
  308.         entry->ResDescr = NULL;
  309.         entry->BitsPerPixel = NULL;
  310.         entry->BppDescr = NULL;
  311.         
  312.         nres = nres_alloc = 0;
  313.         nbpp = nbpp_alloc = 0;
  314.         
  315.         free(line);
  316.         if (!entry->Entry) {
  317.         free(entry);
  318.         continue;
  319.         }
  320.  
  321.         numdb++;
  322.         if (numdb >= numdb_alloc ) {
  323.         numdb_alloc += 25;
  324.         thedb=(DBEntry **)realloc(thedb,
  325.                       sizeof(DBEntry *)*(numdb_alloc));
  326.         }
  327.  
  328.         thedb[numdb - 1] = entry;
  329.         
  330.         while ((line=pc_getline(dbfile))) {
  331.         if (!strncmp(line, "EndEntry", 8))
  332.             break;
  333.         
  334.         if (!strncmp(line, "GSDriver:", 9)) {
  335.             if (entry->GSDriver)
  336.             break;
  337.             
  338.             entry->GSDriver=getfield(line);
  339.         }
  340.  
  341.           if (!strncmp(line, "Description:", 12)) {
  342.           if (entry->Descr)
  343.               break;
  344.  
  345.           tmpstr=getfield(line);
  346.           nfield = parsefields(tmpstr, fields);
  347.           free(tmpstr);
  348.           
  349.           if (nfield == 1 )
  350.               entry->Descr=fields[0];
  351.           else
  352.               break;
  353.           }
  354.           
  355.           if (!strncmp(line, "About:", 6)) {
  356.           if (entry->About)
  357.               break;
  358.           
  359.           tmpstr=getfield(line);
  360.           nfield = parsefields(tmpstr, fields);
  361.           free(tmpstr);
  362.           if (nfield == 1) {
  363.               trim_whitespace(fields[0]);
  364.               insert_newlines(fields[0]);
  365.               entry->About=fields[0];
  366.           } else
  367.               break;
  368.           }
  369.  
  370.           if (!strncmp(line, "Resolution:", 11)) {
  371.           tmpstr=getfield(line);
  372.           nfield = parsefields(tmpstr, fields);
  373.           free(tmpstr);
  374.           if (nfield == 3) {
  375.               nres++;
  376.               
  377.               if (nres >= nres_alloc) {
  378.               nres_alloc += 10;
  379.               entry->Resolution=
  380.                 (char **)realloc(entry->Resolution,
  381.                          nres_alloc*sizeof(char*));
  382.               entry->ResDescr=
  383.                 (char **)realloc(entry->ResDescr,
  384.                          nres_alloc*sizeof(char*));
  385.               }
  386.  
  387.               entry->Resolution[nres-1]=
  388.             (char *)malloc(strlen(fields[0])+strlen(fields[1])+10);
  389.               sprintf(entry->Resolution[nres-1],
  390.                   "%sx%s", fields[0],fields[1]);
  391.  
  392.               if (fields[2])
  393.               entry->ResDescr[nres-1]=strdup(fields[2]);
  394.               else
  395.               entry->ResDescr[nres-1]=NULL;
  396.           } else
  397.               break;
  398.           }
  399.  
  400.           if (!strncmp(line, "BitsPerPixel:", 13)) {
  401.           tmpstr=getfield(line);
  402.           nfield = parsefields(tmpstr, fields);
  403.           free(tmpstr);
  404.           if (nfield == 2) {
  405.               nbpp++;
  406.               
  407.               if (nbpp >= nbpp_alloc) {
  408.               nbpp_alloc += 10;
  409.               entry->BitsPerPixel=
  410.                 (char **)realloc(entry->BitsPerPixel,
  411.                          nbpp_alloc*sizeof(char*));
  412.               entry->BppDescr=
  413.                 (char **)realloc(entry->BppDescr,
  414.                          nbpp_alloc*sizeof(char*));
  415.               }
  416.               
  417.               entry->BitsPerPixel[nbpp-1]=strdup(fields[0]);
  418.               
  419.               if (fields[1])
  420.               entry->BppDescr[nbpp-1]=strdup(fields[1]);
  421.               else
  422.               entry->BppDescr[nbpp-1]=NULL;
  423.           } else
  424.               break;
  425.           }
  426.           free(line);
  427.         }
  428.  
  429.         entry->NumRes = nres;
  430.         entry->NumBpp = nbpp;
  431.     } else    {
  432.         free(line);
  433.     }
  434.     }
  435.  
  436.     fclose(dbfile);
  437.  
  438.     qsort(thedb, numdb, sizeof(*thedb), dbCompare);
  439.  
  440.     return 0;
  441. }
  442.  
  443. #if 0
  444. /* used by below routines - assumes everything is malloc'd          */
  445. /* updates old to new if new is non-NULL                            */
  446. /* frees the old value and points it at the new                     */
  447. /* if new is NULL, means it wasnt updated and old remains unchanged */
  448. static void update_changed( void *new, void **old ) {
  449.     if (new) {
  450.     if (*old) 
  451.         free(*old);
  452.     *old = new;
  453.     }
  454. }
  455. #endif
  456.  
  457. /* display summary line given by char * arg */
  458. void show_printer_about( char *about ) {
  459.     newtWinMessage(_("Printer Information"), _("Ok"), about);
  460. }
  461.  
  462. /* select the printer type you have */
  463. /* return < 0 if user aborted */
  464. /* returns index into thedb[] of the selected entry otherwise*/
  465. static int select_printer_type( PCEntry *changes) {
  466.     newtComponent okay, cancel, form, listbox, answer;
  467.     struct newtExitStruct event;
  468.     long i, sel;
  469.     int formdone;
  470.     char *origtype;
  471.     newtGrid grid, buttons;
  472.  
  473.     if (changes->db && changes->db->Descr) {
  474.     origtype = alloca(strlen(changes->db->Descr)+2);
  475.     strcpy(origtype, changes->db->Descr);
  476.     } else
  477.     origtype = NULL;
  478.     
  479.     newtPushHelpLine(_("<F1> will give you information on a particular "
  480.              "printer type"));
  481.  
  482.     grid = newtCreateGrid(1, 3);
  483.     newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT,
  484.              newtLabel(-1, -1, _("What type of printer do you have?")),
  485.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  486.  
  487.     listbox = newtListbox(-1, -1, 10, NEWT_FLAG_RETURNEXIT | NEWT_FLAG_SCROLL);
  488.     for (i = 0; i < numdb; i++) {
  489.     newtListboxAddEntry(listbox, thedb[i]->Descr, (void *)i);
  490.     
  491.     if (changes->db && changes->db->Entry &&
  492.         !strcmp(changes->db->Entry,thedb[i]->Entry)) {
  493.         newtListboxSetCurrent(listbox, i);
  494.     }
  495.     }
  496.     newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, listbox,
  497.              2, 1, 2, 0, 0, 0);
  498.  
  499.     /* if no selection yet, default to PostScript if it exists */
  500.     if (changes->db==NULL || changes->db->Entry==NULL  ) {
  501.     /* set this just in case we find nothing that matches */
  502.     newtListboxSetCurrent(listbox, 0);
  503.     for (i = 0; i < numdb; i++)
  504.         if (!strcmp(thedb[i]->Descr, "PostScript printer")) {
  505.         newtListboxSetCurrent(listbox, i);
  506.         break;
  507.         }
  508.     }
  509.     
  510.     buttons = newtButtonBar(_("Ok"), &okay, _("Back"), &cancel, NULL);
  511.     newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
  512.              0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
  513.  
  514.     form = newtForm(NULL, NULL, 0);
  515.     newtFormAddHotKey(form, NEWT_KEY_F1); 
  516.     newtGridAddComponentsToForm(grid, form, 1);
  517.     newtGridWrappedWindow(grid, _("Configure Printer"));
  518.     newtGridFree(grid, 1);
  519.     
  520.     formdone = 0;
  521.     answer = NULL;
  522.     while (!formdone) {
  523.     newtFormRun(form, &event);
  524.     
  525.     if (event.reason == NEWT_EXIT_HOTKEY) {
  526.         if (event.u.key == NEWT_KEY_F12)
  527.         formdone = 1;
  528.         else if (event.u.key == NEWT_KEY_F1) {
  529.         show_printer_about(
  530.             thedb[(long)newtListboxGetCurrent(listbox)]->About);
  531.         }
  532.     } else if (event.reason == NEWT_EXIT_COMPONENT) {
  533.         formdone = 1;
  534.         if (event.u.co == cancel)
  535.         answer = cancel;
  536.     }
  537.     }
  538.     
  539.     sel = (long) newtListboxGetCurrent(listbox);
  540.     
  541.     newtPopWindow();
  542.     newtPopHelpLine();
  543.     newtFormDestroy(form);
  544.     
  545.     if ( answer == cancel )
  546.     return -1;
  547.  
  548.     /* store new values */
  549.     changes->db = thedb[sel];
  550.  
  551.     /* MAJOR HACK */
  552.     /* if the printer is an HP, let's do stairstep correction */
  553.     if (!strncmp(changes->db->Descr,"HP",2)) {
  554.     changes->CRLF = 1;
  555.     } else {
  556.     if (origtype) {
  557.         if (strcmp(origtype, changes->db->Descr)) {
  558.         changes->CRLF = 0;
  559.         }
  560.     } else  {
  561.         changes->CRLF = 0;
  562.     }
  563.     }
  564.  
  565.     return sel;
  566. }    
  567.     
  568.  
  569. /* select the paper size and printer resolution you want */
  570. /* return < 0 if user aborted */
  571. /* returns 0 otherwise */
  572. static int select_paper_size_and_res( PCEntry *changes ) {
  573.     newtComponent okay, cancel, form, text, papersz, res, answer, crlf;
  574.     struct newtExitStruct event;
  575.     long i;
  576.     int formdone;
  577.     char * xpos;
  578.     newtGrid grid, subgrid, buttons, leftgrid, rightgrid;
  579.     char crlfret;
  580.     char buf[200];
  581.     
  582.     /* there has to be a current selection for this to work! */
  583.     if (changes->db == NULL)
  584.     return -1;
  585.     
  586.     newtPushHelpLine(_("<F1> will give you information on this "
  587.              "printer driver."));
  588.  
  589.     text = newtTextboxReflowed(-1, -1,
  590.                _("You may now configure the paper size and resolution "
  591.                  "for this printer."), 52, 5, 5, 0);
  592.  
  593.     subgrid = newtCreateGrid(2, 1);
  594.     leftgrid = newtCreateGrid(1, 2);
  595.     rightgrid = newtCreateGrid(1, 2);
  596.  
  597.     /* Paper size listbox */
  598.     newtGridSetField(leftgrid, 0, 0, NEWT_GRID_COMPONENT,
  599.              newtLabel(-1, -1, _("Paper Size")),
  600.              0, 0, 0, 0, 0, 0);
  601.  
  602.     papersz = newtListbox( 8, 5, 5, 0);
  603.     for (i=0; i < NUM_PAPERSIZES; i++) {
  604.     newtListboxAddEntry( papersz, PaperSizes[i], (void *)i );
  605.     if (changes->PaperSize &&
  606.         !strcmp(changes->PaperSize, PaperSizes[i]))
  607.         newtListboxSetCurrent(papersz, i);
  608.     }
  609.  
  610.     newtGridSetField(leftgrid, 0, 1, NEWT_GRID_COMPONENT, papersz,
  611.              0, 0, 0, 0, 0, 0);
  612.     newtGridSetField(subgrid, 0, 0, NEWT_GRID_SUBGRID, leftgrid,
  613.              0, 0, 0, 0, 0, 0);
  614.  
  615.     /* make sure something is picked */
  616.     if (changes->PaperSize==NULL)
  617.     newtListboxSetCurrent(papersz, 0);
  618.  
  619.     /* Resolution */
  620.     newtGridSetField(rightgrid, 0, 0, NEWT_GRID_COMPONENT,
  621.              newtLabel(-1, -1, _("Resolution")),
  622.              0, 0, 0, 0, 0, 0);
  623.     res = newtListbox(-1, -1, 5, 
  624.               changes->db->NumRes < 5 ? 0 : NEWT_FLAG_SCROLL);
  625.  
  626.     if ( changes->db->NumRes > 0) {
  627.     for (i=0; i < changes->db->NumRes; i++) {
  628.         xpos = strchr(changes->db->Resolution[i],'x');
  629.         *xpos = '\0';
  630.         sprintf(buf, "%4sx%4s %s", changes->db->Resolution[i],
  631.             xpos + 1, changes->db->ResDescr[i] ? 
  632.                     changes->db->ResDescr[i] : "");
  633.         *xpos = 'x';
  634.  
  635.         newtListboxAddEntry(res, buf, (void *) i);
  636.         if (changes->Resolution &&
  637.         !strcmp(changes->Resolution, changes->db->Resolution[i]))
  638.         newtListboxSetCurrent(res, i);
  639.     }
  640.     } else {
  641.     newtListboxAddEntry( res, _("Default"), (void *)0 );
  642.     newtListboxSetCurrent(res, 0);
  643.     }
  644.     
  645.     /* make sure something is picked */
  646.     if (changes->Resolution==NULL)
  647.     newtListboxSetCurrent(res, 0);
  648.  
  649.     newtGridSetField(rightgrid, 0, 1, NEWT_GRID_COMPONENT, res,
  650.              0, 0, 0, 0, 0, 0);
  651.     newtGridSetField(subgrid, 1, 0, NEWT_GRID_SUBGRID, rightgrid,
  652.              0, 0, 0, 0, 0, 0);
  653.  
  654.     crlf = newtCheckbox(-1, -1, _("Fix stair-stepping of text?"), 
  655.             changes->CRLF ? '*' : ' ', NULL,&crlfret);
  656.     
  657.     buttons = newtButtonBar(_("Ok"), &okay, _("Back"), &cancel, NULL);
  658.  
  659.     grid = newtCreateGrid(1, 4);
  660.     newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
  661.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  662.     newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, subgrid,
  663.              4, 1, 4, 0, 0, NEWT_GRID_FLAG_GROWX);
  664.     newtGridSetField(grid, 0, 2, NEWT_GRID_COMPONENT, crlf,
  665.              0, 1, 0, 0, 0, 0);
  666.     newtGridSetField(grid, 0, 3, NEWT_GRID_SUBGRID, buttons,
  667.              0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
  668.  
  669.     form = newtForm(NULL, NULL, 0);
  670.     newtGridWrappedWindow(grid, changes->db->Descr); 
  671.     newtGridAddComponentsToForm(grid, form, 1);
  672.     newtGridFree(grid, 1);
  673.     newtFormAddHotKey(form, NEWT_KEY_F1); 
  674.     
  675.     formdone = 0;
  676.     answer = NULL;
  677.     
  678.     while (!formdone) {
  679.     newtFormRun(form, &event);
  680.     
  681.     if (event.reason == NEWT_EXIT_HOTKEY) {
  682.         if (event.u.key == NEWT_KEY_F12)
  683.         formdone = 1;
  684.         else if (event.u.key == NEWT_KEY_F1) {
  685.         show_printer_about( changes->db->About );
  686.         }
  687.     } else if (event.reason == NEWT_EXIT_COMPONENT) {
  688.         formdone = 1;
  689.         if (event.u.co == cancel)
  690.         answer = cancel;
  691.     }
  692.     }
  693.  
  694.  
  695.     if ( answer == cancel ) {
  696.     newtPopHelpLine();
  697.     newtPopWindow();
  698.     newtFormDestroy(form);
  699.     return -1;
  700.     }
  701.  
  702.     i = (long) newtListboxGetCurrent(papersz);
  703.  
  704.     free(changes->PaperSize);
  705.     changes->PaperSize=strdup(PaperSizes[i]);
  706.  
  707.     free(changes->Resolution);
  708.     if (changes->db->NumRes > 0) {
  709.     i = (long) newtListboxGetCurrent(res);
  710.     changes->Resolution=strdup(changes->db->Resolution[i]);
  711.     } else
  712.     changes->Resolution=strdup(_("Default"));
  713.  
  714.     if (crlfret == ' ')
  715.     changes->CRLF = 0;
  716.     else
  717.     changes->CRLF = 1;
  718.     
  719.     newtPopHelpLine();
  720.     newtPopWindow();
  721.     newtFormDestroy(form);
  722.  
  723.     return 0;
  724. }
  725.  
  726. /* pick the color depth, returns < 0 on cancel, 0 otherwise */
  727. static int select_color_depth( PCEntry *changes, int direction ) {
  728.     newtComponent okay, cancel, form, bpp, answer, text;
  729.     struct newtExitStruct event;
  730.     int i, width, height;
  731.     int formdone, maxlen;
  732.     newtGrid grid, buttons;
  733.     char buf[200];
  734.     char * reflowedText;
  735.  
  736.     /* have to have a selection to work */
  737.     if (changes->db == NULL)
  738.     return -1;
  739.  
  740.     /* if only one color depth choice, do nothing */
  741.     if ( changes->db->NumBpp == 0) {
  742.     changes->BitsPerPixel=_(strdup("Default"));
  743.     return direction > 0 ? 0 : -1;
  744.     }
  745.  
  746.     /* we know that changes->db->NumBpp > 0 */
  747.     
  748.     newtPushHelpLine(_("<F1> will give you information on this "
  749.                "printer driver."));
  750.  
  751.     bpp = newtListbox(-1, -1, changes->db->NumBpp, NEWT_FLAG_RETURNEXIT);
  752.     maxlen = 0;
  753.     for (i=0; i < changes->db->NumBpp; i++) {
  754.     sprintf(buf, "%2s  %s", changes->db->BitsPerPixel[i],
  755.         changes->db->BppDescr[i] ? changes->db->BppDescr[i] : "");
  756.     
  757.     /* limit the length of the line */
  758.     if (strlen(buf) > 70)
  759.         buf[70] = '\000';
  760.  
  761.     newtListboxAddEntry(bpp, buf, (void *)i );
  762.     if (changes->BitsPerPixel &&
  763.         !strcmp(changes->BitsPerPixel, changes->db->BitsPerPixel[i]))
  764.         newtListboxSetCurrent(bpp, i);
  765.  
  766.     if (strlen(buf) > maxlen) maxlen = strlen(buf);
  767.     }
  768.     
  769.     /* make sure something is set */
  770.     if (changes->BitsPerPixel==NULL)
  771.     newtListboxSetCurrent(bpp,0);
  772.  
  773.     reflowedText = newtReflowText(_("You may now configure the color "
  774.             "options for this printer."), maxlen + 5, 5, 3,
  775.             &width, &height);
  776.     text = newtTextbox(1, 1, width, height, NEWT_TEXTBOX_WRAP);
  777.     newtTextboxSetText(text, reflowedText);
  778.     free(reflowedText);
  779.  
  780.     buttons = newtButtonBar(_("Ok"), &okay, _("Back"), &cancel, NULL);
  781.     form = newtForm(NULL, NULL, 0);
  782.     newtFormAddHotKey(form, NEWT_KEY_F1); 
  783.  
  784.     grid = newtGridSimpleWindow(text, bpp, buttons);
  785.     newtGridWrappedWindow(grid, _("Configure Color Depth"));
  786.     newtGridAddComponentsToForm(grid, form, 1);
  787.     newtGridFree(grid, 1);
  788.     
  789.     formdone = 0;
  790.     answer = NULL;
  791.     while (!formdone) {
  792.     newtFormRun(form, &event);
  793.     
  794.     if (event.reason == NEWT_EXIT_HOTKEY) {
  795.         if (event.u.key == NEWT_KEY_F12)
  796.         formdone = 1;
  797.         else if (event.u.key == NEWT_KEY_F1) {
  798.         show_printer_about( changes->db->About );
  799.         }
  800.     } else if (event.reason == NEWT_EXIT_COMPONENT) {
  801.         formdone = 1;
  802.         if (event.u.co == cancel)
  803.         answer = cancel;
  804.     }
  805.     }
  806.  
  807.     if ( answer != cancel ) {
  808.     free(changes->BitsPerPixel);
  809.     i = (long) newtListboxGetCurrent(bpp);
  810.     changes->BitsPerPixel=strdup(changes->db->BitsPerPixel[i]);
  811.     }
  812.  
  813.     newtPopHelpLine();
  814.     newtPopWindow();
  815.     newtFormDestroy(form);
  816.     
  817.     return (answer == cancel) ? -1 : 0;
  818. }
  819.  
  820. /* returns the full attribute of the selected printer filter */
  821. /* returns < 0 if user cancelled selected                    */
  822. static int select_filter( PCEntry *changes, int direction ) {
  823.     
  824.     int done;
  825.     int stage;
  826.     int abort;
  827.     
  828.     done = 0;
  829.     stage = direction > 0 ? 1 : 3;
  830.     abort = 0;
  831.     while (!done) {
  832.  
  833.     switch (stage) {
  834.  
  835.         /* select printer model/driver */
  836.       case 1:
  837.         if (select_printer_type(changes) < 0) {
  838.         done = 1;
  839.         abort = 1;
  840.         break;
  841.         } else {
  842.         stage++;
  843.         direction = 1;
  844.         }
  845.         break;
  846.  
  847.         /* select paper size and resolution */
  848.       case 2:
  849.         if (select_paper_size_and_res( changes ) < 0) {
  850.         direction = -1;
  851.         } else
  852.         direction = 1;
  853.         stage += direction;
  854.         break;
  855.  
  856.         /* select color depth */
  857.       case 3:
  858.         if (select_color_depth( changes, direction ) < 0) 
  859.         direction = -1;
  860.         else
  861.         direction = 1;
  862.         stage += direction;
  863.         break;
  864.  
  865.         /* we made it and we're done */
  866.       case 4:
  867.         done = 1;
  868.  
  869.     }
  870.     }
  871.  
  872.     if (abort)
  873.     return -1;
  874.  
  875.     return 0;
  876. }
  877.  
  878.  
  879. /* return < 0 for user cancel */
  880. static int get_local_info( PCEntry *changes ) {
  881.     newtComponent answer, cancel, form, okay, device, text, detectedW;
  882.     char buf[2000];
  883.     char *device_result;
  884.     char *devname;
  885.     char * reflowedText;
  886.     int width, height;
  887.     int detected[3];
  888.     int i, result;
  889.     int npos;
  890.     newtGrid grid, subgrid, buttons;
  891.  
  892. #if defined(__i386__) && !defined(TESTING)
  893.     if (loadModule("lp", DRIVER_OTHER, DRIVER_MINOR_NONE, NULL)) 
  894.     return INST_ERROR;
  895.  
  896. #endif
  897.  
  898. #if 0
  899.     /* old way Erik did this */
  900.     devMakeInode("lp0", "/tmp/lp0");
  901.     devMakeInode("lp1", "/tmp/lp1");
  902.     devMakeInode("lp2", "/tmp/lp2");
  903.     
  904.     /* do auto-detect of lp ports */
  905.     detected[0] = ((result=open("/tmp/lp0", O_WRONLY|O_NONBLOCK)) != -1);
  906.     if (result >= 0) close(result);
  907.     detected[1] = ((result=open("/tmp/lp1", O_WRONLY|O_NONBLOCK)) != -1);
  908.     if (result >= 0) close(result);
  909.     detected[2] = ((result=open("/tmp/lp2", O_WRONLY|O_NONBLOCK)) != -1);
  910.     if (result >= 0) close(result);
  911.  
  912.     unlink("/tmp/lp0");
  913.     unlink("/tmp/lp1");
  914.     unlink("/tmp/lp2");
  915. #else
  916.     /* different approach */
  917.     /* do auto-detect of lp ports */
  918.     devname=alloca(strlen(root_path)+strlen("/dev/lpX")+2);
  919.     strcpy(devname,root_path);
  920.     strcat(devname,"/dev/lpX");
  921.     npos=strlen(devname)-1;
  922.     devname[npos]='0';
  923.     detected[0] = ((result=open(devname, O_WRONLY|O_NONBLOCK)) != -1);
  924.     if (result >= 0) close(result);
  925.     devname[npos]='1';
  926.     detected[1] = ((result=open(devname, O_WRONLY|O_NONBLOCK)) != -1);
  927.     if (result >= 0) close(result);
  928.     devname[npos]='2';
  929.     detected[2] = ((result=open(devname, O_WRONLY|O_NONBLOCK)) != -1);
  930.     if (result >= 0) close(result);
  931. #endif
  932.     
  933. #if defined(__i386__) && !defined(TESTING)
  934.     removeModule("lp");
  935. #endif
  936.  
  937.     reflowedText = newtReflowText(_("What device is your printer connected to "
  938.                 "(note that /dev/lp0 is equivalent to LPT1:)?"), 
  939.                 40, 5, 5, &width, &height);
  940.     text = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP);
  941.     newtTextboxSetText(text, reflowedText);
  942.     free(reflowedText);
  943.  
  944.     strcpy(buf, _("Auto-detected ports:\n\n"));
  945.  
  946.     for (i=0; i<3; i++) {
  947.     strcat(buf, "  /dev/lp");
  948.     buf[strlen(buf) + 1] = '\0';
  949.     buf[strlen(buf)] = i + '0';
  950.     strcat(buf, ": ");
  951.     if (!detected[i])
  952.         strcat(buf, _("Not "));
  953.  
  954.     strcat(buf, _("Detected\n"));
  955.     }
  956.  
  957.     reflowedText = newtReflowText(buf, 40, 5, 5, &width, &height);
  958.     detectedW = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP);
  959.     newtTextboxSetText(detectedW, reflowedText);
  960.     free(reflowedText);
  961.  
  962.     subgrid = newtCreateGrid(2, 1);
  963.     newtGridSetField(subgrid, 0, 0, NEWT_GRID_COMPONENT,
  964.              newtLabel(3, 5, _("Printer Device:")),
  965.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  966.  
  967.     device = newtEntry(19, 5, changes->Device ? changes->Device : "/dev/lp1", 
  968.             15, &device_result, NEWT_FLAG_RETURNEXIT);
  969.     newtGridSetField(subgrid, 1, 0, NEWT_GRID_COMPONENT, device,
  970.              1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  971.     
  972.     buttons = newtButtonBar(_("Ok"), &okay, _("Back"), &cancel, NULL);
  973.  
  974.     grid = newtCreateGrid(1, 4);
  975.     newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
  976.              0, 0, 0, 0, 0, 0);
  977.     newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, subgrid,
  978.              2, 1, 0, 0, 0, 0);
  979.     newtGridSetField(grid, 0, 2, NEWT_GRID_COMPONENT, detectedW,
  980.              2, 1, 0, 0, NEWT_ANCHOR_LEFT, 0);
  981.     newtGridSetField(grid, 0, 3, NEWT_GRID_SUBGRID, buttons,
  982.              0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
  983.  
  984.     form = newtForm(NULL, NULL, 0);
  985.     newtGridAddComponentsToForm(grid, form, 1);
  986.     newtGridWrappedWindow(grid, _("Local Printer Device"));
  987.     newtGridFree(grid, 1);
  988.  
  989.     answer = newtRunForm(form);
  990.  
  991.     if ( answer != cancel ) {
  992.     free(changes->Device);
  993.     changes->Device = strdup(device_result);
  994.     result = 0;
  995.     } else
  996.     result = -1;
  997.  
  998.     newtPopWindow();
  999.     newtFormDestroy(form);
  1000.     return result;
  1001. }
  1002.  
  1003.  
  1004. /* return < 0 for user cancel */
  1005. static int get_remote_info( PCEntry *changes ) {
  1006.     char *queue_result = changes->RemoteQueue;  
  1007.     char *host_result = changes->RemoteHost;
  1008.     int result;
  1009.     struct newtWinEntry entries[3] = {
  1010.     { NULL, &host_result, NEWT_ENTRY_SCROLL },
  1011.     { NULL, &queue_result, NEWT_ENTRY_SCROLL },
  1012.     { NULL, NULL, 0 } };
  1013.     
  1014.     entries[0].text = _("Remote hostname:");
  1015.     entries[1].text = _("Remote queue:");
  1016.     
  1017.     result = newtWinEntries(_("Remote lpd Printer Options"), 
  1018.         _("To use a remote lpd print queue, you need to supply "
  1019.           "the hostname of the printer server and the queue name "
  1020.           "on that server which jobs should be placed in."),
  1021.         50, 5, 5, 20, entries, _("Ok"), _("Back"), NULL);
  1022.  
  1023.     if (result != 2) {
  1024.     free(changes->RemoteHost);
  1025.     changes->RemoteHost = host_result;
  1026.     free(changes->RemoteQueue);
  1027.     changes->RemoteQueue = queue_result;
  1028.     result = 0;
  1029.     } else {
  1030.     result = -1;
  1031.     free(host_result);
  1032.     free(queue_result);
  1033.     }
  1034.  
  1035.     return result;
  1036. }
  1037.  
  1038. /* return < 0 for user cancel */
  1039. static int get_smb_info( PCEntry *changes ) {
  1040.     int result;
  1041.     char *host_result = changes->SMBHost;
  1042.     char *hostip_result = changes->SMBHostIP;
  1043.     char *share_result = changes->SMBShare;
  1044.     char *user_result = changes->SMBUser;
  1045.     char *passwd_result = changes->SMBPasswd;
  1046.     struct newtWinEntry entries[] = {
  1047.     { NULL, &host_result, NEWT_ENTRY_SCROLL },
  1048.     { NULL, &hostip_result, NEWT_ENTRY_SCROLL },
  1049.     { NULL, &share_result, NEWT_ENTRY_SCROLL },
  1050.     { NULL, &user_result, NEWT_ENTRY_SCROLL },
  1051.     { NULL, &passwd_result, NEWT_ENTRY_SCROLL },
  1052.     { NULL, NULL, 0 } };
  1053.  
  1054.     entries[0].text = _("LAN manager host:");
  1055.     entries[1].text = _("LAN manager IP:");
  1056.     entries[2].text = _("Share name:");
  1057.     entries[3].text = _("User name:");
  1058.     entries[4].text = _("Password:");
  1059.  
  1060.     result = newtWinEntries(_("LAN Manager Printer Options"),
  1061.       _("To print to a LAN manager printer, you need to provide the "
  1062.     "LAN manager host name (this is not always the same as the machines "
  1063.     "TCP/IP hostname) and possibly the IP address of the print server, as "
  1064.     "well as the share name for the printer you wish to access and any "
  1065.     "applicable user name and password."),
  1066.         50, 5, 5, 20, entries, _("Ok"), _("Back"), NULL);
  1067.  
  1068.     if ( result != 2 ) {
  1069.     free(changes->SMBHost);
  1070.     changes->SMBHost = host_result;
  1071.     free(changes->SMBHostIP);
  1072.     changes->SMBHostIP = hostip_result;
  1073.     free(changes->SMBShare);
  1074.     changes->SMBShare = share_result;
  1075.     free(changes->SMBUser);
  1076.     changes->SMBUser = user_result;
  1077.     free(changes->SMBPasswd);
  1078.     changes->SMBPasswd = passwd_result;
  1079.     
  1080.     result = 0;
  1081.     } else {
  1082.     result = -1;
  1083.     free(host_result);
  1084.     free(hostip_result);
  1085.     free(share_result);
  1086.     free(user_result);
  1087.     free(passwd_result);
  1088.     }
  1089.  
  1090.     return result;
  1091. }
  1092.  
  1093. /* return < 0 for user cancel */
  1094. static int get_std_info( PCEntry *changes ) {
  1095.     char *queue_result = changes->Queue ? changes->Queue : "lp";
  1096.     char *spool_result = changes->SpoolDir ? 
  1097.                 changes->SpoolDir : "/var/spool/lpd/lp";
  1098.     int result;
  1099.     struct newtWinEntry entries[3] = {
  1100.     { NULL, &queue_result, NEWT_ENTRY_SCROLL },
  1101.     { NULL, &spool_result, NEWT_ENTRY_SCROLL },
  1102.     { NULL, NULL, 0 } };
  1103.  
  1104.     entries[0].text = _("Name of queue:");
  1105.     entries[1].text = _("Spool directory:");
  1106.  
  1107.     result = newtWinEntries(_("Standard Printer Options"),
  1108.     _("Every print queue (which print jobs are directed to) needs a "
  1109.       "name (often lp) and a spool directory associated with it. What "
  1110.       "name and directory should be used for this queue?"),
  1111.         50, 5, 5, 20, entries, _("Ok"), _("Back"), NULL);
  1112.  
  1113.     if (result != 2) {
  1114.     free(changes->Queue);
  1115.     changes->Queue = queue_result;
  1116.     free(changes->SpoolDir);
  1117.     changes->SpoolDir = spool_result;
  1118.     result = 0;
  1119.     } else {
  1120.     free(queue_result);
  1121.     free(spool_result);
  1122.     result = -1;
  1123.     }
  1124.  
  1125.     return result;
  1126. }
  1127.  
  1128.  
  1129. #define QUERY_YES    0
  1130. #define QUERY_NO    1
  1131. #define QUERY_BACK    2
  1132. static int queryConfig(void) {
  1133.     int result;
  1134.  
  1135.     result = newtWinTernary(_("Configure Printer"), _("Yes"), _("No"), 
  1136.                    _("Back"),
  1137.                    _("Would you like to configure a printer?"));
  1138.     
  1139.     if (result == 2) 
  1140.     return QUERY_NO;
  1141.     else if (result == 3)
  1142.     return QUERY_BACK;
  1143.  
  1144.     return QUERY_YES;
  1145. }
  1146.  
  1147. #if 0
  1148. static int query_add_more() {
  1149.     int result;
  1150.  
  1151.     result = newtWinChoice(_("Add Printer"), _("Yes"), _("No"), 
  1152.                    _("Would you like to add another printer?"));
  1153.  
  1154.     if (result == 2) 
  1155.     return -1;
  1156.     return 0;
  1157. }
  1158. #endif
  1159.  
  1160. static char * connToString(int connType) {
  1161.     switch (connType) {
  1162.     case PRINTER_LOCAL:        return "LOCAL";
  1163.     case PRINTER_LPRREM:        return "REMOTE";
  1164.     case PRINTER_SMB: default:    return "SMB";
  1165.     }
  1166. }
  1167.  
  1168. /* returns < 0 for user cancel, otherwise uses #defines in printercfg.h */
  1169. static int get_prn_connx(int connType) {
  1170.     int sel = connType, rc;
  1171.     char * connectionTypes[4];
  1172.  
  1173.     connectionTypes[0] = _("Local");
  1174.     connectionTypes[1] = _("Remote lpd");
  1175.     connectionTypes[2] = _("LAN Manager");
  1176.     connectionTypes[3] = NULL;
  1177.  
  1178.     sel--;
  1179.     rc = newtWinMenu(_("Select Printer Connection"),
  1180.              _("How is this printer connected?"), 40, 5, 5,
  1181.              5, connectionTypes, &sel, _("Ok"), _("Back"), NULL);
  1182.  
  1183.     if (rc == 2) return -1;
  1184.  
  1185.     return sel + 1;
  1186. }
  1187.  
  1188. /* returns 0 on success, -1 on cancel */
  1189. static int verify_pcentry( PCEntry *pcentry ) {
  1190.     char tmpstr[500];
  1191.     int done;
  1192.     int result;
  1193.     int i, max;
  1194.     char info[2000];
  1195.     int lens[15];
  1196.  
  1197.     lens[0] = strlen(_("Printer type:"));
  1198.     lens[1] = strlen(_("Queue:"));
  1199.     lens[2] = strlen(_("Spool directory:"));
  1200.     lens[3] = strlen(_("Printer device:"));
  1201.     lens[4] = strlen(_("Remote host:"));
  1202.     lens[5] = strlen(_("Remote queue:"));
  1203.     lens[6] = strlen(_("Server:"));
  1204.     lens[7] = strlen(_("Share:"));
  1205.     lens[8] = strlen(_("User:"));
  1206.     lens[9] = strlen(_("Printer driver:"));
  1207.     lens[10] = strlen(_("Paper size:"));
  1208.     lens[11] = strlen(_("Resolution:"));
  1209.     lens[12] = strlen(_("Bits per pixel:"));
  1210.  
  1211.     max = 0;
  1212.     for (i = 0; i <= 12; i++)
  1213.     if (lens[i] > max) max = lens[i];
  1214.  
  1215.     strcpy(info, _("Please verify that this printer information is "
  1216.            "correct:\n\n"));
  1217.  
  1218.     sprintf(tmpstr, "  %-*s %s\n  %-*s %s\n  %-*s %s\n", 
  1219.         max, _("Printer type:"), connToString(pcentry->Type),
  1220.         max, _("Queue:"), pcentry->Queue,
  1221.         max, _("Spool directory:"), pcentry->SpoolDir);
  1222.     strcat(info, tmpstr);
  1223.  
  1224.     if (pcentry->Type == PRINTER_LOCAL) {
  1225.     sprintf(tmpstr, "  %-*s %s\n", max, _("Printer device"), 
  1226.         pcentry->Device);
  1227.     } else if (pcentry->Type == PRINTER_LPRREM) {
  1228.     sprintf(tmpstr, "  %-*s %s\n  %-*s %s\n", 
  1229.         max, _("Remote host:"), pcentry->RemoteHost,
  1230.         max, _("Remote queue:"), pcentry->RemoteQueue);
  1231.     } else /* pcentry->Type == PRINTER_SMB */ {
  1232.     sprintf(tmpstr, "  %-*s %s", max, _("Server:"), pcentry->SMBHost);
  1233.     if (pcentry->SMBHostIP && pcentry->SMBHostIP[0]) {
  1234.         strcat(tmpstr, " <");
  1235.         strcat(tmpstr, pcentry->SMBHostIP);
  1236.         strcat(tmpstr, ">");
  1237.     }
  1238.  
  1239.     strcat(info, tmpstr);
  1240.  
  1241.     sprintf(tmpstr, "  %-*s %s\n  %-*s %s <Password hidden>\n", 
  1242.         max, _("Share:"), pcentry->SMBShare,
  1243.         max, _("User:"), pcentry->SMBUser);
  1244.     }
  1245.  
  1246.     strcat(info, tmpstr);
  1247.  
  1248.     sprintf(tmpstr, "  %-*s %s\n  %-*s %s\n  %-*s %s\n  %-*s %s", 
  1249.         max, _("Printer driver:"), pcentry->db->Descr,
  1250.         max, _("Paper size:"), pcentry->PaperSize,
  1251.         max, _("Resolution:"), pcentry->Resolution,
  1252.         max, _("Bits per pixel:"), pcentry->BitsPerPixel);
  1253.     strcat(info, tmpstr);
  1254.  
  1255.     done = 0;
  1256.     result = 0;
  1257.     while (!done) {
  1258.     i = newtWinChoice(_("Verify Printer Configuration"), _("Ok"), 
  1259.                 _("Back"), info);
  1260.  
  1261.     if (i == 2) {
  1262.         done = 1;
  1263.         result = -1;
  1264.     } else {
  1265.         done = 1;
  1266.         result = 0;
  1267.     }
  1268.     }
  1269.  
  1270.     return result;
  1271. }
  1272.  
  1273. /* edit the PrintCap Entry pcentry */
  1274. /* return < 0 if user aborts or error occurs */
  1275. static int edit_pcentry( PCEntry **pcentry, int direction ) {
  1276.     int result;
  1277.     int stage;
  1278.     int done;
  1279.     int abort;
  1280.     PCEntry *changes;
  1281.  
  1282.     /* copy current into temporary */
  1283.     changes = dup_PCEntry( *pcentry );
  1284.  
  1285.     done = 0;
  1286.     abort = 0;
  1287.     stage = direction > 0 ? 0 : 4;
  1288.  
  1289.     while (!done) {
  1290.  
  1291.     switch (stage) {
  1292.       case 0:
  1293.         if ((result = get_prn_connx(changes->Type)) == -1) {
  1294.         done = 1;
  1295.         abort = 1;
  1296.         } else {
  1297.         changes->Type = result;
  1298.         stage++;
  1299.         direction = 1;
  1300.         }
  1301.         break;
  1302.  
  1303.       case 1:
  1304.             result=get_std_info(changes);
  1305.         if (result < 0)
  1306.         direction = -1;
  1307.         else 
  1308.         direction = 1;
  1309.         stage += direction;
  1310.         break;
  1311.  
  1312.       case 2:
  1313.         if (changes->Type == PRINTER_SMB)
  1314.         result=get_smb_info(changes);
  1315.         else if (changes->Type == PRINTER_LPRREM)
  1316.         result=get_remote_info(changes);
  1317.         else if (changes->Type == PRINTER_LOCAL)
  1318.         result=get_local_info(changes);
  1319.         else
  1320.         return -1;
  1321.  
  1322.         if (result < 0)
  1323.         direction = -1;
  1324.         else 
  1325.         direction = 1;
  1326.         stage += direction;
  1327.         break;
  1328.  
  1329.       case 3:
  1330.         result=select_filter(changes, direction);
  1331.         if (result < 0)
  1332.         direction = -1;
  1333.         else 
  1334.         direction = 1;
  1335.         stage += direction;
  1336.         break;
  1337.  
  1338.       case 4:
  1339.         result = verify_pcentry(changes);
  1340.         if (result < 0)
  1341.         direction = -1;
  1342.         else 
  1343.         direction = 1;
  1344.         stage += direction;
  1345.         break;
  1346.  
  1347.       case 5:
  1348.         done = 1;
  1349.         break;
  1350.     }
  1351.     }
  1352.  
  1353.     if (!abort) {
  1354.     free_PCEntry(*pcentry);
  1355.     *pcentry = changes;
  1356.     return 0;
  1357.     } else {
  1358.     free_PCEntry(changes);
  1359.     return -1;
  1360.     }
  1361. }
  1362.  
  1363. /* given the path queue_path, we create all the required spool directory */
  1364. static int create_spool_dir( char *queue_path ) {
  1365.     int result, done;
  1366.     int oldmask;
  1367.     
  1368.     struct group *grent;
  1369.     gid_t lpgid = 0;
  1370.     
  1371.     FILE *groupfile;
  1372.     char groupfilename[80];
  1373.     
  1374.  
  1375.     oldmask=umask(0);
  1376.     result=mkdir(queue_path, 0755);
  1377.     if ( result < 0)
  1378.     if (errno != EEXIST)
  1379.         return -1;
  1380.     umask(oldmask);
  1381.   
  1382.     strcpy(groupfilename, root_path);
  1383.     strcat(groupfilename, "/etc/group");
  1384.     if ((groupfile=fopen(groupfilename, "r"))==NULL)
  1385.     return -1;
  1386.     
  1387.     done=0;
  1388.     while (!done) {
  1389.     grent=fgetgrent(groupfile);
  1390.     if (grent==NULL)
  1391.         return -1;
  1392.       
  1393.     if (!strcmp(grent->gr_name, "lp")) {
  1394.         lpgid=grent->gr_gid;
  1395.         done |= 2;
  1396.     }
  1397.     }
  1398.  
  1399.     fclose(groupfile);
  1400.   
  1401.     if (!done)
  1402.     return -1;
  1403.   
  1404.     result=chown(queue_path, 0, lpgid );
  1405.     if ( result < 0)
  1406.     return -1;
  1407.  
  1408.     return 0;
  1409. }
  1410.  
  1411.  
  1412. /* given the input spec file 'input', and the target output file 'output' */
  1413. /* we set the fields specified by fieldname to the values in fieldval     */
  1414. /* nval  is the number of fields to set                                   */
  1415. /* Doesnt currently catch error exec'ing sed yet                          */
  1416. static int create_config_file( char *input, char *output, 
  1417.             char **fieldname, char **fieldval, 
  1418.             int nval ) {
  1419.     int status;
  1420.     int infd, outfd;
  1421.     int childpid;
  1422.     int i, j;
  1423.     
  1424.     int oldmask;
  1425.  
  1426.     char **sedargs;
  1427.     char *sedcmd;
  1428.     
  1429.     oldmask = umask(0);
  1430.     
  1431.     outfd=creat(output, 0755 );
  1432.     umask(oldmask);
  1433.     if (outfd == -1)
  1434.     return -1;
  1435.   
  1436.     infd=open(input, O_RDONLY);
  1437.     if (infd == -1)
  1438.     return -1;
  1439.  
  1440.     /* we have to setup the args to sed */
  1441.     /* need the name to exec, plus 2 args per field, plus NULL at end */
  1442.     sedargs = (char **) malloc( (nval + 2) * sizeof( char * ) );
  1443.     if (!sedargs)
  1444.     return -1;
  1445.  
  1446.     sedargs[0] = "/bin/sed";
  1447.     sedargs[nval+1] = NULL;
  1448.     for (i=0; i<nval; i++) {
  1449.     sedargs[i+1] = (char *) malloc(25 + strlen(fieldname[i]) +
  1450.                        strlen(fieldval[i]));
  1451.     /* if we get an error, try to cleanup */
  1452.     if (!sedargs[i+1]) {
  1453.         for (j=0; j<i; j++)
  1454.         if (sedargs[j+1])
  1455.             free(sedargs[j+1]);
  1456.         
  1457.         if (sedargs)
  1458.         free(sedargs);
  1459.         
  1460.         return -1;
  1461.     }
  1462.     sprintf(sedargs[i+1], "-e s/@@@%s@@@/%s/g", fieldname[i], fieldval[i]);
  1463.     }
  1464.  
  1465.     sedcmd = malloc(strlen(root_path)+15);
  1466.     if (!sedcmd)
  1467.     return -1;
  1468.     
  1469.     strcpy(sedcmd, root_path);
  1470.     strcat(sedcmd, "/bin/sed");
  1471.     
  1472.     if (!(childpid = fork())) {
  1473.     close(0);
  1474.     close(1);
  1475.     dup2(infd, 0);
  1476.     dup2(outfd, 1);
  1477.     close(infd);
  1478.     close(outfd);
  1479.     execv(sedcmd, sedargs);
  1480.     exit(-1);
  1481.     }
  1482.  
  1483.     close(infd);
  1484.     close(outfd);
  1485.  
  1486.     waitpid(childpid, &status, 0);
  1487.  
  1488.     if (sedcmd)
  1489.     free(sedcmd);
  1490.  
  1491.     for (i=0; i<nval; i++)
  1492.     if (sedargs[i+1])
  1493.         free(sedargs[i+1]);
  1494.  
  1495.     if (sedargs)
  1496.     free(sedargs);
  1497.  
  1498.     return 0;
  1499. }
  1500.  
  1501. /* copy master filter to the spool dir */
  1502. static int copy_master_filter( char *queue_path ) {
  1503.     int childpid, status;
  1504.     char *masterfilter, *cpcmd, *dest;
  1505.     
  1506.     masterfilter=malloc(strlen(PRINTER_FILTER_DIR)+strlen(root_path)+20);
  1507.     strcpy(masterfilter,root_path);
  1508.     strcat(masterfilter,PRINTER_FILTER_DIR);
  1509.     strcat(masterfilter,"master-filter");
  1510.     
  1511.     dest=malloc(strlen(queue_path)+20);
  1512.     strcpy(dest,queue_path);
  1513.     strcat(dest,"filter");
  1514.     
  1515.     cpcmd = malloc(strlen(root_path)+15);
  1516.     if (!cpcmd)
  1517.     return -1;
  1518.     
  1519.     strcpy(cpcmd, root_path);
  1520.     strcat(cpcmd, "/bin/cp");
  1521.     
  1522.     if (!(childpid = fork())) 
  1523.     execl(cpcmd, cpcmd, masterfilter, dest, NULL);
  1524.  
  1525.     waitpid(childpid, &status, 0);
  1526.     
  1527.     free(masterfilter);
  1528.     free(cpcmd);
  1529.     free(dest);
  1530.     return 0;
  1531. }
  1532.  
  1533. /* given a PrintCap Entry, create the spool dir and special */
  1534. /* rhs-printfilters related config files which are required */
  1535. static int configure_queue( PCEntry *pcentry ) {
  1536.     char *queue_path;
  1537.     char *output;
  1538.     char *input;
  1539.     char colorstr[80]; /* holds the '-dBitsPerPixel=nn' */
  1540.     
  1541.     char **fieldname;
  1542.     char **fieldval;
  1543.     int  nfield;
  1544.  
  1545.     FILE *printcap, *smbconfig;
  1546.  
  1547.     if (testing) return 0;
  1548.     
  1549.     if (pcentry->SpoolDir) {
  1550.     /* create the spooldir and set to root.lp ownership */
  1551.     queue_path=malloc(strlen(root_path)+strlen(pcentry->SpoolDir)+5);
  1552.     strcpy(queue_path, root_path);
  1553.     strcat(queue_path, pcentry->SpoolDir);
  1554.     strcat(queue_path, "/");
  1555.     if (create_spool_dir(queue_path) < 0)
  1556.         return -1;
  1557.     
  1558.     /* make the cfg files we need */
  1559.     output=malloc(strlen(queue_path)+strlen("general.cfg")+2);
  1560.     strcpy(output,queue_path);
  1561.     strcat(output,"general.cfg");
  1562.     input=malloc(strlen(root_path)+strlen(PRINTER_FILTER_DIR)+
  1563.              strlen("general.cfg.in")+2);
  1564.     strcpy(input,root_path);
  1565.     strcat(input,PRINTER_FILTER_DIR);
  1566.     strcat(input,"general.cfg.in");
  1567.  
  1568.     /* setup the field arrays */
  1569.     nfield = 4;
  1570.     fieldname = (char **) malloc( nfield * sizeof(char *) );
  1571.     fieldname[0] = "desiredto";
  1572.     fieldname[1] = "papersize";
  1573.     fieldname[2] = "printertype";
  1574.     fieldname[3] = "ascps_trans";
  1575.     
  1576.     fieldval = (char **) malloc( nfield * sizeof(char *) );
  1577.  
  1578.     if (strcmp(pcentry->db->GSDriver, "TEXT"))
  1579.         fieldval[0] = "ps";
  1580.     else
  1581.         fieldval[0] = "asc";
  1582.  
  1583.     if (!pcentry->PaperSize)
  1584.         fieldval[1] = "letter";
  1585.     else
  1586.         fieldval[1] = pcentry->PaperSize;
  1587.  
  1588.     fieldval[2] = connToString(pcentry->Type);
  1589.     
  1590.     if (strcmp(pcentry->db->GSDriver, "POSTSCRIPT"))
  1591.         fieldval[3] = "NO";
  1592.     else
  1593.         fieldval[3] = "YES";
  1594.  
  1595.     if (create_config_file(input, output, fieldname, fieldval, nfield) < 0)
  1596.         return -1;
  1597.  
  1598.     /* successfully created general.cfg, now do postscript.cfg */
  1599.     free(fieldname);
  1600.     free(fieldval);
  1601.     free(output);
  1602.     free(input);
  1603.  
  1604.     output=malloc(strlen(queue_path)+strlen("postscript.cfg")+2);
  1605.     strcpy(output,queue_path);
  1606.     strcat(output,"postscript.cfg");
  1607.     input=malloc(strlen(root_path)+strlen(PRINTER_FILTER_DIR)+
  1608.              strlen("postscript.cfg.in")+2);
  1609.     strcpy(input,root_path);
  1610.     strcat(input,PRINTER_FILTER_DIR);
  1611.     strcat(input,"postscript.cfg.in");
  1612.  
  1613.     /* setup the field arrays */
  1614.     nfield = 10;
  1615.     fieldname = (char **) malloc( nfield * sizeof(char *) );
  1616.     fieldname[0] = "gsdevice";
  1617.     fieldname[1] = "papersize";
  1618.     fieldname[2] = "resolution";
  1619.     fieldname[3] = "color";
  1620.     fieldname[4] = "reversepages";
  1621.     fieldname[5] = "extragsoptions";
  1622.     fieldname[6] = "pssendeof";
  1623.     fieldname[7] = "nup";
  1624.     fieldname[8] = "rtlftmar";
  1625.     fieldname[9] = "topbotmar";
  1626.     
  1627.     fieldval = (char **) malloc( nfield * sizeof(char *) );
  1628.     
  1629.     /* gsdriver */
  1630.     fieldval[0] = pcentry->db->GSDriver;
  1631.     
  1632.     /* papersize */
  1633.     if (!pcentry->PaperSize)
  1634.         fieldval[1] = "letter";
  1635.     else
  1636.         fieldval[1] = pcentry->PaperSize;
  1637.     
  1638.     /* resolution */
  1639.     if (!pcentry->Resolution)
  1640.         fieldval[2] = "";
  1641.     else
  1642.         if (strcmp(pcentry->Resolution,"Default"))
  1643.         fieldval[2] = pcentry->Resolution;
  1644.         else
  1645.         fieldval[2] = "";
  1646.  
  1647.     /* color depth */
  1648.     if (!pcentry->BitsPerPixel)
  1649.         fieldval[3] = "";
  1650.     else
  1651.         if (strcmp(pcentry->BitsPerPixel,"Default")) {
  1652.         strcpy(colorstr,"-dBitsPerPixel=");
  1653.         strcat(colorstr,pcentry->BitsPerPixel);
  1654.         fieldval[3] = colorstr;
  1655.         } else
  1656.         fieldval[3] = "";
  1657.     
  1658.     fieldval[4] = "NO";
  1659.  
  1660.     /* extra gs options */
  1661.     fieldval[5] = "";
  1662.  
  1663.     /* ps send eof */
  1664.     if (strcmp(pcentry->db->GSDriver, "POSTSCRIPT"))
  1665.         fieldval[6] = "NO";
  1666.     else
  1667.         fieldval[6] = "YES";
  1668.  
  1669.     /* nup */
  1670.     fieldval[7] = "1";
  1671.     
  1672.     /* rtlftmar */
  1673.     fieldval[8] = "18";
  1674.     
  1675.     /* topbotmar */
  1676.     fieldval[9] = "18";
  1677.     
  1678.     if (create_config_file(input, output, fieldname, fieldval, nfield) < 0)
  1679.         return -1;
  1680.     
  1681.     /* finally, make textonly.cfg */
  1682.     free(fieldval);
  1683.     free(fieldname);
  1684.     free(output);
  1685.     free(input);
  1686.     
  1687.     output=malloc(strlen(queue_path)+strlen("textonly.cfg")+2);
  1688.     strcpy(output,queue_path);
  1689.     strcat(output,"textonly.cfg");
  1690.     input=malloc(strlen(root_path)+strlen(PRINTER_FILTER_DIR)+
  1691.              strlen("textonly.cfg.in")+2);
  1692.     strcpy(input,root_path);
  1693.     strcat(input,PRINTER_FILTER_DIR);
  1694.     strcat(input,"textonly.cfg.in");
  1695.     
  1696.     /* setup the field arrays */
  1697.     nfield = 3;
  1698.     fieldname = (char **) malloc( nfield * sizeof(char *) );
  1699.     fieldname[0] = "textonlyoptions";
  1700.     fieldname[1] = "crlftrans";
  1701.     fieldname[2] = "textsendeof";
  1702.     
  1703.     fieldval = (char **) malloc( nfield * sizeof(char *) );
  1704.     fieldval[0] = "";
  1705.     fieldval[1] = pcentry->CRLF ? "1" : "";
  1706.     fieldval[2] = "1";
  1707.     
  1708.     if (create_config_file(input, output, fieldname, fieldval, nfield) < 0)
  1709.         return -1;
  1710.     
  1711.     /* simple config file required if SMB printer */
  1712.     if (pcentry->Type == PRINTER_SMB) {
  1713.         output=malloc(strlen(queue_path)+15);
  1714.         strcpy(output,queue_path);
  1715.         strcat(output,".config");
  1716.         smbconfig = fopen(output, "w");
  1717.         
  1718.         fprintf(smbconfig,"share='\\\\%s\\%s'\n",
  1719.             pcentry->SMBHost, pcentry->SMBShare);
  1720.         fprintf(smbconfig,"hostip=%s\n",pcentry->SMBHostIP);
  1721.         fprintf(smbconfig,"user=%s\n",pcentry->SMBUser);
  1722.         fprintf(smbconfig,"password=%s\n",pcentry->SMBPasswd);
  1723.  
  1724.         fclose(smbconfig);
  1725.     }
  1726.  
  1727.     /* we're done with config files - need to copy filter over now  */
  1728.     free(fieldval);
  1729.     free(fieldname);
  1730.     free(output);
  1731.     free(input);
  1732.     
  1733.     if ( copy_master_filter(queue_path) < 0 )
  1734.         return -1;
  1735.     } else
  1736.     return -1; /* we have to have a spool dir! */
  1737.  
  1738.     /* assume that spool dir got setup ok, now add printcap entry */
  1739.     output=alloca(strlen("/etc/printcap")+strlen(root_path)+2);
  1740.     strcpy(output,root_path);
  1741.     strcat(output,"/etc/printcap");
  1742.  
  1743.     printcap=fopen(output, "w");
  1744.     if (printcap == NULL)
  1745.     return -1;
  1746.     
  1747.     fputs("#\n", printcap);
  1748.     fputs("# Please don't edit this file directly unless you know what "
  1749.         "you are doing!\n", printcap);
  1750.     fputs("# Be warned that the control-panel printtool requires a very "
  1751.         "strict format!\n", printcap);
  1752.     fputs("# Look at the printcap(5) man page for more info.\n", printcap);
  1753.     fputs("#\n", printcap);
  1754.     fputs("# This file can be edited with the printtool in the "
  1755.         "control-panel.\n", printcap);
  1756.     fputs("\n", printcap);
  1757.  
  1758.     fputs("\n",printcap);
  1759.     fprintf(printcap, "##PRINTTOOL3## %s %s %s %s %s %s %s %s \n",
  1760.         connToString(pcentry->Type),
  1761.         pcentry->db->GSDriver,
  1762.         pcentry->Resolution,
  1763.         pcentry->PaperSize,
  1764.         "{}",
  1765.         pcentry->db->Entry,
  1766.         pcentry->BitsPerPixel,
  1767.         "{}");
  1768.     fprintf(printcap, "%s:\\\n",pcentry->Queue);
  1769.     fprintf(printcap, "\t:sd=%s:\\\n",pcentry->SpoolDir);
  1770.     fprintf(printcap, "\t:mx#0:\\\n\t:sh:\\\n");
  1771.     
  1772.     if (pcentry->Type == PRINTER_LOCAL) {
  1773.     fprintf(printcap,"\t:lp=%s:\\\n",pcentry->Device);
  1774.     } else if (pcentry->Type == PRINTER_LPRREM) {
  1775.     fprintf(printcap,"\t:rm=%s:\\\n",pcentry->RemoteHost);
  1776.     fprintf(printcap,"\t:rp=%s:\\\n",pcentry->RemoteQueue);
  1777.     } else /* (pcentry->Type == PRINTER_SMB) */ {
  1778.     fprintf(printcap,"\t:lp=/dev/null:\\\n");
  1779.     fprintf(printcap,"\t:af=%s/%s\\\n",pcentry->SpoolDir,"acct");
  1780.     }
  1781.  
  1782.     /* cheating to get the input filter! */
  1783.     fprintf(printcap,"\t:if=%s/%s:\n",pcentry->SpoolDir,"filter");
  1784.     fclose(printcap);
  1785.     return 0;
  1786. }
  1787.  
  1788.  
  1789. int doConfigurePrinters (char *theroot, int direction) {
  1790.  
  1791.     int done, result;
  1792.     static PCEntry *pcentry = NULL;
  1793.     int stage = (direction > 0 || !pcentry) ? 1 : 2;
  1794.     char * printcapFile;
  1795.  
  1796.     printcapFile = alloca(strlen("/etc/printcap") + strlen(theroot) + 2);
  1797.     strcpy(printcapFile, theroot);
  1798.     strcat(printcapFile, "/etc/printcap");
  1799.  
  1800.     /* root under which the installed system lives */
  1801.     root_path = theroot;
  1802.  
  1803.     /* read the printer database into memory -- ignore these errors as they
  1804.        probably indicate missing packages */
  1805.     if (read_printer_db(PRINTER_DB_FILE)) return INST_NOP;
  1806.  
  1807.     install_return_code = 0;
  1808.     done = 0;
  1809.  
  1810.     while (stage <= 2) {
  1811.     switch (stage) {
  1812.       case 1:
  1813.         result = queryConfig();
  1814.         if (result == QUERY_BACK) 
  1815.         return INST_CANCEL;
  1816.         else if (result == QUERY_NO) {
  1817.         if (pcentry) free(pcentry);
  1818.         if (!testing) unlink(printcapFile);
  1819.         pcentry = NULL;
  1820.         return 0;
  1821.         }
  1822.         stage = 2, direction = 1;
  1823.         break;
  1824.  
  1825.       case 2:
  1826.         if (!pcentry) pcentry = new_PCEntry();
  1827.         result = edit_pcentry(&pcentry, direction);
  1828.         
  1829.         if (result == -1) {
  1830.         stage = 1, direction = -1;
  1831.         } else {
  1832.         configure_queue( pcentry );
  1833.         stage = 3;
  1834.         }
  1835.         break;
  1836.     }
  1837.     }
  1838.  
  1839.     return 0;
  1840. }
  1841.  
  1842.