Calendar-CSA
    
    
  
  
  
view release on metacpan or search on metacpan
	X_DT_ENTRY_ATTR_ENTRY_DELIMITER
	X_DT_ENTRY_ATTR_REPEAT_INTERVAL
	X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM
	X_DT_ENTRY_ATTR_REPEAT_TIMES
	X_DT_ENTRY_ATTR_REPEAT_TYPE
	X_DT_ENTRY_ATTR_SEQUENCE_END_DATE
	X_DT_ENTRY_ATTR_SHOWTIME
);
@EXPORT_OK = qw(
	logon
	list_calendars
);
$VERSION = '0.8';
sub AUTOLOAD {
    # This AUTOLOAD is used to 'autoload' constants from the constant()
    # XS function.  If a constant is not found then control is passed
    # to the AUTOLOAD in AutoLoader.
    my $constname;
    ($constname = $AUTOLOAD) =~ s/.*:://;
	PUSHMARK(sp);
	for(i=1;i<=av_len(args);i++)
		XPUSHs(sv_2mortal(newSVsv(*av_fetch(args, i, 0))));
	{
#ifdef CSA_DEBUG
		printf("Dealing with callback type %d, tag %d\n", reason, callback);
#endif
		if (reason & CSA_CB_CALENDAR_LOGON) {
			CSA_logon_callback_data * data = call_data;
			XPUSHs(sv_2mortal(newSVpv("CALENDAR LOGON", 0)));
			XPUSHs(sv_2mortal(newSVCSA_calendar_user(data->user)));
		}
		if (reason & CSA_CB_CALENDAR_DELETED) {
			CSA_calendar_deleted_callback_data * data = call_data;
			XPUSHs(sv_2mortal(newSVpv("CALENDAR DELETED", 0)));
			XPUSHs(sv_2mortal(newSVCSA_calendar_user(data->user)));
		}
		if (reason & CSA_CB_CALENDAR_ATTRIBUTE_UPDATED) {
			CSA_calendar_attr_update_callback_data * data = call_data;
			XPUSHs(sv_2mortal(newSVpv("CALENDAR ATTRIBUTE UPDATED", 0)));
			XPUSHs(sv_2mortal(newSVCSA_calendar_user(data->user)));
			for (j=0;j<data->number_attributes;j++)
				XPUSHs(sv_2mortal(newSVpv(data->attribute_names[j], 0)));
		}
		if (reason & CSA_CB_ENTRY_ADDED) {
			CSA_add_entry_callback_data * data = call_data;
			XPUSHs(sv_2mortal(newSVpv("ENTRY ADDED", 0)));
			XPUSHs(sv_2mortal(newSVCSA_calendar_user(data->user)));
			XPUSHs(sv_2mortal(newSVCSA_opaque_data(&data->added_entry_id)));
		}
		if (reason & CSA_CB_ENTRY_DELETED) {
			CSA_delete_entry_callback_data * data = call_data;
			XPUSHs(sv_2mortal(newSVpv("ENTRY DELETED", 0)));
			XPUSHs(sv_2mortal(newSVCSA_calendar_user(data->user)));
			XPUSHs(sv_2mortal(newSVCSA_opaque_data(&data->deleted_entry_id)));
			XPUSHs(sv_2mortal(newSVCSA_SCOPE(data->scope)));
			XPUSHs(sv_2mortal(newSVISO_date_time(data->date_and_time,0)));
		}
		if (reason & CSA_CB_ENTRY_UPDATED) {
			CSA_update_entry_callback_data * data = call_data;
			XPUSHs(sv_2mortal(newSVpv("ENTRY UPDATED", 0)));
			XPUSHs(sv_2mortal(newSVCSA_calendar_user(data->user)));
			XPUSHs(sv_2mortal(newSVCSA_opaque_data(&data->old_entry_id)));
			XPUSHs(sv_2mortal(newSVCSA_opaque_data(&data->new_entry_id)));
			XPUSHs(sv_2mortal(newSVCSA_SCOPE(data->scope)));
			XPUSHs(sv_2mortal(newSVISO_date_time(data->date_and_time,0)));
		}
	}
	PUTBACK ;
	perl_call_sv(*av_fetch(args, 0, 0), G_DISCARD);
}
			RETVAL = newSVpv(s, 0);
		else {
			RETVAL = newSViv(constantint(name,arg));
		}
	}
	OUTPUT:
	RETVAL
void
add_calendar(user, ...)
	SV *	user
	CODE:
	{
		int i, j, err;
		CSA_calendar_user u;
		CSA_attribute * csa_attrs;
		
		if ((items-1)%2)
			croak("attributes must be paired names and values");
		SvCSA_calendar_user(user, &u);	
		
		if (items>1) {
			csa_attrs = safe_calloc(sizeof(CSA_attribute)*((items-1)/2), 1);
			for(j=0,i=1;i<items;j++,i+=2) {
				csa_attrs[j].name = lengthen(SvPV(ST(i),na));
				csa_attrs[j].value = SvCSA_attribute_value(ST(i+1), 0);
			}
		} else
			csa_attrs = 0;
		err = csa_add_calendar((CSA_session_handle)NULL, &u, (items-1)/2, csa_attrs, NULL);
		
		if (csa_attrs)
			free(csa_attrs);
		
		if (err)
			CsaCroak("add_calendar", err);
	}
Calendar::CSA::Session
logon(service=0, user=0, password=0, charset=0)
	char *	service
	SV *	user
	char *	password
	char *	charset
	CODE:
	{
		Calendar__CSA__Session session = safe_calloc(sizeof(struct Calendar__CSA__Session_t),1);
		CSA_return_code ret;
		CSA_calendar_user cu;
	
		if (service && !strlen(service))
			service = 0;
		
		ret =
		csa_logon(service,
			  SvCSA_calendar_user(user, &cu),
			  password,
			  charset, 
			  "-//XAPIA/CSA/VERSION1/NONSGML CSA Version 1//EN",
			  &session->session,
			  NULL);
	
		session->iso_times = 1;
		if (ret != CSA_SUCCESS)
		{
			CsaCroak("logon", ret);
		}
		
		session->connected = 1;
		RETVAL = session;
	}
	OUTPUT:
	RETVAL
void
list_calendars(service=0)
	char *	service
	PPCODE:
	{
		CSA_calendar_user *result;
		CSA_uint32 number;
		int err,i;
		SV ** s;
		HV * u;
		
		number = 0;
		
		err = csa_list_calendars(service, &number, &result, NULL);
		if (err)
			CsaCroak("list_calendars", err);
		
		if (result) {
			for(i=0;i<number;i++) {
				EXTEND(sp, 1);
				PUSHs(sv_2mortal(newSVpv(result[i].calendar_address,0)));
			}
			csa_free(result);
		}
	}
int
accept_numeric_enumerations(set=&sv_undef)
	SV *	set
	CODE:
	{
	OUTPUT:
	RETVAL
void
look_up(session, users, flags=0)
	Calendar::CSA::Session	session
	SV *	users
	SV *	flags
	PPCODE:
	{
		CSA_calendar_user user, *result;
		CSA_uint32 number;
		int err,i;
		SvCSA_calendar_user(users, &user);
		number = 1;
		
		err = csa_look_up(session->session, &user, SvCSA_LOOKUP(flags), &number, &result, NULL);
		if (err)
			CsaCroak("look_up", err);
			
		for(i=0;i<number;i++) {
			EXTEND(sp, 1);
			PUSHs(sv_2mortal(newSVCSA_calendar_user(result+i)));
		}
		
		csa_free(result);
	}
void
query_configuration(session, item)
	Calendar::CSA::Session	session
	SV *	item
	PPCODE:
	{
		CSA_calendar_user user, *result;
		CSA_uint32 number;
		int err=0,i;
		i = SvOpt(item, "configuration item", configs);
		switch (i) {
		case CSA_CONFIG_CHARACTER_SET:
		  {
			char ** data;
			err = csa_query_configuration(session->session, CSA_CONFIG_CHARACTER_SET, (void**)&data, NULL);
			if (err) goto done;
			csa_free(data);
		default:
			croak("unhandled configuration query");
		}
    done:
		if (err)
			CsaCroak("query_configuration", err);
	}
void
list_calendar_attributes(session)
	Calendar::CSA::Session	session
	PPCODE:
	{
		CSA_attribute_reference *result;
		CSA_uint32 number;
		int err,i;
		SV ** s;
		HV * u;
		
		number = 0;
		
		err = csa_list_calendar_attributes(session->session, &number, &result, NULL);
		if (err)
			CsaCroak("list_calendar_attributes", err);
		
		if (result) {
			for(i=0;i<number;i++) {
				EXTEND(sp, 1);
				PUSHs(sv_2mortal(newSVpv(shorten(result[i], session->shorten),0)));
			}
			csa_free(result);
		}
	}
void
read_calendar_attributes(session, ...)
	Calendar::CSA::Session	session
	PPCODE:
	{
		int i, j, err;
		int flags=0;
		CSA_uint32 count;
		CSA_attribute * result;
		CSA_attribute_reference * csa_names;
		if (items>1) {
			csa_names = safe_calloc(sizeof(CSA_attribute_reference)*(items-1),1);
			for(i=1;i<items;i++)
				csa_names[i-1] = lengthen(SvPV(ST(i), na));
		} else {
			csa_names = 0;
		}
		err = csa_read_calendar_attributes(session->session, items-1, csa_names, &count, &result, NULL);
		
		if (csa_names)
			free(csa_names);
		
		if (err)
			CsaCroak("read_calendar_attributes", err);
		
		if (result) {
			for(i=0;i<count;i++) {
				EXTEND(sp, 2);
				PUSHs(sv_2mortal(newSVpv(shorten(result[i].name,session->shorten), 0)));
				PUSHs(sv_2mortal(newSVCSA_attribute_value(result[i].value, session->shorten, session->iso_times)));
			}
			csa_free(result);
		}
	}
		if (result) {
			for(i=0;i<count;i++) {
				EXTEND(sp, 1);
				PUSHs(sv_2mortal(newSVCSA_reminder_reference(result+i, session, ST(0))));
			}
			csa_free(result);
		}
	}
void
update_calendar_attributes(session, ...)
	Calendar::CSA::Session	session
	CODE:
	{
		int i,j, err;
		CSA_attribute * csa_attrs;
		if ((items-1)%2)
			croak("attributes must be paired names and values");
		if (items>1) {
			csa_attrs = safe_calloc(sizeof(CSA_attribute)*((items-1)/2), 1);
			for(j=0,i=1;i<items;j++,i+=2) {
				csa_attrs[j].name = lengthen(SvPV(ST(i),na));
				csa_attrs[j].value = SvCSA_attribute_value(ST(i+1), 0);
			}
		} else
			csa_attrs = 0;
		err = csa_update_calendar_attributes(session->session, items-1, csa_attrs, NULL);
		
		if (csa_attrs)
			free(csa_attrs);
		
		if (err)
			CsaCroak("update_calendar_attributes", err);
	}
void
add_calendar(session, user, ...)
	Calendar::CSA::Session	session
	SV *	user
	CODE:
	{
		int i, j, err;
		CSA_calendar_user u;
		CSA_attribute * csa_attrs;
		
		if ((items-2)%2)
			croak("attributes must be paired names and values");
		
		SvCSA_calendar_user(user, &u);	
		
		if (items>2) {
			csa_attrs = safe_calloc(sizeof(CSA_attribute)*((items-2)/2), 1);
			for(j=0,i=2;i<items;j++,i+=2) {
				csa_attrs[j].name = lengthen(SvPV(ST(i),na));
				csa_attrs[j].value = SvCSA_attribute_value(ST(i+1), 0);
			}
		} else
			csa_attrs = 0;
		err = csa_add_calendar(session->session, &u, (items-2)/2, csa_attrs, NULL);
		
		if (csa_attrs)
			free(csa_attrs);
		
		if (err)
			CsaCroak("add_calendar", err);
	}
void
free_time_search(session, range, duration, calendar,...)
	Calendar::CSA::Session	session
	SV *	range
	SV *	duration
	SV *	calendar
	PPCODE:
	{
		int i, j, err;
		CSA_uint32 count;
		CSA_free_time * result;
		CSA_calendar_user * csa_users;
		if (items>3) {
			csa_users = safe_malloc(sizeof(CSA_calendar_user)*(items-3));
			for(i=3;i<items;i++)
				SvCSA_calendar_user(ST(i), &csa_users[i-3]);
		} else
			csa_users = 0;
			
		err = csa_free_time_search(session->session, SvISO_date_time_range(range,0), SvISO_time_duration(duration,0), items-3, csa_users, &result, NULL);
		
		if (csa_users)
			free(csa_users);
		
		if (err)
			CsaCroak("free_time_search", err);
			for(i=0;i<result->number_free_time_data;i++) {
				EXTEND(sp, 1);
				PUSHs(sv_2mortal(newSVISO_date_time(result->free_time_data[i], 0)));
			}
			csa_free(result);
		}
	}
void
delete_calendar(session)
	Calendar::CSA::Session	session
	CODE:
	{
		int err = csa_delete_calendar(session->session, NULL);
		if (err)
			CsaCroak("delete_calendar", err);
	}
int
register_callback(session, mode, callback, ...)
	Calendar::CSA::Session	session
	SV *	mode
	SV *	callback
	CODE:
	{
0.01  Fri Aug  8 16:02:51 1997
	- original version; created by h2xs 1.16
0.5   Wed Sep  3 14:49:00 1997
	- First proposed release version
0.7   Sun Sep 14 17:00:13 1997
	- Added patches from Bharat to corect memory & stack allocations.
0.8   Mon Oct  6 17:50:48 1997
	- Added sessionless add_calendar command, fixed an add_calendar bug, and
	  fixed "CALENDAR NOT_EXIST" error.
		buffer[63] = '\0';
		
		if (strlen(buffer)==0)
			return 0;
	}
	
	return buffer;
}
SV * newSVCSA_calendar_user(CSA_calendar_user * user)
{
	HV * u;
	SV * r;
	if (!user)
		return newSVsv(&sv_undef);
	u = newHV();
	if (user->user_name)
		hv_store(u, "user_name", 9, newSVpv(user->user_name,0), 0);
	if (user->calendar_address)
		hv_store(u, "calendar_address", 16, newSVpv(user->calendar_address,0), 0);
	if (user->calendar_address ||
		user->user_name ||
		user->user_type)
		hv_store(u, "user_type", 9, newSVCSA_USER_TYPE(user->user_type), 0);
	r = newRV((SV*)u);
	SvREFCNT_dec(u);
	return r;
}
CSA_calendar_user * SvCSA_calendar_user(SV * user, CSA_calendar_user * target)
{
	HV * u = (HV*)SvRV(user);
	SV ** s;
	
	if (!user || !SvOK(user))
		return 0;
	
	if (!target)
		target = alloc_temp(sizeof(CSA_calendar_user));
	if ((s=hv_fetch(u, "user_name", 9, 0)) && SvOK(*s))
		target->user_name = SvPV(*s, na);
	else
		target->user_name = 0;
	if ((s=hv_fetch(u, "calendar_address", 16, 0)) && SvOK(*s))
		target->calendar_address = SvPV(*s, na);
	else
		target->calendar_address = 0;
	if ((s=hv_fetch(u, "user_type", 9, 0)) && SvOK(*s))
		target->user_type = SvCSA_USER_TYPE(*s);
	else
		target->user_type = 0;
	return target;
}
static struct opts rights[] = {
	{CSA_FREE_TIME_SEARCH, "FREE TIME SEARCH"},
	{CSA_VIEW_PUBLIC_ENTRIES, "VIEW PUBLIC ENTRIES"},
};
SV * newSVCSA_access_rights(CSA_access_rights * right)
{
	HV * u;
	SV * r;
	int i;
	if (!right)
		return newSVsv(&sv_undef);
	u = newHV();
	hv_store(u, "user", 4, newSVCSA_calendar_user(right->user), 0);
	hv_store(u, "rights", 6, newSVOptFlags(right->rights, "rights", rights, 1), 0);
	r = newRV((SV*)u);
	SvREFCNT_dec(u);
	return r;
}
CSA_access_rights * SvCSA_access_rights(SV * data, CSA_access_rights * target)
{	
	HV * h;
	SV ** s;
	
	if (!data || !SvOK(data))
		return 0;
		
	if (!target)
		target = alloc_temp(sizeof(CSA_access_rights));
	h = (HV*)SvRV(data);
	
	if ((s = hv_fetch(h, "user", 4, 0)) && SvOK(*s))
		target->user = SvCSA_calendar_user(*s, 0);
	else
		target->user = 0;
	target->rights = 0;
	if ((s = hv_fetch(h, "rights", 6, 0)) && SvOK(*s))
		target->rights = SvOptFlags(*s, "rights", rights);
	return target;
}
SV * newSVCSA_access_list(CSA_access_list list)
{	
SV * newSVCSA_attendee(CSA_attendee * attendee)
{
	HV * u;
	HV * flags;
	SV * r;
	int i;
	if (!attendee)
		return newSVsv(&sv_undef);
	u = newHV();
	flags = newHV();
	hv_store(u, "attendee", 8, newSVCSA_calendar_user(&attendee->attendee), 0);
	hv_store(u, "rsvp_requested", 14, newSViv(attendee->rsvp_requested),0);
	hv_store(u, "status", 6, newSVOpt(attendee->status, "status", statuses), 0);
	hv_store(u, "priority", 8, newSVOpt(attendee->status, "priority", priorities), 0);
	r = newRV((SV*)u);
	SvREFCNT_dec(u);
	return r;
}
SV * newSVCSA_attendee_list(CSA_attendee_list list)
{	
	case CSA_VALUE_SINT32:
		value = newSViv(attr->item.sint32_value);
		break;
	case CSA_VALUE_UINT32:
		value = newSViv(attr->item.uint32_value);
		break;
	case CSA_VALUE_STRING:
		value = newSVpv(shorten(attr->item.string_value, doshorten), 0);
		break;
	case CSA_VALUE_CALENDAR_USER:
		value = newSVCSA_calendar_user(attr->item.calendar_user_value);
		break;
	case CSA_VALUE_DATE_TIME:
		value = newSVISO_date_time(attr->item.date_time_value, doiso_times);
		break;
	case CSA_VALUE_DATE_TIME_RANGE:
		value = newSVISO_date_time_range(attr->item.date_time_range_value, doiso_times);
		break;
	case CSA_VALUE_TIME_DURATION:
		value = newSVISO_time_duration(attr->item.time_duration_value, doiso_times);
		break;
	case CSA_VALUE_SINT32:
		target->item.sint32_value = SvIV(*s);
		break;
	case CSA_VALUE_UINT32:
		target->item.uint32_value = SvIV(*s);
		break;
	case CSA_VALUE_STRING:
		target->item.string_value = lengthen(SvPV(*s, na));
		break;
	case CSA_VALUE_CALENDAR_USER:
		target->item.calendar_user_value = SvCSA_calendar_user(*s, 0);
		break;
	case CSA_VALUE_DATE_TIME:
		target->item.date_time_value = SvISO_date_time(*s, 0);
		break;
	case CSA_VALUE_DATE_TIME_RANGE:
		target->item.date_time_range_value = SvISO_date_time_range(*s, 0);
		break;
	case CSA_VALUE_TIME_DURATION:
		target->item.time_duration_value = SvISO_time_duration(*s, 0);
		break;
  */
struct opts {
	int value;
	char * name;
};
void * Csa_safe_malloc(int size);
void * Csa_safe_calloc(int nelems, size_t elsize);
char * CsaError(int error);
void CsaCroak(char * routine, int err);
SV * newSVCSA_calendar_user(CSA_calendar_user * user);
CSA_calendar_user * SvCSA_calendar_user(SV * user, CSA_calendar_user * target);
SV * newSVCSA_access_rights(CSA_access_rights * right);
SV * newSVCSA_access_list(CSA_access_list list);
CSA_access_rights * SvCSA_access_rights(SV * data, CSA_access_rights * rights);
CSA_access_list SvCSA_access_list(SV * data, CSA_access_list list);
SV * newSVCSA_attendee(CSA_attendee * attendee);
SV * newSVCSA_attendee_list(CSA_attendee_list list);
SV * newSVCSA_date_time_list(CSA_date_time_list list, int doiso_times);
CSA_date_time_list SvCSA_date_time_list(SV * data, CSA_date_time_list target);
SV * newSVCSA_opaque_data(CSA_opaque_data * data);
CSA_opaque_data * SvCSA_opaque_data(SV * data, CSA_opaque_data * target);
print "Attempting to open database $user\@$host...\n";
$caladdr = "$user\@$host";
($user, $host) = split(/@/, $caladdr);
print "Logging on...\n";
$session = Calendar::CSA::logon("",
	{	user_name => $caladdr,
		user_type => 'INDIVIDUAL',
		calendar_address => $caladdr
	} );
# Turn long standard names into short non-standard names
$session->short_entry_names(1);
# Turn ISO times into UNIX times
$session->unix_times(1);
print "VER SPEC: ",$session->query_configuration("VER SPEC"),"\n";
print "UI AVAIL: ",$session->query_configuration("UI AVAIL"),"\n";
eval
{
    print "Calendars: ", join(", ", Calendar::CSA::list_calendars($host)),"\n";
};
print ($@) if ($@);
print "Calendar attributes: ",join(", ", $session->list_calendar_attributes),"\n";
print "Number of entries: ", $session->read_calendar_attributes("Number Entries")->{value},"\n";
$entrylist = $session->list_entries(
	'Start Date' => {
    	type => 'DATE TIME',
       value => '19940101T010654Z',
        match => 'GREATER THAN'
    },
	'Start Date' => {
    	type => 'DATE TIME',
        value => '19991230T010654Z',
__END__;
# This is the original test code
use Data::Dumper;
print "Log on...\n";
$session = Calendar::CSA::logon("",
	{	user_name => $caladdr,
		user_type => 'INDIVIDUAL',
		calendar_address => $caladdr
	} );
$session->short_entry_names(1);
$session->unix_times(1);
#Calendar::CSA::generate_numeric_enumerations(1);	# 0 is default
#Calendar::CSA::accept_numeric_enumerations(1);	# 0 is default
#$user = $session->look_up({name => $user});
#print Dumper($user);
print "SUBTYPE_APPOINTMENT = '", Calendar::CSA::SUBTYPE_APPOINTMENT, "'\n";;
print Dumper([$session->query_configuration("VER SPEC")]);
print Dumper([$session->query_configuration("UI AVAIL")]);
eval
{
    print Dumper([Calendar::CSA::list_calendars($host)]);
};
print ($@) if ($@);
print Dumper([$session->list_calendar_attributes]);
print Dumper({$session->read_calendar_attributes});
eval
{
#	Segfaults on my machine, in addition to being unimplemented!
#	print Dumper([$session->free_time_search("19970816T040205Z/19970816T040225Z","+PT300S",{user_name=>$user})]);
};
print ($@) if ($@);
# Never been able to trigger a callback.
#$session->register_callback("ENTRY ADDED", sub { print "Callback: @_\n" }, "foo", 1);
( run in 0.371 second using v1.01-cache-2.11-cpan-5dc5da66d9d )