2000-09-25 21:05:18 +00:00
/*
2002-01-30 06:08:46 +00:00
* Unix SMB / CIFS implementation .
2000-09-25 21:05:18 +00:00
* RPC Pipe client / server routines
* Copyright ( C ) Andrew Tridgell 1992 - 2000 ,
* Copyright ( C ) Jean Francois Micouleau 1998 - 2000 ,
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
2002-03-15 08:14:10 +00:00
#if 0
2000-09-25 21:05:18 +00:00
# include "rpc_parse.h"
# include "nterr.h"
2002-03-15 08:14:10 +00:00
# endif
2000-09-25 21:05:18 +00:00
extern pstring global_myname ;
2002-03-15 08:14:10 +00:00
struct msg_info_table {
uint32 msg ;
uint32 field ;
char * name ;
void ( * construct_fn ) ( int snum , SPOOL_NOTIFY_INFO_DATA * data ,
print_queue_struct * queue ,
NT_PRINTER_INFO_LEVEL * printer , TALLOC_CTX * mem_ctx ) ;
} ;
struct msg_info_table msg_table [ ] = {
{ PRINTER_MESSAGE_DRIVER , PRINTER_NOTIFY_DRIVER_NAME , " PRINTER_MESSAGE_DRIVER " , spoolss_notify_driver_name } ,
{ PRINTER_MESSAGE_ATTRIBUTES , PRINTER_NOTIFY_ATTRIBUTES , " PRINTER_MESSAGE_ATTRIBUTES " , spoolss_notify_attributes } ,
{ PRINTER_MESSAGE_COMMENT , PRINTER_NOTIFY_COMMENT , " PRINTER_MESSAGE_COMMENT " , spoolss_notify_comment } ,
{ PRINTER_MESSAGE_LOCATION , PRINTER_NOTIFY_LOCATION , " PRINTER_MESSAGE_LOCATION " , spoolss_notify_location } ,
{ PRINTER_MESSAGE_PRINTERNAME , PRINTER_NOTIFY_PRINTER_NAME , " PRINTER_MESSAGE_PRINTERNAME " , spoolss_notify_printer_name } ,
{ PRINTER_MESSAGE_SHARENAME , PRINTER_NOTIFY_SHARE_NAME , " PRINTER_MESSAGE_SHARENAME " , spoolss_notify_share_name } ,
{ PRINTER_MESSAGE_PORT , PRINTER_NOTIFY_PORT_NAME , " PRINTER_MESSAGE_PORT " , spoolss_notify_port_name } ,
{ PRINTER_MESSAGE_CJOBS , PRINTER_NOTIFY_CJOBS , " PRINTER_MESSAGE_CJOBS " , spoolss_notify_cjobs } ,
{ PRINTER_MESSAGE_SEPFILE , PRINTER_NOTIFY_SEPFILE , " PRINTER_MESSAGE_SEPFILE " , spoolss_notify_sepfile } ,
{ PRINTER_MESSAGE_PARAMS , PRINTER_NOTIFY_PARAMETERS , " PRINTER_MESSAGE_PARAMETERS " , spoolss_notify_parameters } ,
{ PRINTER_MESSAGE_DATATYPE , PRINTER_NOTIFY_DATATYPE , " PRINTER_MESSAGE_DATATYPE " , spoolss_notify_datatype } ,
{ PRINTER_MESSAGE_NULL , 0x0 , " " , NULL } ,
} ;
2000-09-25 21:05:18 +00:00
/*********************************************************
Disconnect from the client machine .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL spoolss_disconnect_from_client ( struct cli_state * cli )
{
cli_nt_session_close ( cli ) ;
cli_ulogoff ( cli ) ;
cli_shutdown ( cli ) ;
return True ;
}
/*********************************************************
Connect to the client machine .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL spoolss_connect_to_client ( struct cli_state * cli , char * remote_machine )
{
ZERO_STRUCTP ( cli ) ;
2001-06-14 00:08:42 +00:00
if ( cli_initialise ( cli ) = = NULL ) {
2000-09-25 21:05:18 +00:00
DEBUG ( 0 , ( " connect_to_client: unable to initialize client connection. \n " ) ) ;
return False ;
}
if ( ! resolve_name ( remote_machine , & cli - > dest_ip , 0x20 ) ) {
DEBUG ( 0 , ( " connect_to_client: Can't resolve address for %s \n " , remote_machine ) ) ;
cli_shutdown ( cli ) ;
return False ;
}
if ( ismyip ( cli - > dest_ip ) ) {
DEBUG ( 0 , ( " connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves. \n " , remote_machine ) ) ;
cli_shutdown ( cli ) ;
return False ;
}
if ( ! cli_connect ( cli , remote_machine , & cli - > dest_ip ) ) {
DEBUG ( 0 , ( " connect_to_client: unable to connect to SMB server on machine %s. Error was : %s. \n " , remote_machine , cli_errstr ( cli ) ) ) ;
cli_shutdown ( cli ) ;
return False ;
}
if ( ! attempt_netbios_session_request ( cli , global_myname , remote_machine , & cli - > dest_ip ) ) {
2002-02-13 16:44:49 +00:00
DEBUG ( 0 , ( " connect_to_client: machine %s rejected the NetBIOS session request. \n " ,
remote_machine ) ) ;
2000-09-25 21:05:18 +00:00
return False ;
}
cli - > protocol = PROTOCOL_NT1 ;
if ( ! cli_negprot ( cli ) ) {
DEBUG ( 0 , ( " connect_to_client: machine %s rejected the negotiate protocol. Error was : %s. \n " , remote_machine , cli_errstr ( cli ) ) ) ;
cli_shutdown ( cli ) ;
return False ;
}
if ( cli - > protocol ! = PROTOCOL_NT1 ) {
DEBUG ( 0 , ( " connect_to_client: machine %s didn't negotiate NT protocol. \n " , remote_machine ) ) ;
cli_shutdown ( cli ) ;
return False ;
}
/*
* Do an anonymous session setup .
*/
if ( ! cli_session_setup ( cli , " " , " " , 0 , " " , 0 , " " ) ) {
DEBUG ( 0 , ( " connect_to_client: machine %s rejected the session setup. Error was : %s. \n " , remote_machine , cli_errstr ( cli ) ) ) ;
cli_shutdown ( cli ) ;
return False ;
}
if ( ! ( cli - > sec_mode & 1 ) ) {
DEBUG ( 0 , ( " connect_to_client: machine %s isn't in user level security mode \n " , remote_machine ) ) ;
cli_shutdown ( cli ) ;
return False ;
}
if ( ! cli_send_tconX ( cli , " IPC$ " , " IPC " , " " , 1 ) ) {
DEBUG ( 0 , ( " connect_to_client: machine %s rejected the tconX on the IPC$ share. Error was : %s. \n " , remote_machine , cli_errstr ( cli ) ) ) ;
cli_shutdown ( cli ) ;
return False ;
}
/*
* Ok - we have an anonymous connection to the IPC $ share .
* Now start the NT Domain stuff : - ) .
*/
if ( cli_nt_session_open ( cli , PIPE_SPOOLSS ) = = False ) {
DEBUG ( 0 , ( " connect_to_client: unable to open the domain client session to machine %s. Error was : %s. \n " , remote_machine , cli_errstr ( cli ) ) ) ;
cli_nt_session_close ( cli ) ;
cli_ulogoff ( cli ) ;
cli_shutdown ( cli ) ;
return False ;
}
return True ;
}
2002-03-15 08:14:10 +00:00
/*
* SPOOLSS Client RPC ' s used by servers as the notification
* back channel
*/
2000-09-25 21:05:18 +00:00
/***************************************************************************
do a reply open printer
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-04-11 01:50:18 +00:00
WERROR cli_spoolss_reply_open_printer ( struct cli_state * cli , TALLOC_CTX * mem_ctx ,
2002-03-15 08:14:10 +00:00
char * printer , uint32 localprinter , uint32 type ,
POLICY_HND * handle )
2000-09-25 21:05:18 +00:00
{
2002-04-11 01:50:18 +00:00
WERROR result = W_ERROR ( ERRgeneral ) ;
2002-03-15 08:14:10 +00:00
2000-09-25 21:05:18 +00:00
prs_struct rbuf ;
prs_struct buf ;
SPOOL_Q_REPLYOPENPRINTER q_s ;
SPOOL_R_REPLYOPENPRINTER r_s ;
2002-03-15 08:14:10 +00:00
prs_init ( & buf , 1024 , mem_ctx , MARSHALL ) ;
prs_init ( & rbuf , 0 , mem_ctx , UNMARSHALL ) ;
2000-09-25 21:05:18 +00:00
/* create and send a MSRPC command with api SPOOLSS_REPLYOPENPRINTER */
2002-03-15 08:14:10 +00:00
2000-09-25 21:05:18 +00:00
/* store the parameters */
make_spoolss_q_replyopenprinter ( & q_s , printer , localprinter , type ) ;
/* turn parameters into data stream */
if ( ! spoolss_io_q_replyopenprinter ( " " , & q_s , & buf , 0 ) ) {
2002-03-15 08:14:10 +00:00
DEBUG ( 0 , ( " cli_spoolss_reply_open_printer: Error : failed to marshall SPOOL_Q_REPLYOPENPRINTER struct. \n " ) ) ;
goto done ;
2000-09-25 21:05:18 +00:00
}
/* send the data on \PIPE\ */
2002-04-11 01:50:18 +00:00
if ( ! rpc_api_pipe_req ( cli , SPOOLSS_REPLYOPENPRINTER , & buf , & rbuf ) )
2002-03-15 08:14:10 +00:00
goto done ;
2000-09-25 21:05:18 +00:00
/* turn data stream into parameters*/
if ( ! spoolss_io_r_replyopenprinter ( " " , & r_s , & rbuf , 0 ) ) {
2002-03-15 08:14:10 +00:00
DEBUG ( 0 , ( " cli_spoolss_reply_open_printer: Error : failed to unmarshall SPOOL_R_REPLYOPENPRINTER struct. \n " ) ) ;
goto done ;
2000-09-25 21:05:18 +00:00
}
memcpy ( handle , & r_s . handle , sizeof ( r_s . handle ) ) ;
2002-04-11 01:50:18 +00:00
result = r_s . status ;
2000-09-25 21:05:18 +00:00
2002-03-15 08:14:10 +00:00
done :
prs_mem_free ( & buf ) ;
prs_mem_free ( & rbuf ) ;
return result ;
2000-09-25 21:05:18 +00:00
}
/***************************************************************************
do a reply open printer
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-04-11 01:50:18 +00:00
WERROR cli_spoolss_reply_close_printer ( struct cli_state * cli , TALLOC_CTX * mem_ctx ,
2002-03-15 08:14:10 +00:00
POLICY_HND * handle )
2000-09-25 21:05:18 +00:00
{
2002-04-11 01:50:18 +00:00
WERROR result = W_ERROR ( ERRgeneral ) ;
2000-09-25 21:05:18 +00:00
prs_struct rbuf ;
prs_struct buf ;
2002-03-15 08:14:10 +00:00
SPOOL_Q_REPLYCLOSEPRINTER q_s ;
SPOOL_R_REPLYCLOSEPRINTER r_s ;
2000-09-25 21:05:18 +00:00
2001-03-09 23:48:58 +00:00
prs_init ( & buf , 1024 , cli - > mem_ctx , MARSHALL ) ;
prs_init ( & rbuf , 0 , cli - > mem_ctx , UNMARSHALL ) ;
2000-09-25 21:05:18 +00:00
/* create and send a MSRPC command with api */
2002-03-15 08:14:10 +00:00
2000-09-25 21:05:18 +00:00
/* store the parameters */
2002-03-15 08:14:10 +00:00
make_spoolss_q_reply_closeprinter ( & q_s , handle ) ;
2000-09-25 21:05:18 +00:00
/* turn parameters into data stream */
2002-03-15 08:14:10 +00:00
if ( ! spoolss_io_q_replycloseprinter ( " " , & q_s , & buf , 0 ) ) {
DEBUG ( 0 , ( " cli_spoolss_reply_close_printer: Error : failed to marshall SPOOL_Q_REPLY_CLOSEPRINTER struct. \n " ) ) ;
goto done ;
2000-09-25 21:05:18 +00:00
}
/* send the data on \PIPE\ */
2002-04-11 01:50:18 +00:00
if ( ! rpc_api_pipe_req ( cli , SPOOLSS_REPLYCLOSEPRINTER , & buf , & rbuf ) )
2002-03-15 08:14:10 +00:00
goto done ;
2000-09-25 21:05:18 +00:00
/* turn data stream into parameters*/
2002-03-15 08:14:10 +00:00
if ( ! spoolss_io_r_replycloseprinter ( " " , & r_s , & rbuf , 0 ) ) {
DEBUG ( 0 , ( " cli_spoolss_reply_close_printer: Error : failed to marshall SPOOL_R_REPLY_CLOSEPRINTER struct. \n " ) ) ;
goto done ;
}
2002-04-11 01:50:18 +00:00
result = r_s . status ;
2002-03-15 08:14:10 +00:00
done :
prs_mem_free ( & buf ) ;
2000-09-25 21:05:18 +00:00
prs_mem_free ( & rbuf ) ;
2002-03-15 08:14:10 +00:00
return result ;
}
/*********************************************************************
This SPOOLSS_ROUTERREPLYPRINTER function is used to send a change
notification event when the registration * * did not * * use
SPOOL_NOTIFY_OPTION_TYPE structure to specify the events to monitor .
Also see cli_spolss_reply_rrpcn ( )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-04-11 01:50:18 +00:00
WERROR cli_spoolss_routerreplyprinter ( struct cli_state * cli , TALLOC_CTX * mem_ctx ,
2002-03-15 08:14:10 +00:00
POLICY_HND * pol , uint32 condition , uint32 changd_id )
{
prs_struct qbuf , rbuf ;
SPOOL_Q_ROUTERREPLYPRINTER q ;
SPOOL_R_ROUTERREPLYPRINTER r ;
2002-04-11 01:50:18 +00:00
WERROR result = W_ERROR ( ERRgeneral ) ;
2002-03-15 08:14:10 +00:00
ZERO_STRUCT ( q ) ;
ZERO_STRUCT ( r ) ;
/* Initialise input parameters */
prs_init ( & qbuf , MAX_PDU_FRAG_LEN , mem_ctx , MARSHALL ) ;
prs_init ( & rbuf , 0 , mem_ctx , UNMARSHALL ) ;
/* write the request */
make_spoolss_q_routerreplyprinter ( & q , pol , condition , changd_id ) ;
/* Marshall data and send request */
if ( ! spoolss_io_q_routerreplyprinter ( " " , & q , & qbuf , 0 ) ) {
DEBUG ( 0 , ( " cli_spoolss_routerreplyprinter: Unable to marshall SPOOL_Q_ROUTERREPLYPRINTER! \n " ) ) ;
goto done ;
2000-09-25 21:05:18 +00:00
}
2002-03-15 08:14:10 +00:00
2002-04-11 01:50:18 +00:00
if ( ! rpc_api_pipe_req ( cli , SPOOLSS_ROUTERREPLYPRINTER , & qbuf , & rbuf ) )
2002-03-15 08:14:10 +00:00
goto done ;
/* Unmarshall response */
if ( ! spoolss_io_r_routerreplyprinter ( " " , & r , & rbuf , 0 ) ) {
DEBUG ( 0 , ( " cli_spoolss_routerreplyprinter: Unable to unmarshall SPOOL_R_ROUTERREPLYPRINTER! \n " ) ) ;
goto done ;
}
/* Return output parameters */
2002-04-11 01:50:18 +00:00
result = r . status ;
2000-09-25 21:05:18 +00:00
2002-03-15 08:14:10 +00:00
done :
prs_mem_free ( & qbuf ) ;
prs_mem_free ( & rbuf ) ;
2000-09-25 21:05:18 +00:00
2002-03-15 08:14:10 +00:00
return result ;
}
2000-09-25 21:05:18 +00:00
2002-03-15 08:14:10 +00:00
/**********************************************************************************
Build the SPOOL_NOTIFY_INFO_DATA entries based upon the flags which have been set
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int build_notify_data ( TALLOC_CTX * ctx , NT_PRINTER_INFO_LEVEL * printer , uint32 flags ,
SPOOL_NOTIFY_INFO_DATA * * notify_data )
{
SPOOL_NOTIFY_INFO_DATA * data ;
uint32 idx = 0 ;
int i = 0 ;
while ( ( msg_table [ i ] . msg ! = PRINTER_MESSAGE_NULL ) & & flags )
{
if ( flags & msg_table [ i ] . msg )
{
DEBUG ( 10 , ( " build_notify_data: %s set on [%s][%d] \n " , msg_table [ i ] . name ,
printer - > info_2 - > printername , idx ) ) ;
if ( ( data = Realloc ( * notify_data , ( idx + 1 ) * sizeof ( SPOOL_NOTIFY_INFO_DATA ) ) ) = = NULL ) {
DEBUG ( 0 , ( " build_notify_data: Realloc() failed with size [%d]! \n " ,
( idx + 1 ) * sizeof ( SPOOL_NOTIFY_INFO_DATA ) ) ) ;
return - 1 ;
}
* notify_data = data ;
/* clear memory */
memset ( * notify_data + idx , 0x0 , sizeof ( SPOOL_NOTIFY_INFO_DATA ) ) ;
/*
* ' id ' ( last param here ) is undefined when type = = PRINTER_NOTIFY_TYPE
* See PRINTER_NOTIFY_INFO_DATA entries in MSDN
* - - jerry
*/
construct_info_data ( * notify_data + idx , PRINTER_NOTIFY_TYPE , msg_table [ i ] . field , 0x00 ) ;
msg_table [ i ] . construct_fn ( - 1 , * notify_data + idx , NULL , printer , ctx ) ;
idx + + ;
}
i + + ;
}
return idx ;
2000-09-25 21:05:18 +00:00
}
2002-03-15 08:14:10 +00:00
/*********************************************************************
This SPOOLSS_ROUTERREPLYPRINTER function is used to send a change
notification event when the registration * * did * * use
SPOOL_NOTIFY_OPTION_TYPE structure to specify the events to monitor
Also see cli_spoolss_routereplyprinter ( )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-09-25 21:05:18 +00:00
2002-04-11 01:50:18 +00:00
WERROR cli_spoolss_reply_rrpcn ( struct cli_state * cli , TALLOC_CTX * mem_ctx ,
2002-03-15 08:14:10 +00:00
POLICY_HND * handle , PRINTER_MESSAGE_INFO * info ,
NT_PRINTER_INFO_LEVEL * printer )
2000-09-25 21:05:18 +00:00
{
prs_struct rbuf ;
prs_struct buf ;
2002-03-15 08:14:10 +00:00
SPOOL_NOTIFY_INFO notify_info ;
SPOOL_NOTIFY_INFO_DATA * notify_data = NULL ;
uint32 data_len ;
2000-09-25 21:05:18 +00:00
2002-04-11 01:50:18 +00:00
WERROR result = W_ERROR ( ERRgeneral ) ;
2002-03-15 08:14:10 +00:00
SPOOL_Q_REPLY_RRPCN q_s ;
SPOOL_R_REPLY_RRPCN r_s ;
if ( ! info ) {
DEBUG ( 5 , ( " cli_spoolss_reply_rrpcn: NULL printer message info pointer! \n " ) ) ;
2002-04-11 01:50:18 +00:00
goto done ;
2002-03-15 08:14:10 +00:00
}
prs_init ( & buf , 1024 , mem_ctx , MARSHALL ) ;
prs_init ( & rbuf , 0 , mem_ctx , UNMARSHALL ) ;
ZERO_STRUCT ( notify_info ) ;
2000-09-25 21:05:18 +00:00
/*
2002-03-15 08:14:10 +00:00
* See comments in _spoolss_setprinter ( ) about PRINTER_CHANGE_XXX
* events . - - jerry
2000-09-25 21:05:18 +00:00
*/
2002-03-15 08:14:10 +00:00
DEBUG ( 10 , ( " cli_spoolss_reply_rrpcn: PRINTER_MESSAGE flags = 0x%8x \n " , info - > flags ) ) ;
data_len = build_notify_data ( mem_ctx , printer , info - > flags , & notify_data ) ;
if ( info - > flags & & ( data_len = = - 1 ) ) {
DEBUG ( 0 , ( " cli_spoolss_reply_rrpcn: Failed to build SPOOL_NOTIFY_INFO_DATA [flags == 0x%x] for printer [%s] \n " ,
info - > flags , info - > printer_name ) ) ;
2002-04-11 01:50:18 +00:00
result = WERR_NOMEM ;
2002-03-15 08:14:10 +00:00
goto done ;
}
notify_info . version = 0x2 ;
notify_info . flags = 0x00020000 ; /* ?? */
notify_info . count = data_len ;
notify_info . data = notify_data ;
/* create and send a MSRPC command with api */
2000-09-25 21:05:18 +00:00
/* store the parameters */
2002-03-15 08:14:10 +00:00
make_spoolss_q_reply_rrpcn ( & q_s , handle , info - > low , info - > high , & notify_info ) ;
2000-09-25 21:05:18 +00:00
/* turn parameters into data stream */
2002-03-15 08:14:10 +00:00
if ( ! spoolss_io_q_reply_rrpcn ( " " , & q_s , & buf , 0 ) ) {
DEBUG ( 0 , ( " cli_spoolss_reply_rrpcn: Error : failed to marshall SPOOL_Q_REPLY_RRPCN struct. \n " ) ) ;
goto done ;
2000-09-25 21:05:18 +00:00
}
/* send the data on \PIPE\ */
2002-04-11 01:50:18 +00:00
if ( ! rpc_api_pipe_req ( cli , SPOOLSS_RRPCN , & buf , & rbuf ) )
2002-03-15 08:14:10 +00:00
goto done ;
2000-09-25 21:05:18 +00:00
/* turn data stream into parameters*/
2002-03-15 08:14:10 +00:00
if ( ! spoolss_io_r_reply_rrpcn ( " " , & r_s , & rbuf , 0 ) ) {
DEBUG ( 0 , ( " cli_spoolss_reply_rrpcn: Error : failed to unmarshall SPOOL_R_REPLY_RRPCN struct. \n " ) ) ;
goto done ;
}
if ( r_s . unknown0 = = 0x00080000 ) {
DEBUG ( 8 , ( " cli_spoolss_reply_rrpcn: I think the spooler resonded that the notification was ignored. \n " ) ) ;
2000-09-25 21:05:18 +00:00
}
2002-04-11 01:50:18 +00:00
result = r_s . status ;
2000-09-25 21:05:18 +00:00
2002-03-15 08:14:10 +00:00
done :
prs_mem_free ( & buf ) ;
prs_mem_free ( & rbuf ) ;
/*
* The memory allocated in this array is talloc ' d so we only need
* free the array here . JRA .
*/
SAFE_FREE ( notify_data ) ;
2000-09-25 21:05:18 +00:00
2002-03-15 08:14:10 +00:00
return result ;
2000-09-25 21:05:18 +00:00
}
2002-03-15 08:14:10 +00:00