home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / TELECOM / OS9_Unix.lzh / RSHSRC / printbsd.c < prev    next >
C/C++ Source or Header  |  1992-10-06  |  11KB  |  423 lines

  1. /*
  2.     OSK version developed by Ivan Powis <pczip@chem.nott.ac.uk>
  3. */
  4. /*
  5.  * Send files to a Berkeley (BSD) line printer daemon.
  6.  * This is done using a TCP connection, following the protocol
  7.  * inherent (and undocumented) in the BSD printer daemon (/usr/lib/lpd).
  8.  *
  9.  * This program differs from the normal BSD lpr(1) command in the
  10.  * following ways.  The BSD lpr command writes the files to be
  11.  * printed into the spooling directory, and then notifies the
  12.  * line printer daemon (lpd) that the files are there (using a
  13.  * UNIX domain socket message).  The lpd program then sees that
  14.  * the files get printed at some time.  If the files are to be
  15.  * printed on another host's line printer, then the printer daemon
  16.  * will contact the daemon on the other host (using an Internet
  17.  * TCP socket) and will transfer the file to the other daemon,
  18.  * who will then see to it that the file gets printed.
  19.  * This program, however, acts like a UNIX printer daemon (lpd)
  20.  * as we assume the files are to be printed on another system.
  21.  * We go ahead and contact the UNIX lpd program on the remote host
  22.  * (using an Internet TCP socket) and send the files to that
  23.  * daemon for printing.
  24.  *
  25.  * There are three functions in this file that main() calls:
  26.  *    send_start() - called once, before the first file
  27.  *    send_file()  - called for every file that can be opened by main
  28.  *    send_done()  - called at the end
  29.  */
  30.  
  31. #include    "lpr.h"
  32. #include    <pwd.h>
  33. #define    gethostname(A,B) g_hostname( (A),(B) ) /*cos os9 standard is no good*/
  34.  
  35. /*
  36.  * Variables specific to this file.
  37.  */
  38.  
  39. static FILE    *cfp;            /* file pointer for control file */
  40. static long    cfilesize;        /* size of cfile, in bytes */
  41.  
  42. static char    cfname[MAXLEN];    /* name of "cf" file */
  43. static char    dfname[MAXLEN];    /* name of "df" file */
  44. static char    buf[MAXLINE];        /* temp buffer */
  45. static int    sockfd;            /* network connection */
  46. static int    seqnum;            /* seq#, set to same value for now */
  47.  
  48. long    get_size();
  49.  
  50. /*
  51.  * Make connection to remote host
  52.  */
  53.  
  54. setup_conn()
  55. {
  56.     register int    uid;
  57.     struct passwd    *pw, *getpwuid();
  58.  
  59.  
  60.                         /* we need a reserved port */
  61.     uid=getuid();
  62.     setuid(0);            /*become super !*/
  63.     if ( (sockfd = tcp_open(hostname, LPR_SERVICE, -1)) < 0)
  64.         exit(_errmsg(errno,"can't connect to service: %s on host: %s",
  65.                         LPR_SERVICE, hostname));
  66.  
  67.     /*
  68.      * If we got the reserved port, then we're either running as
  69.      * root, or the program is set-user-ID root.  In the latter case,
  70.      * the only reason we need to be set-user-ID root is to bind the
  71.      * reserved port, so we can now go back to being the "real"
  72.      * user who executed this program.  We really need to do
  73.      * this anyway, to assure we can't read files as root
  74.      * that the user doesn't have normal access to.
  75.      */
  76.  
  77.     setuid(uid);
  78.  
  79.     /*
  80.      * Get the name of the local host.
  81.      */
  82.  
  83.     if (gethostname(myhostname, MAXHOSTNAMELEN) < 0)
  84.         perror("gethostname error");
  85.  
  86.     /*
  87.      * Get the name of the user executing this program.
  88.      */
  89.  
  90.     if ( (pw = getpwuid(uid)) == NULL)
  91.         exit(_errmsg(0,"getpwuid failed, uid = %d; who are you", uid));
  92.     strcpy(username, pw->pw_name);
  93. }
  94.  
  95. /*
  96.  *    Get a status message from server
  97.  */
  98. void query_server(s)
  99. char *s;
  100. {
  101.     register int c;
  102.     int time=0;
  103.     
  104.     if (*s++ == '+') time=5;
  105.     if (*s >= '0' && *s <='9') time=atoi(s);
  106.     if(!qflag) printf("%s on %s: ",printername,hostname);
  107.     fflush(stdout);
  108. re_query:
  109.     setup_conn();
  110.     sprintf(buf,"\004%s\l",printername);
  111.     if (write(sockfd, buf, strlen(buf)) < strlen(buf))
  112.         perror("status output: ");
  113.     while ((c=readline(sockfd, buf, MAXLINE)) > 0)
  114.         writeln(1,buf,c);
  115.     if(time==0) return;
  116.     close(sockfd);
  117.     sleep(time);
  118.     goto re_query;
  119. }    
  120. /*
  121.  *    Send a cancel or kill message to server
  122.  */
  123. send_kill(s)
  124. char *s;
  125. {
  126.     register int c;
  127.     setup_conn();
  128.     sprintf(buf,"\005%s %s %s\l",printername,rusername,s);
  129.     if (writen(sockfd, buf, strlen(buf)) != strlen(buf))
  130.         perror("writen error");
  131.  
  132.     while ((c=readline(sockfd, buf, MAXLINE)) > 0){
  133.         writeln(1,buf,c);
  134.     }
  135. }    
  136.  
  137. /*
  138.  * Start things up.
  139.  */
  140.  
  141. send_start()
  142. {
  143.     DEBUG2("send_start: host = %s, printer = %s", hostname, printername);
  144.     setup_conn();
  145.     /*
  146.      * We must insert a 3-digit sequence number into the filenames
  147.      * that we're creating to send to the server.  This is to
  148.      * distinguish between successive files that are sent to the
  149.      * same server for the same printer.
  150.      */
  151.  
  152.     seqnum = get_seqno();
  153.  
  154.     sprintf(cfname, "cfA%03d%s", seqnum, myhostname);
  155.     sprintf(dfname, "dfA%03d%s", seqnum, myhostname);
  156.     sprintf(jcname, "%s-%03d",myhostname,seqnum);
  157.     DEBUG2("cfname = %s, dfname = %s", cfname, dfname);
  158.  
  159.     /*
  160.      * Create the control file and open it for writing.
  161.      */
  162.  
  163.     if ( (cfp = fopen(cfname, "w")) == NULL)
  164.         fprintf(stderr,"can't open control file: %s for writing", cfname);
  165.     cfilesize = 0L;
  166.  
  167.     /*
  168.      * Initialize the control file by inserting the following lines:
  169.      *
  170.      *    H<hostname>    (host on which the lpr was executed)
  171.      *    P<username>    (person executing the lpr)
  172.      *    J<jobname>    (for the banner page)
  173.      *    C<classname>    (for the banner page)
  174.      *    L<username>    (literal value for banner page)
  175.      *  M<user>        (for mail when job done)
  176.      *
  177.      * Then, for each file to be printed, send_file() will add
  178.      * the following three lines:
  179.      *
  180.      *    f<df_filename>    (name of text file to print)
  181.      *    U<df_filename>    (to unlink the file after printing)
  182.      *    N<filename>    (real name of the file, used by lpq)
  183.      *
  184.      * The <df_filename> is of the form "df[A-Z]nnn<host>" where
  185.      * "nnn" is the 3-digit sequence number from this host,
  186.      * and "<host>" is the name of the host on which the lpr
  187.      * was executed.
  188.      */
  189.  
  190.     add_com('H',myhostname);
  191.     add_com('P',rusername);
  192.     add_com('C',Cname);
  193.     add_com('L',rusername);
  194.     if(mailflag) add_com('M',rusername);
  195.     
  196.     /*
  197.      * Send a line to the print server telling it we want
  198.      * to send it some files to print, and specifying the
  199.      * printer to be used.
  200.      */
  201.  
  202.     sprintf(buf, "%c%s\l", '\002', printername);
  203.     if (writen(sockfd, buf, strlen(buf)) != strlen(buf))
  204.         perror("writen error");
  205.  
  206.     if (readn(sockfd, buf, 1) != 1)
  207.         perror("readn error");
  208.     if (buf[0] != '\0') {
  209.         if (readline(sockfd, &buf[1], MAXLINE-1) > 0)
  210.            exit(_errmsg(0,"error, server returned: %s", buf));
  211.         else
  212.            exit(_errmsg(0,"didn't get ACK from server, got 0x%02x", buf[0]));
  213.     }
  214. }
  215.  
  216. /*
  217.  * Send a single file.
  218.  * This function is called by main once for every file to be printed.
  219.  * Main has already opened the file for reading, but it still passes
  220.  * us the actual filename from the command line, so that we can
  221.  * use the filename for identifying the file to the server.
  222.  */
  223.  
  224. void send_file(filename, fp)
  225. char    *filename;    /* filename from command line, or "-stdin" */
  226. FILE    *fp;        /* file pointer on which file is open for reading */
  227. {
  228.     static int    filecount = 0;
  229.     register char    *ptr;
  230.     char        *rindex();
  231.  
  232.     filecount++;
  233.  
  234.     /*
  235.      * First strip any leading directory names off the filename.
  236.      * This is to get the base filename for the job banner.
  237.      */
  238.  
  239.     if ( (ptr = rindex(filename, '/')) != NULL) {
  240.         filename = ptr + 1;
  241.     }
  242.  
  243.     /*
  244.      * If this is the first file, set the Job Class on the banner
  245.      * page to the filename.
  246.      */
  247.  
  248.     if (filecount == 1){
  249.         if (Jname != 0) add_com('J',Jname);
  250.         else add_com('J',filename);
  251.     }
  252.     else
  253.         dfname[2]++;    /* A, B, C, ... */
  254.  
  255.     /*
  256.      * Add the 'f', 'U' and 'N' lines to the control file.
  257.      */
  258.  
  259.     add_com('T',filename);
  260.     if(rflag)
  261.         add_com('l',dfname);
  262.     else
  263.         add_com('f',dfname);
  264.     add_com('U',dfname);
  265.     add_com('N',filename);
  266.  
  267.     DEBUG2("send_file: %s, dfname = %s", filename, dfname);
  268.  
  269.     xmit_file(filename, fp, dfname, '\003');
  270.                 /* transmit file across network */
  271. }
  272.  
  273. /*
  274.  * All done with the user's files.
  275.  * Now we must transmit the control file that we've been building
  276.  * to the other side.
  277.  */
  278.  
  279. send_done()
  280. {
  281.     fclose(cfp);
  282.  
  283.     if ( (cfp = fopen(cfname, "r")) == NULL)
  284.         perror("can't reopen cfile for reading");
  285.  
  286.     xmit_file("-cfile", cfp, cfname, '\002');
  287.  
  288.     fclose(cfp);
  289.  
  290.     /*
  291.      * We're done with the control file, so delete it.
  292.      * (Don't unlink if debugflag is 1, assuming we're debugging.)
  293.      */
  294.  
  295.     if (debugflag == 0 && unlink(cfname) < 0)
  296.         perror("can't unlink control file: %s", cfname);
  297.  
  298.     close(sockfd);
  299. }
  300.  
  301. /*
  302.  * Transmit one file to the server.
  303.  * This routine is used to send both the actual text files (data files)
  304.  * that the user wants printed, and to send the control file (cfile)
  305.  * that we build up as we send the data files.
  306.  * The only difference between transmitting these two types of files
  307.  * is the first byte of the transmission (002 for the cfile and 003
  308.  * for the dfiles).
  309.  */
  310.  
  311. xmit_file(filename, fp, fname, xmittype)
  312. char    *filename;    /* name from command line, or "-stdin" or "-cfile" */
  313. FILE    *fp;
  314. char    *fname;        /* the cfname or dfname */
  315. char    xmittype;    /* '\002' or '\003' */
  316. {
  317.     register long    size;
  318.  
  319.     /*
  320.      * We have to get the exact size of the file in bytes
  321.      * to send to the server, so that it knows how much
  322.      * data to read from the net.
  323.      */
  324.  
  325.     size = get_size(filename, fp);
  326.     DEBUG2("xmit_file: %s, size = %ld", filename, size);
  327.  
  328.     /*
  329.      * Send a line to the print server giving the type of
  330.      * file, the exact size of the file in bytes,
  331.      * and the name of the file (its dfname, not its actual
  332.      * name).
  333.      */
  334.  
  335.     sprintf(buf, "%c%ld %s\l", xmittype, size, fname);
  336.     if (writen(sockfd, buf, strlen(buf)) != strlen(buf))
  337.         perror("writen error");
  338.     if (readn(sockfd, buf, 1) != 1)
  339.         perror("readn error");
  340.     if (buf[0] != '\0')
  341.         fprintf(stderr,"didn't get an ACK from server, got 0x%02x", buf[0]);
  342.  
  343.     /*
  344.      * Now send the actual file itself.
  345.      */
  346.  
  347.     copyfile(fp);
  348.  
  349.     /*
  350.      * Write a byte of zero to the server, and wait for
  351.      * a byte of zero to be returned from the server,
  352.      * telling us all is OK (I'm OK, you're OK).
  353.      */
  354.  
  355.     if (writen(sockfd, "", 1) != 1)
  356.         perror("writen error");
  357.     if (readn(sockfd, buf, 1) != 1)
  358.         perror("readn error");
  359.     if (buf[0] != '\0')
  360.         fprintf(stderr,"Server responds with error code %02x", buf[0]);
  361. }
  362.  
  363. /*
  364.  * Copy a file to the network.
  365.  * We read the file using standard i/o, one line at a time,
  366.  * and write the data to the network one line at a time.
  367.  */
  368.  
  369. copyfile(fp)
  370. FILE    *fp;
  371. {
  372.     register int    len;
  373.     char        line[MAXLINE];
  374.  
  375.     while (fgets(line, MAXLINE, fp) != NULL) {
  376.         len = strlen(line);
  377.         if(!rflag) r_to_l(line,len);        /* os9 \n -> UNIX \l */
  378.         if (writen(sockfd, line, len) != len)
  379.             perror("writen error");
  380.     }
  381.  
  382.     if (ferror(fp))
  383.         perror("read error from fgets");
  384. }
  385.  
  386. /*
  387.  * Determine the exact size of a file.
  388.  * Under UNIX this is easy - we just call the fstat() system call.
  389.  * Under other operating systems it is harder, since they may not use
  390.  * exactly one character to represent a newline.
  391.  */
  392.  
  393. long
  394. get_size(filename, fp)
  395. char    *filename;
  396. FILE    *fp;
  397. {
  398.     int l;
  399.     
  400.     if ((l=_gs_size(fileno(fp))) < 0)
  401.         perror("can't fstat");
  402.  
  403.     return(l);
  404. }
  405.  
  406. add_com(c,str)
  407. char c, *str;
  408. {
  409.     fprintf(cfp, "%c%s\l", c,str);
  410.     cfilesize += strlen(str) + 2;
  411. }
  412.  
  413. r_to_l(str,len)
  414. register int len;
  415. register char *str;
  416. {
  417.     int i;
  418.  
  419.     for(i=0;i<len;i++,str++){
  420.         if(*str == '\r') *str='\l';
  421.     }
  422. }
  423.