Exemplo n.º 1
0
int main(int argc, const char *argv[])
{
	int 	db,
		sd		= -1,
		i,
		l,
		category,
		po_err		= -1,
		replace_category = 0;

	char
		*category_name 	= NULL,
		*expenseType	= NULL,
		*paymentType	= NULL;
	size_t size;
	int found;

	unsigned char buf[0xffff];
	unsigned char *b;
	pi_buffer_t *appblock;

	struct 	PilotUser User;
	struct 	ExpenseAppInfo eai;
	struct 	Expense theExpense;

	poptContext po;

	struct poptOption options[] = {
		USERLAND_RESERVED_OPTIONS
	        {"ptype", 	't', POPT_ARG_STRING, &paymentType, 0,"Payment type (Cash, Check, etc.)"},
        	{"etype", 	'e', POPT_ARG_STRING, &expenseType, 0, "Expense type (Airfare, Hotel, etc.)"},
	        {"amount", 	'a', POPT_ARG_STRING, &theExpense.amount, 0, "Payment amount"},
        	{"vendor", 	'V', POPT_ARG_STRING, &theExpense.vendor, 0, "Expense vendor name (Joe's Restaurant)"},
	        {"city", 	'i', POPT_ARG_STRING, &theExpense.city, 0, "Location/city for this expense entry"},
        	{"guests", 	'g', POPT_ARG_STRING, &theExpense.attendees, 0, "Number of guests for this expense entry","NUMBER"},
	        {"note", 	'n', POPT_ARG_STRING, &theExpense.note, 0, "Notes for this expense entry"},
        	{"category", 	'c', POPT_ARG_STRING, &category_name, 0, "Install entry into this category", "CATEGORY" },
                {"replace", 	0, POPT_ARG_VAL, &replace_category, 1, "Replace all entries in category by this one"},
        	POPT_TABLEEND
	};

	/* Zero 'em out to be sure. */
	theExpense.amount=theExpense.vendor=theExpense.city=
	theExpense.attendees=theExpense.note = NULL ;

	po = poptGetContext("pilot-install-expenses", argc, argv, options, 0);
	poptSetOtherOptionHelp(po,"\n\n"
		"   Install Expense application entries to your Palm device\n\n"
		"   Example arguments:\n"
		"     %s -p /dev/pilot -c Unfiled -t Cash -e Meals -a 10.00 -V McDonalds \n"
		"                      -g 21 -l \"San Francisco\" -N \"This is a note\"\n\n");

	if (argc < 2) {
		poptPrintUsage(po,stderr,0);
		return 1;
        }

	 while ((po_err = poptGetNextOpt(po)) >= 0) {
		fprintf(stderr,"   ERROR: Unhandled option %d.\n",po_err);
		return 1;
	}

	theExpense.type = etBus;
	found = 0;
	for (i = 0; expenseType && ExpenseTypeNames[i] != NULL; i++)
	{
		if (strcasecmp(expenseType, ExpenseTypeNames[i]) == 0)
		{
			theExpense.type = i;
			found = 1;
			break;
		}
	}
	if (!found) {
		fprintf(stderr,"   WARNING: Expense type '%s' not recognized, using 'Bus Fare'.\n",expenseType);
	}

	theExpense.payment = epCash;
	found = 0;
	for (i = 0; paymentType && ExpensePaymentNames[i] != NULL; i++)
	{
		if (strcasecmp(paymentType, ExpensePaymentNames[i]) == 0)
		{
			theExpense.payment = i;
			found = 1;
			break;
		}
	}
	if (!found) {
		fprintf(stderr,"   WARNING: Payment type '%s' not recognized, using 'Cash'.\n", paymentType);
	}

	if (replace_category && (!category_name)) {
		fprintf(stderr,
			"   ERROR: category required when specifying replace\n");
		return 1;
	}


	if (!(theExpense.amount || theExpense.vendor || theExpense.city ||
		theExpense.attendees ||theExpense.note)) {
		fprintf(stderr,"   ERROR: Must specify at least one of amount, vendor, city, attendees or note.\n");
		return 1;
	}

	sd = plu_connect();
	if (sd < 0)
		goto error;

	if (dlp_OpenConduit(sd) < 0)
		goto error_close;

	dlp_ReadUserInfo(sd, &User);
	dlp_OpenConduit(sd);

	/* Open the Expense's database, store access handle in db */
	if (dlp_OpenDB(sd, 0, 0x80 | 0x40, Expense_DB, &db) < 0) {
		fprintf(stderr,"   ERROR: Unable to open ExpenseDB on Palm.");
		dlp_AddSyncLogEntry(sd, "Unable to open ExpenseDB.\n");
		goto error_close;
	}

	appblock = pi_buffer_new(0xffff);
	l = dlp_ReadAppBlock(sd, db, 0, 0xffff, appblock);
	unpack_ExpenseAppInfo(&eai, appblock->data, l);
	pi_buffer_free(appblock);

	category = 0;	/* unfiled */
	if (category_name) {
		category = plu_findcategory(&eai.category,category_name,
			PLU_CAT_CASE_INSENSITIVE | PLU_CAT_WARN_UNKNOWN);
		if (category < 0) {
			goto error_close;
		}

		if (replace_category) {
			dlp_DeleteCategory(sd, db, category);
		}

	}

		theExpense.currency 	= 0;

		if (!theExpense.amount) {
			theExpense.amount = "";
		}
		if (!theExpense.vendor) {
			theExpense.vendor = "";
		}
		if (!theExpense.city) {
			theExpense.city = "";
		}
		if (!theExpense.attendees) {
			theExpense.attendees 	= "";
		}
		if (!theExpense.note) {
			theExpense.note = "";
		}

		b = buf;

		/* Date */
		*(b++) 	= 0xc3;
		*(b++) 	= 0x45;

		*(b++) 	= theExpense.type;
		*(b++) 	= theExpense.payment;
		*(b++) 	= theExpense.currency;
		*(b++) 	= 0x00;

		strcpy(b, theExpense.amount);
		b += strlen(theExpense.amount) + 1;

		strcpy(b, theExpense.vendor);
		b += strlen(theExpense.vendor) + 1;

		strcpy(b, theExpense.city);
		b += strlen(theExpense.city) + 1;

		strcpy(b, theExpense.attendees);
		b += strlen(theExpense.attendees) + 1;

		strcpy(b, theExpense.note);
		b += strlen(theExpense.note) + 1;

		size = b - buf;
		dlp_WriteRecord(sd, (unsigned char)db, 0, 0, category,
				(unsigned char *)buf, size, 0);

	/* Close the database */
	dlp_CloseDB(sd, db);

	/* Tell the user who it is, with a different PC id. */
	User.lastSyncPC 	= 0x00010000;
	User.successfulSyncDate = time(NULL);
	User.lastSyncDate 	= User.successfulSyncDate;
	dlp_WriteUserInfo(sd, &User);

	dlp_AddSyncLogEntry(sd, "Wrote expense entry to Palm.\n");
	dlp_EndOfSync(sd, 0);
	pi_close(sd);
	poptFreeContext(po);
	return 0;

error_close:
	pi_close(sd);

error:
	return -1;
}
Exemplo n.º 2
0
int main(int argc, const char *argv[]) {
	int 	c,			/* switch */
		db,
		l,
		sd 			= -1;

	enum { mode_none, mode_read, mode_write, mode_delete_all, mode_delete }
		run_mode = mode_none;

	const char
        	*progname 		= argv[0];

	char 	*defaultcategoryname 	= 0,
		*deletecategory 	= 0,
		*wrFilename		= NULL,
		*rdFilename		= NULL,
		buf[0xffff];

	int writehuman = 0;

	pi_buffer_t *appblock;

	struct 	AddressAppInfo 	aai;
	struct 	PilotUser 	User;
        struct  SysInfo         info;

	poptContext po;

	struct poptOption options[] = {
		USERLAND_RESERVED_OPTIONS
	        {"delete-all",	 0 , POPT_ARG_NONE, NULL,  mode_delete_all, "Delete all Palm records in all categories", NULL},
	        {"delimiter",	't', POPT_ARG_INT,  &tabledelim,          0, "Include category, use delimiter (3=tab, 2=;, 1=,)", "<delimeter>"},
        	{"delete-category",	'd', POPT_ARG_STRING, &deletecategory,'d', "Delete old Palm records in <category>", "category"},
	        {"category",	'c', POPT_ARG_STRING, &defaultcategoryname, 0, "Category to install to", "category"},
        	{"augment",	'a', POPT_ARG_NONE, &augment,             0, "Augment records with additional information", NULL},
	        {"read",	'r', POPT_ARG_STRING, &rdFilename, 'r', "Read records from <file> and install them to Palm", "file"},
        	{"write",	'w', POPT_ARG_STRING, &wrFilename, 'w', "Get records from Palm and write them to <file>", "file"},
		{"human-readable",'C', POPT_ARG_NONE, &writehuman, 0, "Write generic human-readable output instead of CSV", NULL},
	        POPT_TABLEEND
	};

	const char *mode_error = "   ERROR: Specify exactly one of read, write, delete or delete all.\n";

	po = poptGetContext("pilot-addresses", argc, argv, options, 0);
	poptSetOtherOptionHelp(po,"\n\n"
		"   Reads addresses from a file and installs on the Palm, or\n"
		"   writes addresses from the Palm to a file.\n\n"
		"   Provide exactly one of --read or --write.\n\n");
	plu_popt_alias(po,"delall",0,"--bad-option --delete-all");
	plu_popt_alias(po,"delcat",0,"--bad-option --delete-category");
	plu_popt_alias(po,"install",0,"--bad-option --category");
	/* Useful alias */
	plu_popt_alias(po,"no-csv",0,"--human-readable");

	if (argc < 2) {
		poptPrintUsage(po,stderr,0);
		return 1;
	}

	while ((c = poptGetNextOpt(po)) >= 0) {
		switch (c) {
		/* These are the mode-setters. delete-all does it through
		 * popt hooks, since it doesn't take an argument.
		 *
		 * Special case is that you can mix -w and -d to write the
		 * file and then delete a category.
		 */
		case mode_delete_all :
			if (run_mode != mode_none) {
				fprintf(stderr,"%s",mode_error);
				return 1;
			}
			run_mode = mode_delete_all;
			break;
		case 'r':
			if (run_mode != mode_none) {
				fprintf(stderr,"%s",mode_error);
				return 1;
			}
			run_mode = mode_read;
			break;
		case 'w':
			if ((run_mode != mode_none) && (run_mode != mode_delete)) {
				fprintf(stderr,"%s",mode_error);
				return 1;
			}
			run_mode = mode_write;
			break;
		case 'd':
			if ((run_mode != mode_none) && (run_mode != mode_write)) {
				fprintf(stderr,"%s",mode_error);
				return 1;
			}
			run_mode = mode_delete;
			break;
		default:
			fprintf(stderr,"   ERROR: Unhandled option %d.\n",c);
			return 1;
		}
	}

	if (c < -1)
		plu_badoption(po,c);

	if (mode_none == run_mode) {
		fprintf(stderr,"%s",mode_error);
		return 1;
	}

	/* The first implies that -t was given; the second that it wasn't,
	   so use default, and the third if handles weird values. */
	if ((tabledelim < 0) || (tabledelim > sizeof(tabledelim))) {
		fprintf(stderr,"   ERROR: Invalid delimiter number %d (use 0-%d).\n",
			tabledelim,(int)(sizeof(tabledelim)));
		return 1;
	}

	sd = plu_connect();

	if (sd < 0)
		goto error;

        if (dlp_ReadUserInfo(sd, &User) < 0)
                goto error_close;

        if (dlp_ReadSysInfo(sd,&info) < 0) {
                fprintf(stderr,"   ERROR: Could not read Palm System Information.\n");
                return -1;
        }

        if (info.romVersion > 0x05003000) {
                printf("   PalmOS 5.x (Garnet) and later devices are not currently supported by this\n"
                       "   tool. The data format of the AddressBook has changed. The legacy format\n"
                       "   is called \"Classic\" and PalmOS 5.x and later uses \"Extended\" databases\n"
                       "   with a different structure. Your Palm has \"Contacts\", and this tool reads\n"
                       "   the \"AddressBook\" database. (Found OS version: %x)\n\n"

                       "   Due to this change, pilot-addresses and other tools must be rewritten to\n"
                       "   compensate. Sorry about the inconvenience.\n\n", info.romVersion);

		/* return -1; FIXME: Need to adjust this to clealy detect OS version and rewrite */
        }

	/* Open the AddressDB.pdb database, store access handle in db */
	if (dlp_OpenDB(sd, 0, 0x80 | 0x40, "AddressDB", &db) < 0) {
		puts("Unable to open AddressDB");
		dlp_AddSyncLogEntry(sd, "Unable to open AddressDB.\n");
		goto error_close;
	}

	appblock = pi_buffer_new(0xffff);
	l = dlp_ReadAppBlock(sd, db, 0, 0xffff, appblock);
	unpack_AddressAppInfo(&aai, appblock->data, l);
	pi_buffer_free(appblock);

	if (defaultcategoryname) {
		defaultcategory =
		    plu_findcategory(&aai.category,defaultcategoryname,
		    	PLU_CAT_CASE_INSENSITIVE | PLU_CAT_DEFAULT_UNFILED);
	} else {
		defaultcategory = 0;	/* Unfiled */
	}

	switch(run_mode) {
		FILE *f;
		int i;
		int old_quiet;
	case mode_none:
		/* impossible */
		fprintf(stderr,"%s",mode_error);
		break;
	case mode_write:
		/* FIXME - Must test for existing file first! DD 2002/03/18 */
		if (strcmp(wrFilename,"-") == 0) {
			f = stdout;
			old_quiet = plu_quiet;
			plu_quiet = 1;
		} else {
			f = fopen(wrFilename, "w");
		}
		if (f == NULL) {
			sprintf(buf, "%s: %s", progname, wrFilename);
			perror(buf);
			goto error_close;
		}
		write_file(f, sd, db, &aai, writehuman);
		if (f == stdout) {
			plu_quiet = old_quiet;
		}
		if (deletecategory) {
			dlp_DeleteCategory(sd, db,
				plu_findcategory(&aai.category,deletecategory,PLU_CAT_CASE_INSENSITIVE | PLU_CAT_WARN_UNKNOWN));
		}
		if (f != stdout) {
			fclose(f);
		}
		break;
	case mode_read:
		f = fopen(rdFilename, "r");

		if (f == NULL) {
			fprintf(stderr, "Unable to open input file");
			fprintf(stderr, " '%s' (%s)\n\n",
				rdFilename, strerror(errno));
			fprintf(stderr, "Please make sure the file");
			fprintf(stderr, "'%s' exists, and that\n",
				rdFilename);
			fprintf(stderr, "it is readable by this user");
			fprintf(stderr, " before launching.\n\n");

			goto error_close;
		}
		read_file(f, sd, db, &aai);
		fclose(f);
		break;
	case mode_delete:
		i = plu_findcategory (&aai.category,deletecategory,PLU_CAT_CASE_INSENSITIVE | PLU_CAT_WARN_UNKNOWN);
		if (i>=0) {
			dlp_DeleteCategory(sd, db, i);
		}
		break;
	case mode_delete_all:
		for (i = 0; i < 16; i++)
			if (aai.category.name[i][0])
				dlp_DeleteCategory(sd, db, i);
		break;
	}

	/* Close the database */
	dlp_CloseDB(sd, db);

	/* Tell the user who it is, with a different PC id. */
	User.lastSyncPC = 0x00010000;
	User.successfulSyncDate = time(NULL);
	User.lastSyncDate = User.successfulSyncDate;
	dlp_WriteUserInfo(sd, &User);

	if (run_mode == mode_read) {
		dlp_AddSyncLogEntry(sd, "Wrote entries to Palm Address Book.\n");
	} else if (run_mode == mode_write) {
		dlp_AddSyncLogEntry(sd, "Successfully read Address Book from Palm.\n");
	}

	dlp_EndOfSync(sd, 0);
	pi_close(sd);

	return 0;

error_close:
        pi_close(sd);

error:
        return -1;
}
Exemplo n.º 3
0
int main(int argc, const char *argv[])
{
	int 	c,		/* switch */
		db,
		sd 		= -1,
		i,
		read_todos 	= -1;
	FILE 	*ical = NULL;
	char 	cmd[255],
		*ptext 		= NULL,
		*icalfile 	= NULL,
		*pubtext 	= NULL;
	struct ToDoAppInfo tai;
	pi_buffer_t *recbuf,
	    *appblock;

	poptContext pc;

	struct poptOption options[] = {
		USERLAND_RESERVED_OPTIONS
		{"datebook", 'd', POPT_ARG_VAL, &read_todos, 0,
		 "Datebook only, no ToDos", NULL},
		{"pubtext", 't', POPT_ARG_STRING, &ptext, 0,
		 "Replace text of items not started with a bullet with <pubtext>",
		 "pubtext"},
		{"file", 'f', POPT_ARG_STRING, &icalfile, 0,
		 "Write the ical formatted data to <file> (overwrites existing <file>)",
		 "file"},
		POPT_TABLEEND
	};

	pc = poptGetContext("read-ical", argc, argv, options, 0);
	poptSetOtherOptionHelp(pc,"\n\n"
		"   Dumps the DatebookDB and/or ToDo applications to ical format.\n"
		"   Requires the program 'ical'.\n\n");

	if (argc < 2) {
		poptPrintUsage(pc,stderr,0);
		return 1;
	}

	while ((c = poptGetNextOpt(pc)) >= 0) {
		fprintf(stderr,"   ERROR: Unhandled option %d.\n",c);
		return 1;
	}

	if (c < -1) {
		plu_badoption(pc,c);
		return 1;
	}


	if (icalfile == NULL) {
		fprintf(stderr, "   ERROR: ical filename not specified. Please use the -f option.\n");
		return 1;
	}

        sd = plu_connect();
        if (sd < 0)
                goto error;

	unlink(icalfile);
	sprintf(cmd, "ical -list -f - -calendar %s", icalfile);
	ical = popen(cmd, "w");
	if (ical == NULL) {
		int e = errno;
		fprintf(stderr,"   ERROR: cannot start communication with ical.\n"
			"          %s\n",strerror(e));
		return 1;
	}
	fprintf(ical, "calendar cal $ical(calendar)\n");

        if (dlp_OpenConduit(sd) < 0)
                goto error_close;


	if (read_todos) {
		/* Open the ToDo database, store access handle in db */
		if (dlp_OpenDB
		    (sd, 0, 0x80 | 0x40, "ToDoDB", &db) < 0) {
			fprintf(stderr,"   ERROR: Unable to open ToDoDB on Palm.\n");
			dlp_AddSyncLogEntry(sd, "Unable to open ToDoDB.\n");
			goto error_close;
		}

		appblock = pi_buffer_new(0xffff);
		dlp_ReadAppBlock(sd, db, 0, 0xffff, appblock);
		unpack_ToDoAppInfo(&tai, appblock->data, appblock->used);
		pi_buffer_free(appblock);

		recbuf = pi_buffer_new (0xffff);

		for (i = 0;; i++) {
			int 	attr,
				category;
			char 	id_buf[255];
			struct 	ToDo t;
			recordid_t id_;

			int len = dlp_ReadRecordByIndex(sd, db, i, recbuf, &id_, &attr, &category);

			if (len < 0)
				break;

			/* Skip deleted records */
			if ((attr & dlpRecAttrDeleted)
			    || (attr & dlpRecAttrArchived))
				continue;

			unpack_ToDo(&t, recbuf, todo_v1);

			fprintf(ical, "set n [notice]\n");

			/* '\x95' is the "bullet" chcter */
			fprintf(ical, "$n text %s\n", tclquote((pubtext && t.description[0] != '\x95') ? pubtext : t.description));
			fprintf(ical, "$n date [date today]\n");
			fprintf(ical, "$n todo 1\n");
			fprintf(ical, "$n option Priority %d\n", t.priority);
			sprintf(id_buf, "%lx", id_);
			fprintf(ical, "$n option PilotRecordId %s\n", id_buf);
			fprintf(ical, "$n done %d\n", t.complete ? 1 : 0);
			fprintf(ical, "cal add $n\n");

			free_ToDo(&t);
		}
		pi_buffer_free(recbuf);

		/* Close the database */
		dlp_CloseDB(sd, db);

		dlp_AddSyncLogEntry(sd, "Successfully read todos from Palm.\nThank you for using pilot-link.\n");
	}

	/* Open the Datebook's database, store access handle in db */
	if (dlp_OpenDB
	    (sd, 0, 0x80 | 0x40, "DatebookDB", &db) < 0) {
		fprintf(stderr,"   ERROR: Unable to open DatebookDB on Palm.\n");
		dlp_AddSyncLogEntry(sd, "Unable to open DatebookDB.\n");
		goto error_close;
	}

	recbuf = pi_buffer_new (0xffff);

	for (i = 0;; i++) {
		int 	j,
			attr;
		char 	id_buf[255];
		struct 	Appointment a;
		recordid_t id_;

		int len =
		    dlp_ReadRecordByIndex(sd, db, i, recbuf, &id_, &attr, 0);

		if (len < 0)
			break;

		/* Skip deleted records */
		if ((attr & dlpRecAttrDeleted)
		    || (attr & dlpRecAttrArchived))
			continue;

		unpack_Appointment(&a, recbuf, datebook_v1);

		if (a.event) {
			fprintf(ical, "set i [notice]\n");

		} else {
			int 	start,
				end;

			fprintf(ical, "set i [appointment]\n");

			start =
			    a.begin.tm_hour * 60 +
			    a.begin.tm_min;
			end =
			    a.end.tm_hour * 60 +
			    a.end.tm_min;

			fprintf(ical, "$i starttime %d\n", start);
			fprintf(ical, "$i length %d\n", end - start);
		}

		/* Don't hilight private (secret) records */
		if (attr & dlpRecAttrSecret) {
			fprintf(ical, "$i hilite never\n");
		}

		/* Handle alarms */
		if (a.alarm) {
			if (a.event) {
				if (a.advanceUnits == 2) {
					fprintf(ical, "$i earlywarning %d\n", a.advance);
				} else {
					printf("Minute or hour alarm on untimed event ignored: %s\n", a.description);
				}
			} else {
				switch (a.advanceUnits) {
				  case 0:
					  fprintf(ical, "$i alarms { %d }\n", a.advance);
					  break;
				  case 1:
					  fprintf(ical, "$i alarms { %d }\n", a.advance * 60);
					  break;
				  case 2:
					  fprintf(ical, "$i earlywarning %d\n", a.advance);
					  break;
				}
			}
		}

		/* '\x95' is the "bullet" chcter */
		fprintf(ical, "$i text %s\n",
			tclquote((pubtext
				  && a.description[0] !=
				  '\x95') ? pubtext : a.
				 description));

		fprintf(ical,
			"set begin [date make %d %d %d]\n",
			a.begin.tm_mday,
			a.begin.tm_mon + 1,
			a.begin.tm_year + 1900);

		if (a.repeatFrequency) {
			if (a.repeatType == repeatDaily) {
				fprintf(ical,
					"$i dayrepeat %d $begin\n", a.repeatFrequency);
			} else if (a.repeatType == repeatMonthlyByDate) {
				fprintf(ical, "$i month_day %d $begin %d\n", a.begin.tm_mon + 1, a.repeatFrequency);
			} else if (a.repeatType == repeatMonthlyByDay) {
				if (a.repeatDay >= domLastSun) {
					fprintf(ical, "$i month_last_week_day %d 1 $begin %d\n", a.repeatDay % 7 + 1, a.repeatFrequency);
				} else {
					fprintf(ical, "$i month_week_day %d %d $begin %d\n", a.repeatDay % 7 + 1, a.repeatDay / 7 + 1, a.repeatFrequency);
				}
			} else if (a.repeatType == repeatWeekly) {
				/*
				 * Handle the case where the user said weekly repeat, but
				 * really meant daily repeat every n*7 days.  Note: We can't
				 * do days of the week and a repeat-frequency > 1, so do the
				 * best we can and go on.
				 */
				if (a.repeatFrequency > 1) {
					int ii, found;

					for (ii = 0, found = 0; ii < 7; ii++) {
						if (a.repeatDays [ii])
							found++;
					}
					if (found > 1) {
						fprintf(stderr,"   WARNING: Incomplete translation of %s\n", a.description);
					}
					fprintf(ical, "$i dayrepeat %d $begin\n", a.repeatFrequency * 7);
				} else {
					int ii;

					fprintf(ical, "$i weekdays ");
					for (ii = 0; ii < 7; ii++)
						if (a.repeatDays [ii])
							fprintf(ical, "%d ", ii + 1);
					fprintf(ical, "\n");
				}
			} else if (a.repeatType == repeatYearly) {
				fprintf(ical, "$i monthrepeat %d $begin\n", 12 * a.repeatFrequency);
			}
			fprintf(ical, "$i start $begin\n");
			if (!a.repeatForever)
				fprintf(ical,
					"$i finish [date make %d %d %d]\n",
					a.repeatEnd.tm_mday, a.repeatEnd.tm_mon + 1, a.repeatEnd.tm_year + 1900);
			if (a.exceptions)
				for (j = 0; j < a.exceptions; j++)
					fprintf(ical, "$i deletion [date make %d %d %d]\n", a.exception[j].tm_mday, a.exception[j].tm_mon + 1, a.exception[j].tm_year + 1900);
		} else
			fprintf(ical, "$i date $begin\n");

		sprintf(id_buf, "%lx", id_);
		fprintf(ical, "$i option PilotRecordId %s\n", id_buf);
		fprintf(ical, "cal add $i\n");

		free_Appointment(&a);

	}

	pi_buffer_free (recbuf);

	fprintf(ical, "cal save [cal main]\n");
	fprintf(ical, "exit\n");

	pclose(ical);

	/* Close the database */
	dlp_CloseDB(sd, db);

	dlp_AddSyncLogEntry(sd, "read-ical successfully read Datebook from Palm.\n"
				"Thank you for using pilot-link.\n");
	dlp_EndOfSync(sd, 0);
	pi_close(sd);
	return 0;

error_close:
	if (ical) {
		/* explicitly do NOT save on failure. since we've already unlinked
		   the original ical file, we've still destroyed something. */
		fprintf(ical, "exit\n");
		pclose(ical);
	}
        pi_close(sd);

error:
        return -1;
}
Exemplo n.º 4
0
/* Pilot syncing callbacks */
static gint
pre_sync (GnomePilotConduit *conduit,
	  GnomePilotDBInfo *dbi,
	  EAddrConduitContext *ctxt)
{
	GnomePilotConduitSyncAbs *abs_conduit;
	EBookQuery *query;
    	GList *l;
	int len;
	char *filename;
	char *change_id;
	char *auth;
	gint num_records, add_records = 0, mod_records = 0, del_records = 0;
#ifdef PILOT_LINK_0_12
	pi_buffer_t *buffer;
#else
	unsigned char *buf;
#endif

	abs_conduit = GNOME_PILOT_CONDUIT_SYNC_ABS (conduit);

	LOG (g_message ( "---------------------------------------------------------\n" ));
	LOG (g_message ( "pre_sync: Addressbook Conduit v.%s", CONDUIT_VERSION ));
	/* g_message ("Addressbook Conduit v.%s", CONDUIT_VERSION); */

	ctxt->dbi = dbi;

	if (ctxt->cfg->source) {
		ctxt->ebook = e_book_new (ctxt->cfg->source, NULL);
	} else {
		ctxt->ebook = e_book_new_default_addressbook (NULL);
	}
	auth = (gchar *)e_source_get_property (ctxt->cfg->source, "auth");
	if (auth) {
		LOG (g_message ("contacts needs authentication\n"));
		g_signal_connect (ctxt->ebook, "auth_required",
				  G_CALLBACK (addressbook_authenticate), ctxt->cfg->source);
	}
	if (!ctxt->ebook || !e_book_open (ctxt->ebook, TRUE, NULL)) {
		WARN(_("Could not load addressbook"));
		gnome_pilot_conduit_error (conduit, _("Could not load addressbook"));

		return -1;
	}

	/* Load the uid <--> pilot id mappings */
	filename = map_name (ctxt);
	e_pilot_map_read (filename, &ctxt->map);
	g_free (filename);

	/* Get a list of all contacts */
	if (!(query = e_book_query_any_field_contains (""))) {
		LOG (g_warning ("Failed to get EBookQuery"));
		return -1;
	}

	if (!e_book_get_contacts (ctxt->ebook, query, &ctxt->cards, NULL)) {
		LOG (g_warning ("Failed to get Contacts"));
		e_book_query_unref (query);
		return -1;
	}

	e_book_query_unref (query);

	/* Count and hash the changes */
	change_id = g_strdup_printf ("pilot-sync-evolution-addressbook-%d", ctxt->cfg->pilot_id);
	if (!e_book_get_changes (ctxt->ebook, change_id, &ctxt->changed, NULL))
		return -1;
	ctxt->changed_hash = g_hash_table_new (g_str_hash, g_str_equal);
	g_free (change_id);

	for (l = ctxt->changed; l != NULL; l = l->next) {
		EBookChange *ebc = l->data;
		const char *uid;

		uid = e_contact_get_const (ebc->contact, E_CONTACT_UID);
		if (!e_pilot_map_uid_is_archived (ctxt->map, uid)) {

			g_hash_table_insert (ctxt->changed_hash, g_strdup (uid), ebc);

			switch (ebc->change_type) {
			case E_BOOK_CHANGE_CARD_ADDED:
				add_records++;
				break;
			case E_BOOK_CHANGE_CARD_MODIFIED:
				mod_records++;
				break;
			case E_BOOK_CHANGE_CARD_DELETED:
				del_records++;
				break;
			}
		} else if (ebc->change_type == E_BOOK_CHANGE_CARD_DELETED) {
			e_pilot_map_remove_by_uid (ctxt->map, uid);
		}
	}

	/* Set the count information */
  	num_records = g_list_length (ctxt->cards);
  	gnome_pilot_conduit_sync_abs_set_num_local_records(abs_conduit, num_records);
  	gnome_pilot_conduit_sync_abs_set_num_new_local_records (abs_conduit, add_records);
  	gnome_pilot_conduit_sync_abs_set_num_updated_local_records (abs_conduit, mod_records);
  	gnome_pilot_conduit_sync_abs_set_num_deleted_local_records(abs_conduit, del_records);

#ifdef PILOT_LINK_0_12
	buffer = pi_buffer_new(DLP_BUF_SIZE);
	if(buffer == NULL){
		return pi_set_error(dbi->pilot_socket, PI_ERR_GENERIC_MEMORY);
	}

	len = dlp_ReadAppBlock (dbi->pilot_socket, dbi->db_handle, 0,
			      DLP_BUF_SIZE, buffer);
#else
	buf = (unsigned char*)g_malloc (0xffff);
	len = dlp_ReadAppBlock (dbi->pilot_socket, dbi->db_handle, 0,
			      (unsigned char *)buf, 0xffff);
#endif
	if (len < 0) {
		WARN (_("Could not read pilot's Address application block"));
		WARN ("dlp_ReadAppBlock(...) = %d", len);
		gnome_pilot_conduit_error (conduit,
					   _("Could not read pilot's Address application block"));
		return -1;
	}
#ifdef PILOT_LINK_0_12
	unpack_AddressAppInfo (&(ctxt->ai), buffer->data, len);
	pi_buffer_free (buffer);
#else
	unpack_AddressAppInfo (&(ctxt->ai), buf, len);
	g_free (buf);
#endif
  	check_for_slow_setting (conduit, ctxt);
	if (ctxt->cfg->sync_type == GnomePilotConduitSyncTypeCopyToPilot
	    || ctxt->cfg->sync_type == GnomePilotConduitSyncTypeCopyFromPilot)
		ctxt->map->write_touched_only = TRUE;

	return 0;
}
Exemplo n.º 5
0
/* Pilot syncing callbacks */
static gint
pre_sync (GnomePilotConduit *conduit,
	  GnomePilotDBInfo *dbi,
	  EMemoConduitContext *ctxt)
{
	GnomePilotConduitSyncAbs *abs_conduit;
	GList *l;
	int len;
	unsigned char *buf;
	char *filename, *change_id;
	icalcomponent *icalcomp;
	gint num_records, add_records = 0, mod_records = 0, del_records = 0;
#ifdef PILOT_LINK_0_12
	pi_buffer_t * buffer;
#endif

	abs_conduit = GNOME_PILOT_CONDUIT_SYNC_ABS (conduit);

	LOG (g_message ( "---------------------------------------------------------\n" ));
	LOG (g_message ( "pre_sync: Memo Conduit v.%s", CONDUIT_VERSION ));
	g_message ("Memo Conduit v.%s", CONDUIT_VERSION);

	ctxt->dbi = dbi;
	ctxt->client = NULL;

	if (start_calendar_server (ctxt) != 0) {
		WARN(_("Could not start evolution-data-server"));
		gnome_pilot_conduit_error (conduit, _("Could not start evolution-data-server"));
		return -1;
	}

	/* Get the timezone */
	ctxt->timezone = get_default_timezone ();
	if (ctxt->timezone == NULL)
		return -1;
	LOG (g_message ( "  Using timezone: %s", icaltimezone_get_tzid (ctxt->timezone) ));

	/* Set the default timezone on the backend. */
	if (ctxt->timezone && !e_cal_set_default_timezone (ctxt->client, ctxt->timezone, NULL))
		return -1;

	/* Get the default component */
	if (!e_cal_get_default_object (ctxt->client, &icalcomp, NULL))
		return -1;

	ctxt->default_comp = e_cal_component_new ();
	if (!e_cal_component_set_icalcomponent (ctxt->default_comp, icalcomp)) {
		g_object_unref (ctxt->default_comp);
		icalcomponent_free (icalcomp);
		return -1;
	}

	/* Load the uid <--> pilot id map */
	filename = map_name (ctxt);
	e_pilot_map_read (filename, &ctxt->map);
	g_free (filename);

	/* Get the local database */
	if (!e_cal_get_object_list_as_comp (ctxt->client, "#t", &ctxt->comps, NULL))
		return -1;

	/* Count and hash the changes */
	change_id = g_strdup_printf ("pilot-sync-evolution-memo-%d", ctxt->cfg->pilot_id);
	if (!e_cal_get_changes (ctxt->client, change_id, &ctxt->changed, NULL))
		return -1;

	ctxt->changed_hash = g_hash_table_new (g_str_hash, g_str_equal);
	g_free (change_id);

	for (l = ctxt->changed; l != NULL; l = l->next) {
		ECalChange *ccc = l->data;
		const char *uid;

		e_cal_component_get_uid (ccc->comp, &uid);
		if (!e_pilot_map_uid_is_archived (ctxt->map, uid)) {

			g_hash_table_insert (ctxt->changed_hash, g_strdup (uid), ccc);

			switch (ccc->type) {
			case E_CAL_CHANGE_ADDED:
				add_records++;
				break;
			case E_CAL_CHANGE_MODIFIED:
				mod_records++;
				break;
			case E_CAL_CHANGE_DELETED:
				del_records++;
				break;
			}
		} else if (ccc->type == E_CAL_CHANGE_DELETED) {
			e_pilot_map_remove_by_uid (ctxt->map, uid);
		}
	}

	/* Set the count information */
	num_records = g_list_length (ctxt->comps);
	gnome_pilot_conduit_sync_abs_set_num_local_records(abs_conduit, num_records);
	gnome_pilot_conduit_sync_abs_set_num_new_local_records (abs_conduit, add_records);
	gnome_pilot_conduit_sync_abs_set_num_updated_local_records (abs_conduit, mod_records);
	gnome_pilot_conduit_sync_abs_set_num_deleted_local_records(abs_conduit, del_records);

	g_message("num_records: %d\nadd_records: %d\nmod_records: %d\ndel_records: %d\n",
		num_records, add_records, mod_records, del_records);

#ifdef PILOT_LINK_0_12
	buffer = pi_buffer_new(DLP_BUF_SIZE);
	if(buffer == NULL){
		pi_set_error(dbi->pilot_socket, PI_ERR_GENERIC_MEMORY);
		return -1;
	}

 	len = dlp_ReadAppBlock (dbi->pilot_socket, dbi->db_handle, 0,
				DLP_BUF_SIZE,
				buffer);
#else
	buf = (unsigned char*)g_malloc (0xffff);
	len = dlp_ReadAppBlock (dbi->pilot_socket, dbi->db_handle, 0,
			      (unsigned char *)buf, 0xffff);
#endif
	if (len < 0) {
		WARN (_("Could not read pilot's Memo application block"));
		WARN ("dlp_ReadAppBlock(...) = %d", len);
		gnome_pilot_conduit_error (conduit,
					   _("Could not read pilot's Memo application block"));
		return -1;
	}
#ifdef PILOT_LINK_0_12
	buf = g_new0 (unsigned char,buffer->used);
	memcpy(buf, buffer->data, buffer->used);
 	unpack_MemoAppInfo (&(ctxt->ai), buf, len);
	pi_buffer_free(buffer);
#else
	unpack_MemoAppInfo (&(ctxt->ai), buf, len);
#endif

	g_free (buf);

	lastDesktopUniqueID = 128;

	check_for_slow_setting (conduit, ctxt);
	if (ctxt->cfg->sync_type == GnomePilotConduitSyncTypeCopyToPilot
	    || ctxt->cfg->sync_type == GnomePilotConduitSyncTypeCopyFromPilot)
		ctxt->map->write_touched_only = TRUE;

	return 0;
}
Exemplo n.º 6
0
int
main (int argc, char **argv)
{
	int sd;
	int result;
	struct SysInfo s;
	struct PilotUser u1, u2;
	struct NetSyncInfo n1, n2;
	struct CardInfo c;
	struct DBInfo dbi;
	struct DBSizeInfo dbsi;
	unsigned long romVersion;
	time_t t1, t2;	
	int handle;
	unsigned char pref1[256], pref2[256];
	unsigned char ablock1[256];
	unsigned char sblock1[256];
	unsigned char ires1[256];
	unsigned char dres1[256];
	unsigned char record1[256], record2[256], record3[256];
	recordid_t rid1, rid2, rid3, rlist[4];
	int index, id_, count;
	unsigned long type;
	int cardno;
	int i;
	pi_buffer_t *record4,
		*dres2,
		*ires2,
		*appblock;

	record4 = pi_buffer_new (sizeof(record1));
	ires2 = pi_buffer_new (sizeof (ires1));
	dres2 = pi_buffer_new (sizeof (dres1));
	appblock = pi_buffer_new(256);
	
	sd = pilot_connect (argv[1]);

	t1 = time (NULL);
	LOG((PI_DBG_USER, PI_DBG_LVL_INFO, "DLPTEST Starting at %s", ctime (&t1)));

	/*********************************************************************
	 *
	 * Test: Open Conduit
	 *
	 * Direct Testing Functions:
	 *   dlp_OpenConduit
	 *
	 * Indirect Testing Functions:
	 *   None
	 *
	 *********************************************************************/
	result = dlp_OpenConduit (sd);
	CHECK_RESULT(dlp_OpenConduit);

	/*********************************************************************
	 *
	 * Test: System Information
	 *
	 * Direct Testing Functions:
	 *   dlp_ReadSysInfo
	 *
	 * Indirect Testing Functions:
	 *   None
	 *
	 *********************************************************************/
	result = dlp_ReadSysInfo (sd, &s);
	CHECK_RESULT(dlp_ReadSysInfo);
	
	/*********************************************************************
	 *
	 * Test: User Info
	 *
	 * Direct Testing Functions:
	 *   dlp_WriteUserInfo
	 *   dlp_ReadUserInfo
	 *
	 * Indirect Testing Functions:
	 *   None
	 *
	 *********************************************************************/
	memset (&u1, '\0', sizeof (struct PilotUser));
	memset (&u2, '\0', sizeof (struct PilotUser));
	u1.passwordLength = 0;
	strcpy (u1.username, "Test User");
	strcpy (u1.password, "");
	u1.userID = 500;
	u1.viewerID = 5000;
	u1.lastSyncPC = 111111;
	u1.successfulSyncDate = time(NULL);
	u1.lastSyncDate = time(NULL) + 100;

	result = dlp_WriteUserInfo (sd, &u1);
	CHECK_RESULT(dlp_WriteUserInfo);
	result = dlp_ReadUserInfo (sd, &u2);
	CHECK_RESULT(dlp_ReadUserInfo);
	if (memcmp(&u1, &u2, sizeof(struct PilotUser) != 0)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST User info mismatch\n"));
		goto error;
	}

	/*********************************************************************
	 *
	 * Test: Feature
	 *
	 * Direct Testing Functions:
	 *   dlp_ReadFeature
	 *
	 * Indirect Testing Functions:
	 *   None
	 *
	 *********************************************************************/
	romVersion = 0;

	result = dlp_ReadFeature(sd, makelong("psys"), 1, &romVersion);
	CHECK_RESULT(dlp_ReadFeature);
	if (romVersion != s.romVersion) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Rom Version mismatch\n"));
		goto error;
	}
	
	/*********************************************************************
	 *
	 * Test: Net Sync Info
	 *
	 * Direct Testing Functions:
	 *   dlp_WriteNetSyncInfo
	 *   dlp_ReadNetSyncInfo
	 *
	 * Indirect Testing Functions:
	 *   None
	 *
	 *********************************************************************/
#if DLP_1_1
	memset (&n1, '\0', sizeof (struct NetSyncInfo));
	memset (&n2, '\0', sizeof (struct NetSyncInfo));
	n1.lanSync = 0;
	strcpy (n1.hostName, "localhost");
	strcpy (n1.hostAddress, "192.168.1.1");
	strcpy (n1.hostSubnetMask, "255.255.255.0");

	result = dlp_WriteNetSyncInfo (sd, &n1);
	CHECK_RESULT(dlp_WriteNetSyncInfo);
	result = dlp_ReadNetSyncInfo (sd, &n2);
	CHECK_RESULT(dlp_ReadNetSyncInfo);
	if (memcmp(&n1, &n2, sizeof(struct NetSyncInfo) != 0)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Net sync info mismatch\n"));
		goto error;
	}
#endif

	/*********************************************************************
	 *
	 * Test: Time
	 *
	 * Direct Testing Functions:
	 *   dlp_SetSysDateTime
	 *   dlp_GetSysDateTime
	 *
	 * Indirect Testing Functions:
	 *   None
	 *
	 *********************************************************************/
	t1 = time(NULL);

	dlp_SetSysDateTime (sd, t1);
	CHECK_RESULT(dlp_SetSysDateTime);
	dlp_GetSysDateTime (sd, &t2);
	CHECK_RESULT(dlp_GetSysDateTime);
	if (t2 > t1 + 1) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST System Time Mismatch\n"));
		goto error;
	}

	/*********************************************************************
	 *
	 * Test: Storage Information
	 *
	 * Direct Testing Functions:
	 *   dlp_ReadStorageInfo
	 *
	 * Indirect Testing Functions:
	 *   None
	 *
	 *********************************************************************/
	c.more = 1;
	for (i = 0; c.more != 0; i++) {
		result = dlp_ReadStorageInfo (sd, i, &c);
		CHECK_RESULT(dlp_ReadStorageInfo);
	}

	/*********************************************************************
	 *
	 * Test: Database List
	 *
	 * Direct Testing Functions:
	 *   dlp_ReadDBList
	 *
	 * Indirect Testing Functions:
	 *   None
	 *
	 *********************************************************************/
	dbi.more = 1;
	for (i = 0; dbi.more != 0; i++) {
		result = dlp_ReadDBList (sd, 0, dlpDBListRAM | dlpDBListROM, i, record4);
		CHECK_RESULT(dlp_ReadDBList);
		memcpy(&dbi, record4->data, sizeof(struct DBInfo));
	}

	/*********************************************************************
	 *
	 * Test: Existing Database
	 *
	 * Direct Testing Functions:
	 *   dlp_OpenDB
	 *   dlp_CloseDB
	 *
	 * Indirect Testing Functions:
	 *   None
	 *
	 *********************************************************************/
	result = dlp_OpenDB (sd, 0, dlpOpenReadWrite, "ToDoDB", &handle);
	CHECK_RESULT(dlp_OpenDB);
	result = dlp_CloseDB (sd, handle);
	CHECK_RESULT(dlp_CloseDB);

	/*********************************************************************
	 *
	 * Test: New Database
	 *
	 * Direct Testing Functions:
	 *   dlp_CreateDB
	 *   dlp_CloseDB
	 *   dlp_DeleteDB
	 *
	 * Indirect Testing Functions:
	 *   None
	 *
	 *********************************************************************/
	result = dlp_CreateDB (sd, CREATOR, DATA, 0, dlpDBFlagResource, 1, "TestResource", &handle);
	CHECK_RESULT(dlp_CreateDB);
	result = dlp_CloseDB (sd, handle);
	CHECK_RESULT(dlp_CloseDB);
	result = dlp_DeleteDB (sd, 0, "TestResource");
	CHECK_RESULT(dlp_DeleteDB);

	/*********************************************************************
	 *
	 * Test: Database Info and Searching
	 *
	 * Direct Testing Functions:
	 *   dlp_SetDBInfo
	 *   dlp_FindDBByName
	 *   dlp_FindDBByOpenHandle
	 *   dlp_FindDBByTypeCreator
	 *
	 * Indirect Testing Functions:
	 *   dlp_CreateDB
	 *   dlp_OpenDB
	 *   dlp_ReadDBList
	 *   dlp_CloseDB
	 *   dlp_DeleteDB
	 *
	 *********************************************************************/
#if DLP_1_2
	result = dlp_CreateDB (sd, CREATOR, DATA, 0, 0, 1, "TestRecord", &handle);
	CHECK_RESULT(dlp_CreateDB);
	result = dlp_SetDBInfo (sd, handle, dlpDBFlagBackup, dlpDBFlagCopyPrevention, 0, 0, 0, 0, 0, 0);
	CHECK_RESULT(dlp_SetDBInfo);	
	result = dlp_CloseDB (sd, handle);
	CHECK_RESULT(dlp_CloseDB);

	result = dlp_OpenDB (sd, 0, dlpOpenReadWrite, "TestRecord", &handle);
	CHECK_RESULT(dlp_OpenDB);
	
	result = dlp_FindDBByOpenHandle (sd, handle, &cardno, NULL, &dbi, &dbsi);
	CHECK_RESULT(dlp_FindDBByOpenHandle);
	if (strcmp (dbi.name, "TestRecord") || !(dbi.flags & dlpDBFlagBackup)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Database info mismatch with openhandle\n"));
		goto error;
	}

	result = dlp_CloseDB (sd, handle);
	CHECK_RESULT(dlp_CloseDB);
	
	result = dlp_FindDBByName (sd, 0, "TestRecord", NULL, NULL, &dbi, &dbsi);
	CHECK_RESULT(dlp_FindDBByName);
	if (strcmp (dbi.name, "TestRecord") || !(dbi.flags & dlpDBFlagBackup)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Database info mismatch with name\n"));
		goto error;
	}

	result = dlp_FindDBByTypeCreator (sd, DATA, CREATOR, 1, 0, &cardno, NULL, NULL, &dbi, &dbsi);
	CHECK_RESULT(dlp_FindDBByName);
	if (strcmp (dbi.name, "TestRecord") || !(dbi.flags & dlpDBFlagBackup)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Database info mismatch with type/creator\n"));
		goto error;
	}

	result = dlp_DeleteDB (sd, 0, "TestRecord");
	CHECK_RESULT(dlp_DeleteDB);
#endif

	/*********************************************************************
	 *
	 * Test: App Preference
	 *
	 * Direct Testing Functions:
	 *   dlp_WriteAppPreference
	 *   dlp_ReadAppPreference
	 *
	 * Indirect Testing Functions:
	 *   None
	 *
	 *********************************************************************/
	memset (pref1, '\0', sizeof (pref1));
	memset (pref2, '\0', sizeof (pref2));
	pref1[9] = 'T';
	pref2[10] = 'T';
	
	result = dlp_WriteAppPreference (sd, CREATOR, 0, 1, 1, pref1, sizeof(pref1));
	CHECK_RESULT(dlp_WriteAppPrefence);
	result = dlp_ReadAppPreference (sd, CREATOR, 0, 1, sizeof(pref2), pref2, NULL, NULL);
	CHECK_RESULT(dlp_ReadAppPreference);
	if (memcmp(&pref1, &pref2, sizeof(pref1) != 0)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Preference mismatch\n"));
		goto error;
	}

	/*********************************************************************
	 *
	 * Test: Record
	 *
	 * Direct Testing Functions:
	 *   dlp_WriteAppBlock
	 *   dlp_ReadAppBlock
	 *   dlp_WriteSortBlock
	 *   dlp_ReadSortBlock
	 *   dlp_WriteRecord
	 *   dlp_ReadOpenDBInfo
	 *   dlp_ReadRecordById
	 *   dlp_ReadRecordByIndex
	 *   dlp_ReadNextModifiedRec
	 *   dlp_ReadNextRecInCategory
	 *   dlp_ReadNextModifiedRecInCategory
	 *   dlp_MoveCategory
	 *   dlp_DeleteRecord
	 *   dlp_DeleteCategory
	 *   dlp_ResetDBIndex
	 *
	 * Indirect Testing Functions:
	 *   dlp_CreateDB
	 *   dlp_CloseDB
	 *   dlp_DeleteDB
	 *
	 *********************************************************************/
	memset (ablock1, '\0', sizeof (ablock1));
	memset (sblock1, '\0', sizeof (sblock1));
	memset (record1, '\0', sizeof (record1));
	memset (record2, '\0', sizeof (record2));
	memset (record3, '\0', sizeof (record3));
	ablock1[3] = 'T';
	sblock1[17] = 'T';
	record1[32] = 'T';
	record2[33] = 'T';
	record3[34] = 'T';
	
	result = dlp_CreateDB (sd, CREATOR, DATA, 0, 0, 1, "TestRecord", &handle);
	CHECK_RESULT(dlp_CreateDB);

	/* Write and read back an app block */
	result = dlp_WriteAppBlock (sd, handle, ablock1, sizeof(ablock1));
	CHECK_RESULT(dlp_WriteAppBlock);
	result = dlp_ReadAppBlock (sd, handle, 0, sizeof(ablock1), appblock);
	CHECK_RESULT(dlp_ReadAppBlock);
	if (result != sizeof(ablock1) || memcmp(ablock1, appblock->data, sizeof(ablock1) != 0)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST App block mismatch\n"));
		goto error;
	}

	/* Write and read back a sort block */
	result = dlp_WriteSortBlock (sd, handle, sblock1, sizeof(sblock1));
	CHECK_RESULT(dlp_WriteSortBlock);
	result = dlp_ReadSortBlock (sd, handle, 0, sizeof(sblock1), appblock);
	CHECK_RESULT(dlp_ReadSortBlock);
	if (result != sizeof(sblock1) || memcmp(sblock1, appblock->data, sizeof(sblock1) != 0)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST App block mismatch\n"));
		goto error;
	}
	
	/* Write some records out */
	result = dlp_WriteRecord (sd, handle, 0, 0, 1, record1, sizeof(record1), &rid1);
	CHECK_RESULT(dlp_WriteRecord);
	result = dlp_WriteRecord (sd, handle, dlpRecAttrDirty, 0, 2, record2, sizeof(record2), &rid2);
	CHECK_RESULT(dlp_WriteRecord);
	result = dlp_WriteRecord (sd, handle, 0, 0, 3, record3, sizeof(record3), &rid3);
	CHECK_RESULT(dlp_WriteRecord);

	/* Get the db info */
	result = dlp_ReadOpenDBInfo (sd, handle, &count);
	CHECK_RESULT(dlp_ReadOpenDBInfo);
	if (count != 3) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Read wrong open database info\n"));
		goto error;
	}

	/* Get the id list */
	result = dlp_ReadRecordIDList (sd, handle, 0, 0, 4, rlist, &count);
	CHECK_RESULT(dlp_ReadRecordIDList);
	if (count != 3) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Read wrong record id list length\n"));
		goto error;
	}
	for (i = 0; i < 3; i++) {
		if (rlist[i] != rid1 && rlist[i] != rid2 && rlist[i] != rid3) {
			LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Read wrong record id\n"));
			goto error;			
		}
	}
	
	/* Try reading the records in various ways */
	result = dlp_ReadRecordById (sd, handle, rid1, record4, &index, NULL, NULL);
	CHECK_RESULT(dlp_ReadRecordById);
	if (memcmp(record1, record4->data, sizeof(record1) != 0)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Record by Id mismatch\n"));
		goto error;
	}
	result = dlp_ReadRecordByIndex (sd, handle, index, record4, NULL, NULL, NULL);
	CHECK_RESULT(dlp_ReadRecordByIndex);
	if (memcmp(record1, record4->data, sizeof(record1) != 0)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Record by index mismatch\n"));
		goto error;
	}
	result = dlp_ReadNextModifiedRec (sd, handle, record4, NULL, NULL, NULL, NULL);
	CHECK_RESULT(dlp_ReadNextModifiedRec);
	if (memcmp(record2, record4->data, sizeof(record2) != 0)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Next modified record mismatch\n"));
		goto error;
	}
	
	/* Reset because of the above next modified record call */
	result = dlp_ResetDBIndex (sd, handle);
	CHECK_RESULT(dlp_ResetDBIndex)

	/* This is a DLP 1.1 call, but pilot-link has a 1.0 implementation */
	result = dlp_ReadNextRecInCategory (sd, handle, 3, record4, NULL, NULL, NULL);
	CHECK_RESULT(dlp_ReadNextRecInCategory)
	if (memcmp(record3, record4->data, sizeof(record3) != 0)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST dlp_ReadNextRecInCategory mismatch\n"));
		goto error;
	}

	/* Reset because of the above next record in category call */
	result = dlp_ResetDBIndex (sd, handle);
	CHECK_RESULT(dlp_ResetDBIndex)

	/* This is a DLP 1.1 call, but pilot-link has a 1.0 implementation */
	result = dlp_ReadNextModifiedRecInCategory (sd, handle, 2, record4, NULL, NULL, NULL);
	CHECK_RESULT(dlp_ReadNextModifiedRecInCategory)
	if (memcmp(record2, record4->data, sizeof(record2) != 0)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST dlp_ReadNextModifiedRecInCategory mismatch\n"));
		goto error;
	}

	/* Reset because of the above next modified record in category call */
	result = dlp_ResetDBIndex (sd, handle);
	CHECK_RESULT(dlp_ResetDBIndex)

	/* Move a category and try to read the record back in */
	result = dlp_MoveCategory (sd, handle, 1, 4);
	CHECK_RESULT(dlp_MoveCategory)
	result = dlp_ReadNextRecInCategory (sd, handle, 4, record4, NULL, NULL, NULL);
	CHECK_RESULT(dlp_ReadNextRecInCategory)
	if (memcmp(record1, record4->data, sizeof(record1) != 0)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST dlp_ReadNextRecInCategory mismatch\n"));
		goto error;
	}
	
	/* Delete records in various ways */
	result = dlp_DeleteRecord (sd, handle, 0, rid1);
	CHECK_RESULT(dlp_DeleteRecord <Single>);
	result = dlp_ReadRecordById (sd, handle, rid1, record4, NULL, NULL, NULL);
	if (result >= 0) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Deleted record could still be read\n"));
		goto error;
	}
	result = dlp_DeleteCategory (sd, handle, 3);
	CHECK_RESULT(dlp_DeleteCategory);
	result = dlp_ReadRecordById (sd, handle, rid3, record4, NULL, NULL, NULL);
	if (result >= 0) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Deleted category could still be read\n"));
		goto error;
	}
	result = dlp_DeleteRecord (sd, handle, 1, 0);
	CHECK_RESULT(dlp_DeleteRecord <All>);
	result = dlp_ReadRecordById (sd, handle, rid2, record4, NULL, NULL, NULL);
	if (result >= 0) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Deleted all record could still be read\n"));
		goto error;
	}

	result = dlp_CloseDB (sd, handle);
	CHECK_RESULT(dlp_CloseDB);
	result = dlp_DeleteDB (sd, 0, "TestRecord");
	CHECK_RESULT(dlp_DeleteDB);

	/*********************************************************************
	 *
	 * Test: Resource
	 *
	 * Direct Testing Functions:
	 *   dlp_WriteResource
	 *   dlp_ReadResourceByType
	 *   dlp_ReadResourceByIndex
	 *   dlp_DeleteResource
	 *
	 * Indirect Testing Functions:
	 *   dlp_CreateDB
	 *   dlp_CloseDB
	 *   dlp_DeleteDB
	 *
	 *********************************************************************/
	memset (ires1, '\0', sizeof (ires1));
	memset (dres1, '\0', sizeof (dres1));
	ires1[3] = 'T';
	dres1[4] = 'T';

	result = dlp_CreateDB (sd, CREATOR, DATA, 0, dlpDBFlagResource, 1, "TestResource", &handle);
	CHECK_RESULT(dlp_CreateDB);

	/* Write out some resources */
	result = dlp_WriteResource (sd, handle, INFO, 1, ires1, sizeof(ires1));
	CHECK_RESULT(dlp_WriteResource);
	result = dlp_WriteResource (sd, handle, DATA, 0, dres1, sizeof(dres1));
	CHECK_RESULT(dlp_WriteResource);

	/* Read in the resources by various methods */
	result = dlp_ReadResourceByType (sd, handle, INFO, 1, ires2, &index);
	CHECK_RESULT(dlp_ReadResourceByType)
	if (memcmp(ires1, ires2->data, sizeof(ires1) != 0)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Resource by type mismatch\n"));
		goto error;
	}
	result = dlp_ReadResourceByIndex (sd, handle, index, ires2, &type, &id_);
	CHECK_RESULT(dlp_ReadResourceByIndex)
	if (memcmp(ires1, ires2->data, sizeof(ires1) != 0)) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Resource by index mismatch\n"));
		goto error;
	}
	if (type != INFO) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Resource by index return type mismatch\n"));
		goto error;
	}
	if (id_ != 1) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Resource by index return id mismatch\n"));
		goto error;
	}

	/* Delete resources by the various methods */
	result = dlp_DeleteResource (sd, handle, 0, INFO, 1);
	CHECK_RESULT(dlp_DeleteResource <Single>)
	result = dlp_ReadResourceByType (sd, handle, INFO, 1, ires2, &index);
	if (result >= 0) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Deleted resource could still be read\n"));
		goto error;
	}
	result = dlp_DeleteResource (sd, handle, 1, INFO, 1);
	CHECK_RESULT(dlp_DeleteResource <All>)
	result = dlp_ReadResourceByType (sd, handle, DATA, 0, dres2, &index);
	if (result >= 0) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Deleted all resource could still be read\n"));
		goto error;
	}

	result = dlp_CloseDB (sd, handle);
	CHECK_RESULT(dlp_CloseDB)
	result = dlp_DeleteDB (sd, 0, "TestResource");
	CHECK_RESULT(dlp_DeleteDB)

	/*********************************************************************
	 *
	 * Test: Database Cleanup
	 *
	 * Direct Testing Functions:
	 *   dlp_CleanUpDatabase
	 *   dlp_ResetSyncFlags
	 *
	 * Indirect Testing Functions:
	 *   dlp_CreateDB
	 *   dlp_WriteRecord
	 *   dlp_CloseDB
	 *   dlp_DeleteDB
	 *
	 *********************************************************************/
	result = dlp_CreateDB (sd, CREATOR, DATA, 0, 0, 1, "TestRecord", &handle);
	CHECK_RESULT(dlp_CreateDB);

	/* Create dummy records */
	result = dlp_WriteRecord (sd, handle, dlpRecAttrDeleted, 0, 0, record1, sizeof(record1), &rid1);
	CHECK_RESULT(dlp_WriteRecord);
	result = dlp_WriteRecord (sd, handle, dlpRecAttrDirty, 0, 0, record2, sizeof(record2), &rid2);
	CHECK_RESULT(dlp_WriteRecord);

	/* Call the test functions */
	result = dlp_CleanUpDatabase (sd, handle);
	CHECK_RESULT(dlp_CleanUpDatabase);
	result = dlp_ResetSyncFlags (sd, handle);
	CHECK_RESULT(dlp_ResetSyncFlags);

	result = dlp_CloseDB (sd, handle);
	CHECK_RESULT(dlp_CloseDB);

	/* Confirm the test functions worked */
	result = dlp_OpenDB (sd, 0, dlpOpenReadWrite, "TestRecord", &handle);
	CHECK_RESULT(dlp_OpenDB);

	result = dlp_ReadRecordById (sd, handle, rid1, record4, NULL, NULL, NULL);
	if (result >= 0) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Cleaned up record could still be read\n"));
		goto error;
	}
	result = dlp_ReadNextModifiedRec (sd, handle, record4, NULL, NULL, NULL, NULL);
	if (result >= 0) {
		LOG((PI_DBG_USER, PI_DBG_LVL_ERR, "DLPTEST Modified recorded could still be read\n"));
		goto error;
	}

	result = dlp_CloseDB (sd, handle);
	CHECK_RESULT(dlp_CloseDB);
	result = dlp_DeleteDB (sd, 0, "TestRecord");
	CHECK_RESULT(dlp_DeleteDB);

	/*********************************************************************
	 *
	 * Test: Sync Log
	 *
	 * Direct Testing Functions:
	 *   dlp_AddSyncLogEntry
	 *
	 * Indirect Testing Functions:
	 *   None
	 *
	 *********************************************************************/
	result = dlp_AddSyncLogEntry (sd, "dlp-test added sync log entry");
	CHECK_RESULT(dlp_AddSyncLogEntry);

	/*********************************************************************
	 *
	 * Test: End Sync
	 *
	 * Direct Testing Functions:
	 *   dlp_EndOfSync
	 *
	 * Indirect Testing Functions:
	 *   None
	 *
	 *********************************************************************/
	result = dlp_EndOfSync (sd, dlpEndCodeNormal);
	CHECK_RESULT(dlp_EndOfSync);

	t1 = time (NULL);
	LOG((PI_DBG_USER, PI_DBG_LVL_INFO, "DLPTEST Ending at %s", ctime (&t1)));

 error:
	pi_close (sd);
	pi_buffer_free (record4);
	pi_buffer_free (ires2);
	pi_buffer_free (dres2);
	pi_buffer_free(appblock);
	return 0;
}