1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of
5 * the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
15 * MA 02111-1307 USA
16 */
17/***************************************************************************
18 * LPRng - An Extended Print Spooler System
19 *
20 * Copyright 1988-2003, Patrick Powell, San Diego, CA
21 *     papowell@lprng.com
22 * See LICENSE for conditions of use.
23 *
24 ***************************************************************************/
25
26 static char *const _id =
27"$Id: sendreq.c,v 1.1.1.1 2008/10/15 03:28:27 james26_jang Exp $";
28
29
30#include "lp.h"
31
32#include "child.h"
33#include "fileopen.h"
34#include "getqueue.h"
35#include "linksupport.h"
36#include "readstatus.h"
37#include "user_auth.h"
38#include "sendreq.h"
39#include "sendauth.h"
40
41/**** ENDINCLUDE ****/
42
43
44/***************************************************************************
45 * Commentary:
46 * The protocol used to send requests to a remote host consists of the
47 * following:
48 *
49 * Client                                   Server
50 * - short format
51 * \Xprintername option option\n - request
52 *                                          status\n
53 * 										....
54 *                                          status\n
55 * 										<close connection>
56 *
57 * The requestor:
58 * 1.  makes a connection (connection timeout)
59 * 2.  sends the \3printername options line
60 * 3.  reads from the connection until nothing left
61 *
62 * int Send_request( char *printer,	* name of printer *
63 * 	char *host,					* name of remote host *
64 * 	int class,					* 'Q'= LPQ, 'C'= LPC, M = lprm *
65 * 	int format,					* X value for request *
66 * 	char **options,				* options to send *
67 * 	int connnect_timeout,		* timeout on connection *
68 * 	int transfer_timeout,		* timeout on transfer *
69 * 	int output )				* output fd
70 *
71 **************************************************************************/
72
73
74/***************************************************************************
75 * Send_request
76 * 1. Open connection to remote host
77 * 2. Send a line of the form:
78 *     \Xprinter <options>
79 * 3. Read from the connection until closed and echo on fd 1
80 ***************************************************************************/
81
82int Send_request(
83	int class,					/* 'Q'= LPQ, 'C'= LPC, M = lprm */
84	int format,					/* X for option */
85	char **options,				/* options to send */
86	int connnect_timeout,		/* timeout on connection */
87	int transfer_timeout,		/* timeout on transfer */
88	int output					/* output on this FD */
89	)
90{
91	char errormsg[LARGEBUFFER];
92	char *cmd = 0;
93	int status = -1, sock = -1, err;
94	char *real_host = 0;
95	char *save_host = 0;
96	struct security *security = 0;
97	struct line_list info;
98
99	Init_line_list(&info);
100	errormsg[0] = 0;
101
102	DEBUG1("Send_request: printer '%s', host '%s', format %d",
103		RemotePrinter_DYN, RemoteHost_DYN, format );
104	DEBUG1("Send_request: connnect_timeout %d, transfer_timeout %d",
105			connnect_timeout, transfer_timeout );
106
107#ifdef ORIGINAL_DEBUG//JY@1020
108	security = Fix_send_auth(0,&info, 0, errormsg, sizeof(errormsg) );
109#endif
110
111	DEBUG1("Send_request: security %s", security?security->name:0 );
112	if( security ){
113		DEBUG1("Send_request: security name '%s', tag '%s'",
114		security->name, security->config_tag );
115	}
116	if( errormsg[0] ){
117		goto error;
118	}
119
120	if( islower( class ) ) class = toupper(class);
121
122	if( Remote_support_DYN ) uppercase( Remote_support_DYN );
123	if( islower(class) ) class = toupper(class);
124	if( safestrchr( Remote_support_DYN, class ) == 0 ){
125		char *m = "unknown";
126		switch( class ){
127		case 'R': m = "lpr"; break;
128		case 'M': m = "lprm"; break;
129		case 'Q': m = "lpq"; break;
130		case 'V': m = "lpq -v"; break;
131		case 'C': m = "lpc"; break;
132		}
133		DEBUG1("Send_request: no remote support for %c - '%s' operation", class, m );
134		if( !Is_server ){
135			SNPRINTF(errormsg,sizeof(errormsg))
136			_("no network support for '%s' operation"), m);
137		}
138		status = 0;
139		goto error;
140	}
141
142	cmd = safestrdup2(" ",RemotePrinter_DYN,__FILE__,__LINE__);
143	cmd[0] = format;
144	if( options ){
145		for( ; options && *options; ++options ){
146			cmd = safeextend3(cmd," ",*options, __FILE__,__LINE__ );
147		}
148	}
149	DEBUG1("Send_request: command '%s'", cmd );
150	cmd = safeextend2(cmd,"\n", __FILE__,__LINE__ );
151	errno = 0;
152
153#ifdef ORIGINAL_DEBUG//JY@1020
154	sock = Link_open_list( RemoteHost_DYN,
155		&real_host, connnect_timeout, 0, Unix_socket_path_DYN );
156#endif
157	err = errno;
158	if( sock < 0 ){
159		char *msg = "";
160		SNPRINTF( errormsg, sizeof(errormsg)-2)
161			"cannot open connection - %s",
162			err?Errormsg(err):"bad or missing hostname" );
163		if( !Is_server ){
164			int v = safestrlen(errormsg);
165			SNPRINTF( errormsg+v, sizeof(errormsg)-v)
166			"\nMake sure the remote host supports the LPD protocol");
167			if( geteuid() && getuid() ){
168				v = safestrlen(errormsg);
169				SNPRINTF( errormsg+v, sizeof(errormsg)-v)
170				"\nand accepts connections from this host and from non-privileged (>1023) ports");
171			}
172		}
173		goto error;
174	}
175
176	DEBUG1("Send_request: socket %d, real host '%s'", sock, real_host );
177	save_host = safestrdup(RemoteHost_DYN,__FILE__,__LINE__);
178	Set_DYN(&RemoteHost_DYN, real_host );
179	if( real_host ) free( real_host ); real_host = 0;
180
181	if( security && security->client_connect ){
182		DEBUG1("Send_request: security '%s', using connect", security->name );
183		status = security->client_connect( 0, &sock,
184				transfer_timeout,
185				errormsg, sizeof(errormsg),
186				security, &info );
187		DEBUG1("Send_request: connect status %d, error  '%s'", status, errormsg );
188		if( status ) goto error;
189	}
190	/* now send the command line */
191	if( security && security->client_send ){
192#ifdef ORIGINAL_DEBUG//JY@1020
193		status = Send_auth_transfer( &sock, transfer_timeout, 0, 0,
194			errormsg, sizeof(errormsg), cmd, security, &info );
195#endif
196	} else {
197		status = Link_send( RemoteHost_DYN, &sock, transfer_timeout,
198			cmd, safestrlen(cmd), 0 );
199		if( status ){
200			SNPRINTF(errormsg,sizeof(errormsg))"%s",Link_err_str(status));
201			close(sock); sock = -1;
202			goto error;
203		}
204	}
205
206 error:
207	if( status || errormsg[0] ){
208		char line[SMALLBUFFER];
209		SNPRINTF( line,sizeof(line)) "Printer '%s@%s' - ",
210			RemotePrinter_DYN, RemoteHost_DYN );
211		if( Write_fd_str( output, line ) < 0
212			|| Write_fd_str( output, errormsg ) < 0
213			|| Write_fd_str( output, "\n" ) < 0 ) cleanup(0);
214	}
215	if( save_host ){
216		Set_DYN(&RemoteHost_DYN,save_host);
217		free(save_host); save_host = 0;
218	}
219	if( cmd ) free(cmd); cmd = 0;
220	Free_line_list(&info);
221	return( sock );
222}
223