/******************************************************************************
Function: globus_l_gass_server_ez_put_callback()

Description: 

Parameters: 

Returns: 
******************************************************************************/
static void
globus_l_gass_server_ez_put_callback(
				    void *arg,
				    globus_gass_transfer_request_t request,
				    globus_byte_t *     bytes,
				    globus_size_t       len,
				    globus_bool_t       last_data)
{
    int fd;

    fd = (int) arg;

    globus_libc_write(fd, bytes, len);
    if(!last_data)
    {
        globus_gass_transfer_receive_bytes(request,
                                           bytes,
                                           1024,
                                           1,
                                           globus_l_gass_server_ez_put_callback,
                                           arg);
    return ;
    }

    if((fd!=fileno(stdout)) && (fd!=fileno(stderr)))
    {
        close(fd);
    }
    globus_free(bytes);
    globus_gass_transfer_request_destroy(request);
    return ;

} /* globus_l_gass_server_ez_put_callback() */
static
void
test_l_data_callback(
    void *                              arg,
    globus_gass_transfer_request_t      request,
    globus_byte_t *                     bytes,
    globus_size_t                       length,
    globus_bool_t                       last_data)
{
    test_monitor_t                      *monitor = arg;

    if (last_data)
    {
        globus_gass_transfer_request_destroy(request);
        return;
    }

    globus_gass_transfer_receive_bytes(
        request,
        bytes,
        sizeof(monitor->old_output),
        1,
        test_l_data_callback,
        monitor);
}
static
void
test_l_new_accept_callback(
    void *                              callback_arg,
    globus_gass_transfer_request_t      request)
{
    test_monitor_t                      *monitor = callback_arg;
    int                                 rc;

    globus_mutex_lock(&monitor->mutex);
    monitor->new_request = request;
    globus_mutex_unlock(&monitor->mutex);


    rc = globus_gass_transfer_authorize(
        request,
        GLOBUS_GASS_TRANSFER_LENGTH_UNKNOWN);

    rc = globus_gass_transfer_receive_bytes(
        request,
        monitor->new_output,
        sizeof(monitor->new_output),
        1,
        test_l_data_callback,
        monitor);
    rc = globus_gass_transfer_register_listen(
            monitor->new_listener,
            test_l_new_listener_callback,
            monitor);
}
static void
globus_l_gass_server_ez_register_accept_callback(
					void * listener,
					globus_gass_transfer_request_t request 
					)
{
    int rc;
    char * subjectname;
    char * path=GLOBUS_NULL;
    char * url;
    globus_url_t parsed_url;
    globus_l_gass_server_ez_t * s;
    globus_gass_server_ez_request_t *r;
    struct stat	statstruct;
    globus_byte_t * buf;
    int amt;
    int flags=0;

    
    subjectname=globus_gass_transfer_request_get_subject(request);

    /* lookup our options */
    s=(globus_l_gass_server_ez_t *)globus_hashtable_lookup(
                                &globus_l_gass_server_ez_listeners,
                                listener);

    /* Check for valid URL */
    url=globus_gass_transfer_request_get_url(request);
    rc = globus_url_parse(url, &parsed_url);
    if(rc != GLOBUS_SUCCESS ||
       parsed_url.url_path == GLOBUS_NULL || strlen(parsed_url.url_path) == 0U)
    {
        globus_gass_transfer_deny(request, 404, "File Not Found");
        globus_gass_transfer_request_destroy(request);
        if (rc == GLOBUS_SUCCESS)
            globus_url_destroy(&parsed_url);
	goto reregister_nourl;
    }

    if(globus_gass_transfer_request_get_type(request) ==
       GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND)
    {
        flags = O_CREAT | O_WRONLY | O_APPEND;
    }
    else if(globus_gass_transfer_request_get_type(request) ==
            GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT)
    {
        flags = O_CREAT | O_WRONLY | O_TRUNC;
    }
    switch(globus_gass_transfer_request_get_type(request))
        {
          case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND:
          case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT:

	    /* Check to see if this is a request we are allowed to handle */

            if(((s->options & GLOBUS_GASS_SERVER_EZ_WRITE_ENABLE) == 0UL) &&
              ((s->options & GLOBUS_GASS_SERVER_EZ_STDOUT_ENABLE) == 0UL) &&
              ((s->options & GLOBUS_GASS_SERVER_EZ_STDERR_ENABLE) == 0UL) &&
              ((s->options & GLOBUS_GASS_SERVER_EZ_CLIENT_SHUTDOWN_ENABLE) ==
									 0UL))
    	    {
		goto deny;
            }
	
	    /* Expand ~ and ~user prefix if enaabled in options */
    	    rc = globus_l_gass_server_ez_tilde_expand(s->options,
                                              parsed_url.url_path,
                                              &path);
              
            if(strncmp(path, "/dev/saga", 9) == 0 && 
                    (s->options & GLOBUS_GASS_SERVER_EZ_STDOUT_ENABLE))
            {
                rc = s->fd; // the pipe handle!
            
                goto authorize;
            }
            else if(strncmp(path, "/dev/saga/", 9) == 0)
            {
                goto deny;
            }
                
    	    else if(strcmp(path, "/dev/globus_gass_client_shutdown") == 0)
    	    {
        	if(s->options & GLOBUS_GASS_SERVER_EZ_CLIENT_SHUTDOWN_ENABLE &&
           	   s->callback != GLOBUS_NULL)
        	{
            	    s->callback();
        	}

		goto deny;
    	    }
#ifdef TARGET_ARCH_WIN32
			// The call to open() in Windows defaults to text mode, so
			// we to override it.
			flags |= O_BINARY;
#endif
            rc = globus_libc_open(path, flags, 0600);

            if(rc < 0)
            {
                goto deny;
            }
	
	    authorize:
            globus_gass_transfer_authorize(request, 0);
	    if(s->options & GLOBUS_GASS_SERVER_EZ_LINE_BUFFER)
	    {
	        r=(globus_gass_server_ez_request_t *)globus_malloc(
				sizeof(globus_gass_server_ez_request_t));
		r->fd=rc;
		r->line_buffer=globus_malloc(80);
                r->line_buffer_used= 0UL;
        	r->line_buffer_length = 80UL;
        	r->linebuffer = GLOBUS_TRUE;

		globus_gass_transfer_receive_bytes(request,
						globus_malloc(1024),
						1024,
						1,
						globus_gass_server_ez_put_memory_done,
						r);
	    }
	    else
	    {
                globus_gass_transfer_receive_bytes(request,
                                               globus_malloc(1024),
                                               1024,
                                               1,
                                               globus_l_gass_server_ez_put_callback,
                                               (void *) rc);
	    }
            break;

          case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET:
            flags = O_RDONLY;

			/* Expand ~ and ~user prefix if enaabled in options */
            rc = globus_l_gass_server_ez_tilde_expand(s->options,
                                              parsed_url.url_path,
                                              &path);

   	    if((s->options & GLOBUS_GASS_SERVER_EZ_READ_ENABLE) == 0UL)
    	    {
		goto deny;
    	    }
	   
	    if(stat(path, &statstruct)==0)
	    {
#ifdef TARGET_ARCH_WIN32
				// The call to open() in Windows defaults to text mode, 
				// so we to override it.
				flags |= O_BINARY;
#endif
                rc = globus_libc_open(path, flags, 0600);
		fstat(rc, &statstruct);
	    }
	    else
	    {
		globus_gass_transfer_deny(request, 404, "File Not Found");
		globus_gass_transfer_request_destroy(request);
		goto reregister;
	    }

            buf = globus_malloc(1024);
            amt = read(rc, buf, 1024);
            if(amt == -1)
            {
                globus_free(buf);
                goto deny;
            }
            globus_gass_transfer_authorize(request,
                                           statstruct.st_size);

            globus_gass_transfer_send_bytes(request,
                                            buf,
                                            amt,
                                            GLOBUS_FALSE,
                                            globus_l_gass_server_ez_get_callback,
                                            (void *) rc);
	  break;
	default:
	deny:
	  globus_gass_transfer_deny(request, 400, "Bad Request");
	  globus_gass_transfer_request_destroy(request);

	}

  reregister:
    globus_url_destroy(&parsed_url);

  reregister_nourl:
    globus_gass_transfer_register_listen(
				(globus_gass_transfer_listener_t) listener,
				globus_l_gass_server_ez_listen_callback,
				s->reqattr);

    if (path != GLOBUS_NULL) globus_free(path);

} /*globus_l_gass_server_ez_register_accept_callback*/
/******************************************************************************
Function: globus_l_gass_server_ez_put_memory_done()

Description: 

Parameters: 

Returns: 
******************************************************************************/
static void
globus_gass_server_ez_put_memory_done(void * arg,
                                       globus_gass_transfer_request_t request,
                                       globus_byte_t buffer[],
                                       globus_size_t receive_length,
				       globus_bool_t last_data)
{
    globus_gass_server_ez_request_t *r=GLOBUS_NULL;
    globus_size_t max_length;
    unsigned long lastnl, x;
    int status;
    const int buffer_length=1024;
    
    /* This callback handles line-buffered put requests. 
     */    

    r = (globus_gass_server_ez_request_t *)arg;

    status=globus_gass_transfer_request_get_status(request);
    lastnl = 0UL;


    /* find last \n in the buffer, since we are line-buffering */
    max_length=receive_length;
    for(x = max_length; x > 0UL; x--)
    {
	if(buffer[x-1] == '\n')
	{
	    lastnl = x;
	    break;
	}
    }
    
    if(status == GLOBUS_GASS_TRANSFER_REQUEST_PENDING && !last_data)
    {
	/* data arrived, and more will be available, so write up until
	 * the last \n we've received and save the rest
	 */
	if(r->line_buffer != GLOBUS_NULL &&
	   lastnl != 0UL &&
	    r->line_buffer_used != 0UL)
	{
	    globus_l_gass_server_ez_write(r->fd,
				r->line_buffer,
				r->line_buffer_used);
	    r->line_buffer_used = 0UL;
	}
	
	if(lastnl != 0UL)
	{
	    globus_l_gass_server_ez_write(r->fd,
				buffer,
				lastnl);
	}
	else
	{
	    lastnl = 0;
	}
	if(r->line_buffer_used + receive_length - lastnl >
	   r->line_buffer_length)
	{
	    r->line_buffer = (globus_byte_t *)
		realloc(r->line_buffer,
			r->line_buffer_used + receive_length - lastnl);
	    r->line_buffer_length = r->line_buffer_used + receive_length - lastnl;
	    memcpy(r->line_buffer + r->line_buffer_used,
		   buffer + lastnl,
		   receive_length - lastnl);
	    r->line_buffer_used += receive_length - lastnl;
	}
	else
	{
	    memcpy(r->line_buffer + r->line_buffer_used,
		   buffer + lastnl,
		   receive_length - lastnl);
	    r->line_buffer_used += receive_length - lastnl;
	}
	
	globus_gass_transfer_receive_bytes(request,
				  	   buffer,
					   buffer_length,
					   1UL,
					   globus_gass_server_ez_put_memory_done,
					   arg);
					
    }
    else
    {
	
	if(r->line_buffer != GLOBUS_NULL &&
	   r->line_buffer_used != 0UL)
	{
	    globus_l_gass_server_ez_write(r->fd,
				r->line_buffer,
				r->line_buffer_used);
	}
	if(receive_length != 0UL)
	{
	    globus_l_gass_server_ez_write(r->fd,
				buffer,
				receive_length);
	}

	    
	if(r->fd!=fileno(stdout) && r->fd!=fileno(stderr))
	{
    if(-1 == close(r->fd))
      printf("close error(fd: %d): %s\n", r->fd, strerror( errno ));
	}

	if(buffer != GLOBUS_NULL)
	{
	    globus_free(buffer);
	}  

	globus_gass_transfer_request_destroy(request);
		

	if(r->linebuffer)
	{
	    globus_free(r->line_buffer);
	} 
	globus_free(r);
    }
} /* globus_l_gass_server_ez_put_memory_done() */