/*
 * This source file is Copyright 1995 by Evan Scott.
 * All rights reserved.
 * Permission is granted to distribute this file provided no
 * fees beyond distribution costs are levied.
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/alerts.h>

#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/dostags.h>

#include <proto/exec.h>
#include <proto/dos.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "evtypes.h"
#include "verify.h"
#include "tcp.h"

#include "site.h"
#include "ftp.h"
#include "split.h"

#include "globals.h"

boolean collapse(b8 *s)
{
	b8 *t, *u;
	
	t = s;
	u = s;
	
	/* . & .. are illegal */
	if (u[0] == '.') {
		if (u[1] == 0) return false;
		if (u[1] == '/') return false;
		if (u[1] == '.') {
			if (u[2] == 0) return false;
			if (u[2] == '/') return false;
		}
	}
	
	while (*u) {
		if (t == s && u[0] == '/') {
			// return false; // used to do this, but people didn't want it to error
			u++;	/* ignore it */
			continue;
		}
		
		if (u[0] == '/' && u[1] == '.') {
			if (u[2] == 0) return false;
			if (u[2] == '/') return false;
			if (u[2] == '.') {
				if (u[3] == 0) return false;
				if (u[3] == '/') return false;
			}
		}
		
		if (u[0] == '/' && u[1] == '/') {
			while (--t > s) {
				if (*t == '/') break;
			}
			u++;
			if (t == s) u++;
		} else {
			*t++ = *u++;
		}
	}
	
	if (t > s && t[-1] == '/') t[-1] = 0;	/* cull the trailing '/' */
	
	*t = 0;
	
	return true;
}

boolean split_data(lock *l, b8 *z, split *sd)
{
	b8 *s, *t;
	int len1, len2, len3;
	/* 
	 * sigh ... all that work to separate the libs to processes ... just
	 * given up and used the global DosBase here
	 */
	struct DevProc *dp;
	
	truth(z != nil);
	
	if (!l && z[0] == 0) {
		
		sd->port = local_port;
		sd->path = nil;
		
		sd->work = nil;

		return true;
	}
	
	s = (b8 *)allocate(z[0] + 1, V_cstr);
	if (!s) {
		sd->work = nil;
		return false;
	}
	
	if (z[0])
		memcpy(s, &z[1], z[0]);

	s[z[0]] = 0;
	
	sd->work = s;

	for (; ; s++) {	
		if (!*s) {
			z = sd->work;
			break;
		}
		
		if (*s == ':') {
			s++;
			dp = GetDeviceProc(sd->work, nil);
			if (!dp) {
				deallocate(sd->work, V_cstr);
				sd->work = nil;
				return false;
			}
			
			l = (lock *)(dp->dvp_Lock << 2);
			
			FreeDeviceProc(dp);
			
			z = s;
			
			break;
		}
	}
	
	/* have to look at lock to see where we are relative to */
	
	if (!l || (l->port == local_port && l->rfsl == ftphosts_lock)) {
		s = z;
		goto resolve;
	}
	
	verify(l, V_lock);
	
	if (l->port == local_port) {	/* most handlers might allow this, but there's no point */
		show_string("Split Fail B");
		deallocate(sd->work, V_cstr);
		sd->work = nil;
		return false;
	}
	
	/* construct a full path name so we can collapse it sensibly */
	
	if (l->fname[0] == 0) {
		len1 = strlen(l->port->mp_Node.ln_Name);
		len2 = strlen(z);
		
		s = (b8 *)allocate(len1 + len2 + 2, V_cstr);
		if (!s) {
			deallocate(sd->work, V_cstr);
			sd->work = nil;
			return false;
		}
		
		strcpy(s, l->port->mp_Node.ln_Name);
		
		if (sd->work[0]) {
			s[len1] = '/';
			strcpy(&s[len1 + 1], z);
		} else {
			s[len1] = 0;
		}
		
		deallocate(sd->work, V_cstr);
		sd->work = s;
	} else {
		len1 = strlen(l->port->mp_Node.ln_Name);
		len2 = strlen(l->fname);
		len3 = strlen(z);
		
		s = (b8 *)allocate(len1 + len2 + len3 + 3, V_cstr);
		if (!s) {
			deallocate(sd->work, V_cstr);
			sd->work = nil;
			return false;
		}
		
		strcpy(s, l->port->mp_Node.ln_Name);
		s[len1] = '/';
		strcpy(&s[len1 + 1], l->fname);
		if (sd->work[0]) {
			s[len1 + len2 + 1] = '/';
			strcpy(&s[len1 + len2 + 2], z);
		} else {
			s[len1 + len2 + 1] = 0;
		}
		deallocate(sd->work, V_cstr);
		sd->work = s;
	}
	
resolve:
	if (!collapse(s)) {
		deallocate(sd->work, V_cstr);
		sd->work = nil;
		return false;
	}
	
	for (t = s; *t; t++) {
		if (*t == '/') {
			*t++ = 0;
			sd->port = get_site(s);
			if (!sd->port) {
				deallocate(sd->work, V_cstr);
				sd->work = nil;
				return false;
			}
			if (t[0])
				sd->path = t;
			else
				sd->path = nil;
			return true;
		}
	}
	
	if (s[0] == 0) {
		deallocate(sd->work, V_cstr);
		sd->work = nil;
		sd->path = nil;
		sd->port = local_port;
		return true;
	}
	
	/* ok, we don't have a '/' so check for .info or Unnamed or
	   Disk or Default ... they are "special" */
	if (stricmp(s, "Disk") == 0 ||
			strnicmp(s, "Unnamed", 7) == 0 ||
			stricmp(s, ".backdrop") == 0 ||
			stricmp(s, "Default") == 0 ||
			stricmp(&s[strlen(s) - 5], ".info") == 0) {
		sd->port = local_port;
		sd->path = s;
		return true;
	}
	
	sd->port = get_site(s);
	deallocate(sd->work, V_cstr);
	sd->work = nil;
	sd->path = nil;
	
	if (!sd->port) return false;
	return true;
}

void end_split(split *sd)
{
	if (sd->work) {
		deallocate(sd->work, V_cstr);
		sd->work = nil;
	}
}
