
//======================================================================
//
//	Portions written by FreemanSoft Inc.
//
//	FreemanSoft disclaims any warranty of any kind, expressed or implied,
//	as to this source code's fitness for any particular use.
//
//	For more information, use the following electronic mail addresses:
//	 
//		info@FreemanSoft.com	general questions
//		support@FreemanSoft.com	technical questions
//
//======================================================================


/* Written by
 *	Joe Freeman	jfreeman@next.com	
 *	RdistControl
 *
 *	This code has no warranty.  
 *	It is provided so that the consumer may maintain and modify it
 *	at their own risk.  Use this code at your own risk.
 */

#import "RdistControl.h"
#import "Subprocess.h"
#import "PreferencesPanel.h"
#import "pathutil.h"
#import "common.h"
#import "rdistControl.h"		// strings entries

#import "JumpBackControl.h"


/*================================================================
 *	Private methods 
 *================================================================*/
 
@implementation RdistControl

/*================================================================
 *	all strings related to rdist are right before runPassTwo: 
 *================================================================*/

	

- (const char *)buttonImageName
{
    return "JumpBack_notext.tiff";
}

- (const char *)buttonAltImageName
{
    return "JumpBack_abort.tiff";
}

- (const char *)stringsTable
{
    return "rdistControl";
}

- free
{
    [[NXApp delegate] dropDragJumpBackController:self];
    return [super free];
}


/*
 * try and figure out if the values have changed 
 * support relative and absolute 
 */
- updateFromTextFields:sender
{
    /* first do the simpler dest path */
    if (strcmp(dPathList, [destinationText stringValue]))
    {
    	/* destination path has changed */
	strcpy(dPathList, [destinationText stringValue]);
    } 
    
    /* then do the more complicated source path */
    if (!strcmp(NXGetDefaultValue([NXApp appName],path_default), 
    			rdist_absolute))
    {
    	/* running in absolute mode so text field is full path name */
	if (strcmp(sPathList, [sourceText stringValue])){
		strcpy(sPathList, [sourceText stringValue]);
	} 
    }
    else if (!strcmp(NXGetDefaultValue([NXApp appName],path_default),
			rdist_relative))
    {
    	/* running in relative mode so only append the base name */
	if (strcmp(basename(sPathList), [sourceText stringValue])){
		strcpy(basename(sPathList), [sourceText stringValue]);
	} 
    }

    
    return self;
}


/* figure out our current mode (relative or absolute) and 
 * show path names appropriately 
 */
-updateTextFields:sender
{
	[destinationText setStringValue: dPathList];
	if (!strcmp(NXGetDefaultValue([NXApp appName],path_default),
			rdist_absolute))
	{
		[sourceText setStringValue: sPathList];
	}
	else if (!strcmp(NXGetDefaultValue([NXApp appName],path_default),
			rdist_relative))
	{
		[sourceText setStringValue: basename(sPathList)];
	}
	return self;
}

#define find_string \
	"/usr/bin/find %s -type d ! -exec %s {} \\; -print"
	
- runPassOne:sender
{
	char	buf[MAXPATHLEN+1];
	char	fwPath[MAXPATHLEN+1];	/* writable check executable */
	
	/* assume ok */
	canContinue = YES;	
	if (!strcmp(NXGetDefaultValue([NXApp appName],find_no_write), yes_str))
	{
		[[NXBundle mainBundle] getPath: fwPath
				forResource:file_writable_prog
				ofType:""];
		if (fwPath && *fwPath){
			[self setState: PASS_1_RUNNING];
			[self logIt: start_pass_1_string];
			sprintf(buf, find_string, sPathList,fwPath);
			subprocessObj = [Subprocess new:buf
				withDelegate:self
				andPtySupport:NO
				andStdErr:YES];	
		} else {
			[self logIt: missing_file_writable];
			[self abortProcess:self];
		}
		return self;
	} else {
		return nil;	/* didn't run find */
	}
	 
    return self;
}

#define	line_1			"%s -> localhost"
#define	line_2			"	install %s%s ;"
#define	line_3			"	except_pat lost+found ;"
#define	line_4			"	except_pat %s ;"
				// first param is verify string
				// second is removestring
#define	rdist_script_cmd 	"nice -19 /usr/ucb/rdist%s%s -w -f  - "
				// first is source dir rest as above
				// must put cd in before nice cause builtin
#define	rdist_script_rel	"cd %s ; nice -19 /usr/ucb/rdist%s%s -w -f - "
				// delete files in backup but not in src dir	
#define	rdist_remove_old	" -R "	
				// don't delete dest files missing from source
#define	rdist_keep_old		" "
				// run verify mode don't copy anything
#define rdist_verify_only	" -v"
				// run and copy 
#define rdist_execute		" "
		
- runPassTwo:sender
{	
    char	runString[MAXPATHLEN+1];
    char	scriptString[MAXPATHLEN+1];
    char	*removeString;	 /* pointer used to insert -R if needed */
    char	*verifyString;	 /* pointer used to insert -v if needed */
    int		i;
    char	*exemptStrings;	/* returned from app delegate */
    int		exemptCount;	/* returned from app delegate */
    char	buildPattern[MAXPATHLEN+1];	/* loads from except stream */
    int		charCnt;	/* num copied into buildPattern */				
    
    removeString = rdist_keep_old;
    verifyString = rdist_execute;
    
    canContinue = YES;
    

	[self setState:PASS_2_RUNNING];
	/* now start the backup */
	[self logIt:start_pass_2_string];
	/* does not work for some reason [logText delete:self];	*/
	if (!strcmp(NXGetDefaultValue([NXApp appName], dup_default ),
							dup_update))
		removeString = rdist_keep_old;
	else if (!strcmp(NXGetDefaultValue([NXApp appName], dup_default ),
							dup_exact))
		removeString = rdist_remove_old;
	if (!strcmp(NXGetDefaultValue([NXApp appName],path_default),
							rdist_relative))
		sprintf(runString, rdist_script_rel, 
			parentname(sPathList), verifyString,  removeString );
	else
		sprintf(runString, rdist_script_cmd,
				verifyString, removeString );
	if (debug_level >= debug_except_pat)
		fprintf(stderr,"subprocess string is \n%s\n",runString);
	//subprocessObj = [Subprocess new:runString];
	//[subprocessObj setDelegate:self];
	subprocessObj = [Subprocess new:runString
				withDelegate:self
				andPtySupport:NO
				andStdErr:YES];
	if (!strcmp(NXGetDefaultValue([NXApp appName],path_default),
							rdist_relative))
		sprintf(scriptString,line_1,basename(sPathList) );
	else
		sprintf(scriptString,line_1,[sourceText stringValue]);
	[subprocessObj send:scriptString];
	if (debug_level >= debug_except_pat)
		fprintf(stderr,"%s\n",scriptString);
	
	sprintf(scriptString,line_2, removeString, 
			[destinationText stringValue]); 
	[subprocessObj send:scriptString];
	if (debug_level >= debug_except_pat)
		fprintf(stderr,"%s\n",scriptString);
	
	///sprintf(scriptString,line_3);
	///[subprocessObj send:scriptString];
	
	/* grab the global preferences panel and ask it a question */
	[[PreferencesPanel new] 	getExemptString:&exemptStrings
					length:&exemptCount];
		
	/* 
	 * we need to escape for the sprintf and for the shell 
	 * 	that runs these commands
	 * we no longer sprintf into the buffer, so we only need to escape
	 * special characters one time 
	 * the \ does not need to be escaped 
	 */	
	charCnt = 0;
	buildPattern[0] = '\0';		
	for ( i = 0 ; i <= exemptCount; i++){
		/* note: we go one past end of string so catch that first */
		/* this is so we can catch files where no final \n */
		if (	i == exemptCount ||
			exemptStrings[i] == '\n' ) {
			if (charCnt > 0 ) {
				buildPattern[charCnt]= '\0';
			
				sprintf(scriptString,line_4, buildPattern);
				if (debug_level >= debug_except_pat)
					fprintf(stderr,"%s\n",scriptString);
				[subprocessObj send:scriptString];
				[self logIt:"	exempting: "];
				[self logIt:buildPattern];
				[self logIt:"\n"];
			
				charCnt = 0;
				buildPattern[0] = '\0';	
			}	
		} else 
		if (	exemptStrings[i] == '$' ||
			exemptStrings[i] == '.' ||
			exemptStrings[i] == '^' ){
			buildPattern[charCnt++] = '\\';
			buildPattern[charCnt++] = exemptStrings[i];
		} else 
		if (	exemptStrings[i] == '\\') {
			buildPattern[charCnt++] = exemptStrings[i];
		} else 
		{
			buildPattern[charCnt++] = exemptStrings[i];
		}
	}
	/* should free exemptStrings */		
		
	
	
	sprintf(scriptString,line_4,[destinationText stringValue]); 
	[subprocessObj send:scriptString];
	if (debug_level >= debug_except_pat)
		fprintf(stderr,"%s\n",scriptString);
						
	/* this is to try and protect us from the case where the dest 
	 * directory is inside the source folder */
	if ((!strcmp(NXGetDefaultValue([NXApp appName],path_default),
							rdist_relative))&&
		(strlen(parentname(sPathList))<strlen(parentname(dPathList))) )
		if (!strncmp(dPathList,parentname(sPathList),
				strlen(parentname(sPathList)) ) ){
			sprintf(scriptString,line_4, 
				&dPathList[strlen(parentname(sPathList))+1]);
			[subprocessObj send:scriptString];
		}
	[subprocessObj terminateInput];

    return self;
}


@end
