/*
 * $Id$
 *
 * address.c:  Translate Pilot address book data formats
 * (c) 1996, Kenneth Albanowski
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Library General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 * 
 * This library 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 Library
 * General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */


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

#include "pi-macros.h"
#include "pi-address.h"

#define hi(x) (((x) >> 4) & 0x0f)
#define lo(x) ((x) & 0x0f)
#define pair(x,y) (((x) << 4) | (y))

/***********************************************************************
 *
 * Function:    free_Address
 *
 * Summary:	Free the members of an address structure
 *
 * Parameters:  Address_t*
 *
 * Returns:     void
 *
 ***********************************************************************/
void
free_Address(Address_t *addr)
{
	int 	i;

	for (i = 0; i < 19; i++)
		if (addr->entry[i]) {
			free(addr->entry[i]);
			addr->entry[i] = NULL;
		}
}


/***********************************************************************
 *
 * Function:    unpack_Address
 *
 * Summary:     Fill in the address structure based on the raw record 
 *		data
 *
 * Parameters:  Address_t*, pi_buffer_t *buf
 *
 * Returns:     -1 on error, 0 on success
 *
 ***********************************************************************/
int
unpack_Address(Address_t *addr, const pi_buffer_t *buf, addressType type)
{
	unsigned long	contents,
			v;
	size_t		ofs,
			slen;

	if (type != address_v1)
		/* Don't support anything else yet */
		return -1;

	if (buf == NULL || buf->data == NULL || buf->used < 9)
		return -1;

	/* get_byte(buffer); gapfill */
	addr->showPhone     = hi(get_byte(buf->data + 1));
	addr->phoneLabel[4] = lo(get_byte(buf->data + 1));
	addr->phoneLabel[3] = hi(get_byte(buf->data + 2));
	addr->phoneLabel[2] = lo(get_byte(buf->data + 2));
	addr->phoneLabel[1] = hi(get_byte(buf->data + 3));
	addr->phoneLabel[0] = lo(get_byte(buf->data + 3));

	contents = get_long(buf->data + 4);

	/* get_byte(buf->data+8) offset */

	ofs = 9;

	/* if(flag & 0x1) { 
	   addr->lastname = strdup((buf->data + ofs);
	   ofs += strlen((buf->data + ofs)) + 1;
	   } else {
	   addr->lastname = 0;
	   } */

	for (v = 0; v < 19; v++) {
		if (contents & (1 << v)) {
			if ((buf->used - ofs) < 1)
				return 0;
			slen = strlen((char *) (buf->data + ofs));
			addr->entry[v] = strdup((char *) (buf->data + ofs));
			if (addr->entry[v] == NULL)
				return -1;
			ofs += slen + 1;
		} else {
			addr->entry[v] = 0;
		}
	}

	return 0;
}


/***********************************************************************
 *
 * Function:    pack_Address
 *
 * Summary:     Fill in the raw address record data based on the 
 *		address structure
 *
 * Parameters:  Address_t*, pi_buffer_t *buf of record, record type
 *
 * Returns:     -1 on error, 0 on success.
 *
 ***********************************************************************/
int
pack_Address(const Address_t *addr, pi_buffer_t *buf, addressType type)
{
	unsigned int	l,
			destlen = 9;

	unsigned char *buffer;
	unsigned long 	contents,
			v,
			phoneflag;

	unsigned char offset;

	if (addr == NULL || buf == NULL)
		return -1;

	if (type != address_v1)
		/* Don't support anything else yet */
		return -1;

	for (v = 0; v < 19; v++)
		if (addr->entry[v] && strlen(addr->entry[v]))
			destlen += strlen(addr->entry[v]) + 1;

	pi_buffer_expect (buf, destlen);
	buf->used = destlen;

	buffer 		= buf->data + 9;
	phoneflag 	= 0;
	contents 	= 0;
	offset 		= 0;

	for (v = 0; v < 19; v++) {
		if (addr->entry[v] && strlen(addr->entry[v])) {
			if (v == entryCompany)
				offset =
				    (unsigned char) (buffer - buf->data) - 8;
			contents |= (1 << v);
			l = strlen(addr->entry[v]) + 1;
			memcpy(buffer, addr->entry[v], l);
			buffer += l;
		}
	}

	phoneflag = ((unsigned long) addr->phoneLabel[0]) << 0;
	phoneflag |= ((unsigned long) addr->phoneLabel[1]) << 4;
	phoneflag |= ((unsigned long) addr->phoneLabel[2]) << 8;
	phoneflag |= ((unsigned long) addr->phoneLabel[3]) << 12;
	phoneflag |= ((unsigned long) addr->phoneLabel[4]) << 16;
	phoneflag |= ((unsigned long) addr->showPhone) << 20;

	set_long(buf->data, phoneflag);
	set_long(buf->data + 4, contents);
	set_byte(buf->data + 8, offset);

	return 0;
}


/***********************************************************************
 *
 * Function:    unpack_AddressAppInfo
 *
 * Summary:     Fill in the app info structure based on the raw app 
 *		info data
 *
 * Parameters:  AddressAppInfo_t*, char * to record, record length
 *
 * Returns:     The necessary length of the buffer if record is NULL,
 *		or 0 on error, the length of the data used from the 
 *		buffer otherwise
 *
 ***********************************************************************/
int
unpack_AddressAppInfo(AddressAppInfo_t *ai, const unsigned char *record, size_t len)
{
	size_t 	i,
		destlen = 4 + 16 * 22 + 2 + 2;

	const unsigned char *start = record;
	unsigned long r;

	ai->type = address_v1;

	i = unpack_CategoryAppInfo(&ai->category, record, len);
	if (!record)
		return i + destlen;
	if (!i)
		return i;
	record += i;
	len -= i;

	if (len < destlen)
		return 0;

	r = get_long(record);
	for (i = 0; i < 22; i++)
		ai->labelRenamed[i] = !!(r & (1 << i));

	record += 4;
	memcpy(ai->labels, record, 16 * 22);
	record += 16 * 22;
	ai->country = get_short(record);
	record += 2;
	ai->sortByCompany = get_byte(record);
	record += 2;

	for (i = 3; i < 8; i++)
		strcpy(ai->phoneLabels[i - 3], ai->labels[i]);
	for (i = 19; i < 22; i++)
		strcpy(ai->phoneLabels[i - 19 + 5], ai->labels[i]);

	return (record - start);
}

/***********************************************************************
 *
 * Function:    pack_AddressAppInfo
 *
 * Summary:     Fill in the raw app info record data based on the app
 *		info structure
 *
 * Parameters:  AddressAppInfo_t*, char * to record, record length
 *
 * Returns:     The length of the buffer required if record is NULL,
 *		or 0 on error, the length of the data used from the
 *		buffer otherwise
 *
 ***********************************************************************/
int
pack_AddressAppInfo(const AddressAppInfo_t *ai, unsigned char *record, size_t len)
{
	int 	i;
	size_t	destlen = 4 + 16 * 22 + 2 + 2;
	unsigned char *pos = record;
	unsigned long r;

	i = pack_CategoryAppInfo(&ai->category, record, len);
	if (!record)
		return destlen + i;
	if (!i)
		return i;

	pos += i;
	len -= i;

	/* Note: phoneLabels are kept in sync with labels[] by
	 * unpack_AddressAppInfo(); no need to re-sync here, and we
	 * cannot write through `ai` since it is const-qualified.
	 */

	memset(pos, 0, destlen);

	r = 0;
	for (i = 0; i < 22; i++)
		if (ai->labelRenamed[i])
			r |= (1 << i);
	set_long(pos, r);
	pos += 4;

	memcpy(pos, ai->labels, 16 * 22);
	pos += 16 * 22;
	set_short(pos, ai->country);
	pos += 2;
	set_byte(pos, ai->sortByCompany);
	pos += 2;

	return (pos - record);
}

/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */
/* ex: set tabstop=4 expandtab: */
/* Local Variables: */
/* indent-tabs-mode: t */
/* c-basic-offset: 8 */
/* End: */
