#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif
/*
Copyright (c) 1997 Kenneth Albanowski. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
*/
extern int _csa_iso8601_to_tick(char *, time_t *);
extern int _csa_tick_to_iso8601(time_t, char *);
extern int _csa_iso8601_to_range(char *, time_t *, time_t *);
extern int _csa_range_to_iso8601(time_t, time_t, char *);
extern int _csa_iso8601_to_duration(char *, time_t *);
extern int _csa_duration_to_iso8601(time_t, char *);
#include <csa/csa.h>
#include "CsaUtils.h"
char * CsaError(int error)
{
switch(error) {
case CSA_E_AMBIGUOUS_USER: return "AMBIGUOUS USER";
case CSA_E_CALENDAR_EXISTS: return "CALENDAR EXISTS";
case CSA_E_CALENDAR_NOT_EXIST: return "CALENDAR NOT EXIST";
case CSA_E_CALLBACK_NOT_REGISTERED: return "CALLBACK NOT REGISTERED";
case CSA_E_DISK_FULL: return "DISK FULL";
case CSA_E_FAILURE: return "FAILURE";
case CSA_E_FILE_EXIST: return "FILE EXIST";
case CSA_E_FILE_NOT_EXIST: return "FILE NOT EXIST";
case CSA_E_INSUFFICIENT_MEMORY: return "INSUFFICIENT MEMORY";
case CSA_E_INVALID_ATTRIBUTE: return "INVALID ATTRIBUTE";
case CSA_E_INVALID_ATTRIBUTE_VALUE: return "INVALID ATTRIBUTE VALUE";
case CSA_E_INVALID_CALENDAR_SERVICE: return "INVALID CALENDAR SERVICE";
case CSA_E_INVALID_CONFIGURATION: return "INVALID CONFIGURATION";
case CSA_E_INVALID_DATA_EXT: return "INVALID DATA EXT";
case CSA_E_INVALID_DATE_TIME: return "INVALID DATE TIME";
case CSA_E_INVALID_ENTRY_HANDLE: return "INVALID ENTRY HANDLE";
case CSA_E_INVALID_ENUM: return "INVALID ENUM";
case CSA_E_INVALID_FILE_NAME: return "INVALID FILE NAME";
case CSA_E_INVALID_FLAG: return "INVALID FLAG";
case CSA_E_INVALID_FUNCTION_EXT: return "INVALID FUNCTION EXT";
case CSA_E_INVALID_MEMORY: return "INVALID MEMORY";
case CSA_E_INVALID_PARAMETER: return "INVALID PARAMETER";
case CSA_E_INVALID_PASSWORD: return "INVALID PASSWORD";
case CSA_E_INVALID_RULE: return "INVALID RULE";
case CSA_E_INVALID_SESSION_HANDLE: return "INVALID SESSION HANDLE";
case CSA_E_INVALID_USER: return "INVALID USER";
case CSA_E_NO_AUTHORITY: return "NO AUTHORITY";
case CSA_E_NOT_SUPPORTED: return "NOT SUPPORTED";
case CSA_E_PASSWORD_REQUIRED: return "PASSWORD REQUIRED";
case CSA_E_READONLY: return "READONLY";
case CSA_E_SERVICE_UNAVAILABLE: return "SERVICE UNAVAILABLE";
case CSA_E_TEXT_TOO_LARGE: return "TEXT TOO LARGE";
case CSA_E_TOO_MANY_USERS: return "TOO MANY USERS";
case CSA_E_UNABLE_TO_OPEN_FILE: return "UNABLE TO OPEN FILE";
case CSA_E_UNSUPPORTED_ATTRIBUTE: return "UNSUPPORTED ATTRIBUTE";
case CSA_E_UNSUPPORTED_CHARACTER_SET: return "UNSUPPORTED CHARACTER SET";
case CSA_E_UNSUPPORTED_DATA_EXT: return "UNSUPPORTED DATA EXT";
case CSA_E_UNSUPPORTED_ENUM: return "UNSUPPORTED ENUM";
case CSA_E_UNSUPPORTED_FLAG: return "UNSUPPORTED FLAG";
case CSA_E_UNSUPPORTED_FUNCTION_EXT: return "UNSUPPORTED FUNCTION EXT";
case CSA_E_UNSUPPORTED_PARAMETER: return "UNSUPPORTED PARAMETER";
case CSA_E_UNSUPPORTED_VERSION: return "UNSUPPORTED VERSION";
case CSA_E_USER_NOT_FOUND: return "USER NOT FOUND";
#ifdef CSA_E_TIME_ONLY
case CSA_E_TIME_ONLY: return "TIME ONLY";
#endif
#ifdef CSA_X_DT_E_BACKING_STORE_PROBLEM
case CSA_X_DT_E_BACKING_STORE_PROBLEM: return "X-DT BACKING STORE PROBLEM";
#endif
#ifdef CSA_X_DT_E_ENTRY_NOT_FOUND
case CSA_X_DT_E_ENTRY_NOT_FOUND: return "X-DT ENTRY NOT FOUND";
#endif
#ifdef CSA_X_DT_E_INVALID_SERVER_LOCATION
case CSA_X_DT_E_INVALID_SERVER_LOCATION:return "X-DT INVALID SERVER LOCATION";
#endif
#ifdef CSA_X_DT_E_SERVER_TIMEOUT
case CSA_X_DT_E_SERVER_TIMEOUT: return "X-DT SERVER TIMEOUT";
#endif
#ifdef CSA_X_DT_E_SERVICE_NOT_REGISTERED
case CSA_X_DT_E_SERVICE_NOT_REGISTERED: return "X-DT SERVICE NOT REGISTERED";
#endif
default: return "UNKNOWN ERROR";
}
}
void CsaCroak(char * routine, int err)
{
croak("Csa %s failed: %s (%d)", routine, CsaError(err), err);
}
static void * alloc_temp(int size)
{
SV * s = sv_2mortal(newSVpv("",0));
SvGROW(s, size);
return SvPV(s, na);
}
void CroakOpts(char * name, char * value, struct opts * o)
{
SV * result = sv_newmortal();
char buffer[40];
int i;
sv_catpv(result, "invalid ");
sv_catpv(result, name);
sv_catpv(result, " ");
sv_catpv(result, value);
sv_catpv(result, ", expecting");
for(i=0;o[i].name;i++) {
if (i==0)
sv_catpv(result," '");
else if (o[i+1].name)
sv_catpv(result,"', '");
else
sv_catpv(result,"', or '");
sv_catpv(result, o[i].name);
}
sv_catpv(result,"'");
croak(SvPV(result, na));
}
int Csa_accept_numeric_enumerations = 0;
int Csa_generate_numeric_enumerations = 0;
long SvOpt(SV * name, char * optname, struct opts * o)
{
int i;
char * n = SvPV(name, na);
for(i=0;o[i].name;i++)
if (strEQ(o[i].name, n))
return o[i].value;
if (Csa_accept_numeric_enumerations && SvIOKp(name))
return SvIV(name);
CroakOpts(optname, n, o);
}
SV * newSVOpt(long value, char * optname, struct opts * o)
{
int i;
if (Csa_generate_numeric_enumerations)
return newSViv(value);
for(i=0;o[i].name;i++)
if (o[i].value == value)
return newSVpv(o[i].name, 0);
croak("invalid %s value %d", optname, value);
}
long SvOptFlags(SV * name, char * optname, struct opts * o)
{
int i;
int val=0;
if (SvRV(name) && (SvTYPE(SvRV(name)) == SVt_PVAV)) {
AV * r = (AV*)SvRV(name);
for(i=0;i<=av_len(r);i++)
val |= SvOpt(*av_fetch(r, i, 0), optname, o);
} else if (SvRV(name) && (SvTYPE(SvRV(name)) == SVt_PVHV)) {
HV * r = (HV*)SvRV(name);
/* This is bad, as we don't catch members with invalid names */
for(i=0;o[i].name;i++) {
SV ** s = hv_fetch(r, o[i].name, strlen(o[i].name), 0);
if (s && SvOK(*s) && SvTRUE(*s))
val |= o[i].value;
}
} else
val |= SvOpt(name, optname, o);
return val;
}
SV * newSVOptFlags(long value, char * optname, struct opts * o, int hash)
{
SV * result;
if (Csa_generate_numeric_enumerations)
return newSViv(value);
if (hash) {
HV * h = newHV();
int i;
result = newRV((SV*)h);
SvREFCNT_dec(h);
for(i=0;o[i].name;i++)
if ((value & o[i].value) == o[i].value) {
hv_store(h, o[i].name, strlen(o[i].name), newSViv(1), 0);
value &= ~o[i].value;
}
} else {
AV * a = newAV();
int i;
result = newRV((SV*)a);
SvREFCNT_dec(a);
for(i=0;o[i].name;i++)
if ((value & o[i].value) == o[i].value) {
av_push(a, newSVpv(o[i].name, 0));
value &= ~o[i].value;
}
}
return result;
}
static struct opts attributes[] = {
{CSA_VALUE_BOOLEAN, "BOOLEAN"},
{CSA_VALUE_ENUMERATED, "ENUMERATED"},
{CSA_VALUE_FLAGS, "FLAGS"},
{CSA_VALUE_SINT32, "SINT32"},
{CSA_VALUE_UINT32, "UINT32"},
{CSA_VALUE_STRING, "STRING"},
{CSA_VALUE_CALENDAR_USER, "CALENDAR USER"},
{CSA_VALUE_DATE_TIME, "DATE TIME"},
{CSA_VALUE_DATE_TIME_RANGE, "DATE TIME RANGE"},
{CSA_VALUE_TIME_DURATION, "TIME DURATION"},
{CSA_VALUE_ACCESS_LIST, "ACCESS LIST"},
{CSA_VALUE_ATTENDEE_LIST, "ATTENDEE LIST"},
{CSA_VALUE_DATE_TIME_LIST, "DATE TIME LIST"},
{CSA_VALUE_REMINDER, "REMINDER"},
{CSA_VALUE_OPAQUE_DATA, "OPAQUE DATA"},
{0,0}
};
static struct opts scopes[] = {
{CSA_SCOPE_ALL, "ALL"},
{CSA_SCOPE_ONE, "ONE"},
{CSA_SCOPE_FORWARD, "FORWARD"},
{0, 0}
};
SV * newSVCSA_SCOPE(int scope) { return newSVOpt(scope, "scope", scopes); }
int SvCSA_SCOPE(SV * name) { return SvOpt(name, "scope", scopes); }
static struct opts lineterms[] = {
{CSA_LINE_TERM_CRLF, "CRLF"},
{CSA_LINE_TERM_LF, "LF"},
{CSA_LINE_TERM_CR, "CR"},
{0, 0}
};
SV * newSVCSA_LINE_TERM(int value) { return newSVOpt(value, "line term", lineterms); }
int SvCSA_LINE_TERM(SV * name) { return SvOpt(name, "line term", lineterms); }
static struct opts requires[] = {
{CSA_REQUIRED_NO, "NO"},
{CSA_REQUIRED_OPT, "OPT"},
{CSA_REQUIRED_YES, "YES"},
{0, 0}
};
SV * newSVCSA_REQUIRED(int value) { return newSVOpt(value, "required", requires); }
int SvCSA_REQUIRED(SV * name) { return SvOpt(name, "required", requires); }
static struct opts types[] = {
{CSA_USER_TYPE_INDIVIDUAL, "INDIVIDUAL"},
{CSA_USER_TYPE_GROUP, "GROUP"},
{CSA_USER_TYPE_RESOURCE, "RESOURCE"},
{0, 0}
};
SV * newSVCSA_USER_TYPE(int type) { return newSVOpt(type, "type", types); }
int SvCSA_USER_TYPE(SV * name) { return SvOpt(name, "type", types); }
static struct opts lookups[] = {
{CSA_LOOKUP_RESOLVE_PREFIX_SEARCH, "PREFIX SEARCH"},
{CSA_LOOKUP_RESOLVE_IDENTITY, "IDENTITY"},
{0, 0}
};
SV * newSVCSA_LOOKUP(int value) { return newSVOpt(value, "lookup", lookups); }
int SvCSA_LOOKUP(SV * name) { return SvOpt(name, "lookup", lookups); }
static struct opts matches[] = {
{CSA_MATCH_ANY, "ANY"},
{CSA_MATCH_EQUAL_TO, "EQUAL TO"},
{CSA_MATCH_NOT_EQUAL_TO, "NOT EQUAL TO"},
{CSA_MATCH_GREATER_THAN, "GREATER THAN"},
{CSA_MATCH_LESS_THAN, "LESS THAN"},
{CSA_MATCH_GREATER_THAN_OR_EQUAL_TO, "GREATER THAN OR EQUAL TO"},
{CSA_MATCH_LESS_THAN_OR_EQUAL_TO, "LESS THAN OR EQUAL TO"},
{CSA_MATCH_CONTAIN, "CONTAIN"},
{CSA_MATCH_ANY, "*"},
{CSA_MATCH_EQUAL_TO, "=="},
{CSA_MATCH_NOT_EQUAL_TO, "!="},
{CSA_MATCH_NOT_EQUAL_TO, "<>"},
{CSA_MATCH_GREATER_THAN, ">"},
{CSA_MATCH_LESS_THAN, "<"},
{CSA_MATCH_GREATER_THAN_OR_EQUAL_TO, ">="},
{CSA_MATCH_LESS_THAN_OR_EQUAL_TO, "<="},
{CSA_MATCH_CONTAIN, "//"},
{0, 0}
};
SV * newSVCSA_MATCH(int match) { return newSVOpt(match, "match", matches); }
int SvCSA_MATCH(SV * name) { return SvOpt(name, "match", matches); }
SV * newSVISO_date_time(char * value, int doiso)
{
if (doiso)
return newSVpv(value, 0);
else {
time_t tick;
if (_csa_iso8601_to_tick(value, &tick))
return newSVsv(&sv_undef);
else
return newSViv(tick);
}
}
SV * newSVISO_date_time_range(char * value, int doiso)
{
if (doiso)
return newSVpv(value, 0);
else {
time_t tick1,tick2;
AV * l;
SV * result;
if (_csa_iso8601_to_range(value, &tick1, &tick2))
return newSVsv(&sv_undef);
l = newAV();
av_push(l, newSViv(tick1));
av_push(l, newSViv(tick2));
result = newRV((SV*)l);
SvREFCNT_dec(l);
return result;
}
}
SV * newSVISO_time_duration(char * value, int doiso)
{
if (doiso)
return newSVpv(value, 0);
else {
time_t tick;
if (_csa_iso8601_to_duration(value, &tick))
return newSVsv(&sv_undef);
return newSViv(tick);
}
}
char * SvISO_date_time(SV * value, char * buffer)
{
if (!value || !SvOK(value))
return 0;
if (!buffer)
buffer = alloc_temp(64);
if (SvIOKp(value) || SvNOKp(value)) {
_csa_tick_to_iso8601(SvIV(value), buffer);
} else {
strncpy(buffer, SvPV(value, na), 63);
buffer[63] = '\0';
if (strlen(buffer)==0)
return 0;
}
return buffer;
}
char * SvISO_date_time_range(SV * value, char *buffer)
{
if (!value || !SvOK(value))
return 0;
if (!buffer)
buffer = alloc_temp(64);
if (SvRV(value)) {
time_t t1,t2;
AV * a = (AV*)SvRV(value);
t1 = SvIV(*av_fetch(a,0,0));
t2 = SvIV(*av_fetch(a,1,0));
_csa_range_to_iso8601(t1, t2, buffer);
} else {
strncpy(buffer, SvPV(value, na), 63);
buffer[63] = '\0';
if (strlen(buffer)==0)
return 0;
}
return buffer;
}
char * SvISO_time_duration(SV * value, char * buffer)
{
if (!value || !SvOK(value))
return 0;
if (!buffer)
buffer = alloc_temp(64);
if (SvIOKp(value) || SvNOKp(value)) {
_csa_duration_to_iso8601(SvIV(value), buffer);
} else {
strncpy(buffer, SvPV(value, na), 63);
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"},
{CSA_INSERT_PUBLIC_ENTRIES, "INSERT PUBLIC ENTRIES"},
{CSA_INSERT_CONFIDENTIAL_ENTRIES, "INSERT CONFIDENTIAL ENTRIES"},
{CSA_INSERT_PRIVATE_ENTRIES, "INSERT PRIVATE ENTRIES"},
{CSA_CHANGE_PUBLIC_ENTRIES, "CHANGE PUBLIC ENTRIES"},
{CSA_CHANGE_CONFIDENTIAL_ENTRIES, "CHANGE CONFIDENTIAL ENTRIES"},
{CSA_CHANGE_PRIVATE_ENTRIES, "CHANGE PRIVATE ENTRIES"},
{CSA_VIEW_CALENDAR_ATTRIBUTES, "VIEW CALENDAR ATTRIBUTES"},
{CSA_INSERT_CALENDAR_ATTRIBUTES, "INSERT CALENDAR ATTRIBUTES"},
{CSA_CHANGE_CALENDAR_ATTRIBUTES, "CHANGE CALENDAR ATTRIBUTES"},
{CSA_ORGANIZER_RIGHTS, "ORGANIZER RIGHTS"},
{CSA_OWNER_RIGHTS, "OWNER RIGHTS"},
{0, 0}
};
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;
int i;
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)
{
AV * l;
SV * r;
CSA_access_rights * right;
if (!list)
return newSVsv(&sv_undef);
l = newAV();
for(right = list; right; right=right->next)
av_push(l, newSVCSA_access_rights(right));
r = newRV((SV*)l);
SvREFCNT_dec(l);
return r;
}
CSA_access_list SvCSA_access_list(SV * data, CSA_access_list list)
{
AV * l;
int i;
if (!data || !SvOK(data))
return 0;
l = (AV*)SvRV(data);
if (av_len(l)==-1)
return 0;
if (!list)
list = alloc_temp(sizeof(CSA_access_rights)* (av_len(l)+1));
for(i=0;i<=av_len(l);i++) {
SvCSA_access_rights(*av_fetch(l, i, 0), list);
list->next = list+i+1;
}
if (i)
(list+i-1)->next = 0;
return list;
}
static struct opts statuses[] = {
{CSA_STATUS_ACCEPTED, "ACCEPTED"},
{CSA_STATUS_NEEDS_ACTION, "NEEDS ACTION"},
{CSA_STATUS_SENT, "SENT"},
{CSA_STATUS_TENTATIVE, "TENTATIVE"},
{CSA_STATUS_CONFIRMED, "CONFIRMED"},
{CSA_STATUS_REJECTED, "REJECTED"},
{CSA_STATUS_COMPLETED, "COMPLETED"},
{CSA_STATUS_DELEGATED, "DELEGATED"},
#ifdef CSA_X_DT_STATUS_ACTIVE
{CSA_X_DT_STATUS_ACTIVE, "X-DT ACTIVE"},
#endif
#ifdef CSA_X_DT_STATUS_DELETE_PENDING
{CSA_X_DT_STATUS_DELETE_PENDING, "X-DT DELETE PENDING"},
#endif
#ifdef CSA_X_DT_STATUS_ADD_PENDING
{CSA_X_DT_STATUS_ADD_PENDING, "X-DT ADD PENDING"},
#endif
#ifdef CSA_X_DT_STATUS_COMMITTED
{CSA_X_DT_STATUS_COMMITTED, "X-DT COMMITTED"},
#endif
#ifdef CSA_X_DT_STATUS_CANCELLED
{CSA_X_DT_STATUS_CANCELLED, "X-DT CANCELLED"},
#endif
{0, 0}
};
static struct opts priorities[] = {
{CSA_FOR_YOUR_INFORMATION, "FOR YOUR INFORMATION"},
{CSA_ATTENDANCE_REQUESTED, "ATTENDANCE REQUESTED"},
{CSA_ATTENDANCE_REQUIRED, "ATTENDANCE REQUIRED"},
{CSA_IMMEDIATE_RESPONSE, "IMMEDIATE RESPONSE"},
{0, 0}
};
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)
{
AV * l;
SV * r;
CSA_attendee * attendee;
if (!list)
return newSVsv(&sv_undef);
l = newAV();
for(attendee = list; attendee; attendee = attendee->next)
av_push(l, newSVCSA_attendee(attendee));
r = newRV((SV*)l);
SvREFCNT_dec(l);
return r;
}
SV * newSVCSA_date_time_list(CSA_date_time_list list, int doiso_times)
{
AV * l;
SV * r;
CSA_date_time_entry * dt;
if (!list)
return newSVsv(&sv_undef);
l = newAV();
for(dt = list; dt; dt = dt->next)
av_push(l, newSVISO_date_time(dt->date_time, doiso_times));
r = newRV((SV*)l);
SvREFCNT_dec(l);
return r;
}
CSA_date_time_list SvCSA_date_time_list(SV * data, CSA_date_time_list target)
{
AV * l;
int i;
if (!data || !SvOK(data))
return 0;
l = (AV*)SvRV(data);
if (av_len(l)<0)
return 0;
if (!target)
target = alloc_temp(sizeof(CSA_date_time_entry)*(av_len(l)+1));
for(i=0;i<=av_len(l);i++) {
(target+i)->date_time = SvISO_date_time(*av_fetch(l, i, 0), 0);
(target+i)->next = target+i+1;
}
if (i)
(target+i-1)->next = 0;
return target;
}
SV * newSVCSA_opaque_data(CSA_opaque_data * data)
{
if (!data || !data->data)
return newSVsv(&sv_undef);
return newSVpv((char *)data->data, data->size);
}
CSA_opaque_data * SvCSA_opaque_data(SV * data, CSA_opaque_data * target)
{
unsigned int len;
if (!data || !SvOK(data))
return 0;
if (!target)
target = alloc_temp(sizeof(CSA_opaque_data));
target->data = (CSA_uint8 *)SvPV(data, len);
target->size = len;
return target;
}
SV * newSVCSA_reminder(CSA_reminder * rem, int doiso_times)
{
HV * u;
HV * flags;
SV * r;
int i;
if (!rem)
return newSVsv(&sv_undef);
u = newHV();
hv_store(u, "lead_time", 9, newSVISO_time_duration(rem->lead_time, doiso_times), 0);
hv_store(u, "snooze_time", 11, newSVISO_time_duration(rem->snooze_time, doiso_times), 0);
hv_store(u, "repeat_count", 12, newSViv(rem->repeat_count), 0);
hv_store(u, "reminder_data", 13, newSVCSA_opaque_data(&rem->reminder_data), 0);
r = newRV((SV*)u);
SvREFCNT_dec(u);
return r;
}
CSA_reminder * SvCSA_reminder(SV * data, CSA_reminder * target)
{
HV * h = (HV*)SvRV(data);
SV ** s;
int i;
if (!data || !SvOK(data))
return 0;
if (!target)
target = alloc_temp(sizeof(CSA_reminder));
memset(target, 0, sizeof(CSA_reminder));
if ((s=hv_fetch(h, "lead_time", 9, 0)) && SvOK(*s))
target->lead_time = SvISO_time_duration(*s,0);
else
target->lead_time = 0;
if ((s=hv_fetch(h, "snooze_time", 11, 0)) && SvOK(*s))
target->snooze_time = SvISO_time_duration(*s,0);
else
target->snooze_time = 0;
if ((s=hv_fetch(h, "repeat_count", 12, 0)) && SvOK(*s))
target->repeat_count = SvIV(*s);
else
target->repeat_count = 0;
if ((s=hv_fetch(h, "data", 4, 0)) && SvOK(*s))
SvCSA_opaque_data(*s, &target->reminder_data);
return target;
}
SV * newSVCSA_attribute_value(CSA_attribute_value * attr, int doshorten, int doiso_times)
{
HV * h;
SV * r;
SV * type = 0;
SV * value = 0;
if (!attr)
return newSVsv(&sv_undef);
h = newHV();
type = newSVOpt(attr->type, "attribute type", attributes);
switch (attr->type) {
case CSA_VALUE_BOOLEAN:
value = newSViv(attr->item.boolean_value);
break;
case CSA_VALUE_ENUMERATED:
value = newSViv(attr->item.enumerated_value);
break;
case CSA_VALUE_FLAGS:
value = newSViv(attr->item.flags_value);
break;
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_ACCESS_LIST:
value = newSVCSA_access_list(attr->item.access_list_value);
break;
case CSA_VALUE_DATE_TIME_LIST:
value = newSVCSA_date_time_list(attr->item.date_time_list_value, doiso_times);
break;
case CSA_VALUE_REMINDER:
value = newSVCSA_reminder(attr->item.reminder_value, doiso_times);
break;
case CSA_VALUE_OPAQUE_DATA:
value = newSVCSA_opaque_data(attr->item.opaque_data_value);
break;
default:
value = newSVsv(&sv_undef); /* unknown type */
}
hv_store(h, "type", 4, type, 0);
hv_store(h, "value", 5, value, 0);
r = newRV((SV*)h);
SvREFCNT_dec(h);
return r;
}
SV * newSVCSA_attribute(CSA_attribute * attr, int doshorten, int doiso_times)
{
HV * h;
SV * r;
char * type = 0;
SV * value = 0;
if (!attr)
return newSVsv(&sv_undef);
h = newHV();
hv_store(h, "name", 4, newSVpv(attr->name,0), 0);
hv_store(h, "value", 5, newSVCSA_attribute_value(attr->value, doshorten, doiso_times), 0);
r = newRV((SV*)h);
SvREFCNT_dec(h);
return r;
}
CSA_attribute_value * SvCSA_attribute_value(SV * attr, CSA_attribute_value * target)
{
HV * h;
SV * r;
SV ** s;
int type = 0;
SV * value = 0;
if (!attr || !SvOK(attr))
return 0;
if (SvTYPE(SvRV(attr)) != SVt_PVHV)
croak("an attribute value must be a hash containing type and value keys");
h = (HV*)SvRV(attr);
if (!(s=hv_fetch(h, "type", 4, 0)) || !SvOK(*s))
croak("an attribute value must be a hash containing type and value keys");
type = SvOpt(*s, "attribute type", attributes);
if (!(s=hv_fetch(h, "value", 5, 0)))
croak("an attribute value must be a hash containing type and value keys");
if (!target)
target = alloc_temp(sizeof(CSA_attribute_value));
target->type = type;
switch (type) {
case CSA_VALUE_BOOLEAN:
target->item.boolean_value = SvIV(*s);
break;
case CSA_VALUE_ENUMERATED:
target->item.enumerated_value = SvIV(*s);
break;
case CSA_VALUE_FLAGS:
target->item.flags_value = SvIV(*s);
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;
case CSA_VALUE_ACCESS_LIST:
target->item.access_list_value = SvCSA_access_list(*s, 0);
break;
case CSA_VALUE_DATE_TIME_LIST:
target->item.date_time_list_value = SvCSA_date_time_list(*s, 0);
break;
case CSA_VALUE_REMINDER:
target->item.reminder_value = SvCSA_reminder(*s, 0);
break;
case CSA_VALUE_OPAQUE_DATA:
target->item.opaque_data_value = SvCSA_opaque_data(*s, 0);
break;
defaut:
croak("unhandled attribute type");
}
return target;
}
CSA_attribute * SvCSA_attribute(SV * attr, CSA_attribute * target)
{
HV * h;
SV * r;
SV ** s;
char * type = 0;
SV * value = 0;
if (!attr || !SvOK(attr))
return 0;
if (!target)
target = alloc_temp(sizeof(CSA_attribute));
h = (HV*)SvRV(attr);
if ((s=hv_fetch(h, "name", 4, 0)) && SvOK(*s))
target->name = SvPV(*s, na);
else
croak("attribute must have name");
if ((s=hv_fetch(h, "value", 5, 0)) && SvOK(*s))
target->value = SvCSA_attribute_value(*s, 0);
else
croak("attribute must have value");
return target;
}
static struct opts cb_modes[] = {
{CSA_CB_CALENDAR_LOGON, "CALENDAR LOGON"},
{CSA_CB_CALENDAR_DELETED, "CALENDAR DELETED"},
{CSA_CB_CALENDAR_ATTRIBUTE_UPDATED, "CALENDAR ATTRIBUTE UPDATED"},
{CSA_CB_ENTRY_ADDED, "ENTRY ADDED"},
{CSA_CB_ENTRY_DELETED, "ENTRY DELETED"},
{CSA_CB_ENTRY_UPDATED, "ENTRY UPDATED"},
{0, 0}
};
int SvCSA_callback_mode(SV * mode) { return SvOpt(mode, "callback mode", cb_modes); }
static struct {char *l; char *s; } short_names[] = {
{"-//XAPIA/CSA/CALATTR//NONSGML Access List//EN", "Access List"},
{"-//XAPIA/CSA/CALATTR//NONSGML Calendar Name//EN", "Calendar Name"},
{"-//XAPIA/CSA/CALATTR//NONSGML Calendar Owner//EN", "Calendar Owner"},
{"-//XAPIA/CSA/CALATTR//NONSGML Calendar Size//EN", "Calendar Size"},
{"-//XAPIA/CSA/CALATTR//NONSGML Character Set//EN", "Character Set"},
{"-//XAPIA/CSA/CALATTR//NONSGML Country//EN", "Country"},
{"-//XAPIA/CSA/CALATTR//NONSGML Date Created//EN", "Date Created"},
{"-//XAPIA/CSA/CALATTR//NONSGML Language//EN", "Language"},
{"-//XAPIA/CSA/CALATTR//NONSGML Number Entries//EN", "Number Entries"},
{"-//XAPIA/CSA/CALATTR//NONSGML Product Identifier//EN", "Product Identifier"},
{"-//XAPIA/CSA/CALATTR//NONSGML Time Zone//EN", "Time Zone"},
{"-//XAPIA/CSA/CALATTR//NONSGML Version//EN", "Version"},
{"-//XAPIA/CSA/CALATTR//NONSGML Work Schedule//EN", "Work Schedule"},
{"-//CDE_XAPIA_PRIVATE/CSA/CALATTR//NONSGML Server Version//EN", "Server Version"},
{"-//CDE_XAPIA_PRIVATE/CSA/CALATTR//NONSGML Data Version//EN", "Data Version"},
{"-//CDE_XAPIA_PRIVATE/CSA/CALATTR//NONSGML Calendar Delimiter//EN", "Calendar Delimiter"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Attendee List//EN", "Attendee List"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Audio Reminder//EN", "Audio Reminder"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Classification//EN", "Classification"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Date Completed//EN", "Date Completed"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Date Created//EN", "Date Created"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Description//EN", "Description"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Due Date//EN", "Due Date"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML End Date//EN", "End Date"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Exception Dates//EN", "Exception Dates"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Exception Rule//EN", "Exception Rule"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Flashing Reminder//EN", "Flashing Reminder"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Last Update//EN", "Last Update"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Mail Reminder//EN", "Mail Reminder"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Number Recurrences//EN", "Number Recurrences"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Organizer//EN", "Organizer"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Popup Reminder//EN", "Popup Reminder"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Priority//EN", "Priority"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Recurrence Rule//EN", "Recurrence Rule"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Recurring Dates//EN", "Recurring Dates"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Reference Identifier//EN", "Reference Identifier"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Sequence Number//EN", "Sequence Number"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Sponsor//EN", "Sponsor"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Start Date//EN", "Start Date"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Status//EN", "Status"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Subtype//EN", "Subtype"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Summary//EN", "Summary"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Time Transparency//EN", "Time Transparency"},
{"-//XAPIA/CSA/ENTRYATTR//NONSGML Type//EN", "Type"},
{"-//CDE_XAPIA_PRIVATE/CSA/ENTRYATTR//NONSGML Show Time//EN", "Show Time"},
{"-//CDE_XAPIA_PRIVATE/CSA/ENTRYATTR//NONSGML Repeat Type//EN", "Repeat Type"},
{"-//CDE_XAPIA_PRIVATE/CSA/ENTRYATTR//NONSGML Repeat Times//EN", "Repeat Times"},
{"-//CDE_XAPIA_PRIVATE/CSA/ENTRYATTR//NONSGML Repeat Interval//EN", "Repeat Interval"},
{"-//CDE_XAPIA_PRIVATE/CSA/ENTRYATTR//NONSGML Sequence End Date//EN", "Sequence End Date"},
{"-//CDE_XAPIA_PRIVATE/CSA/ENTRYATTR//NONSGML Entry Delimiter//EN", "Entry Delimiter"},
{"-//XAPIA/CSA/SUBTYPE//NONSGML Subtype Appointment//EN", "Subtype Appointment"},
{"-//XAPIA/CSA/SUBTYPE//NONSGML Subtype Class//EN", "Subtype Class"},
{"-//XAPIA/CSA/SUBTYPE//NONSGML Subtype Holiday//EN", "Subtype Holiday"},
{"-//XAPIA/CSA/SUBTYPE//NONSGML Subtype Meeting//EN", "Subtype Meeting"},
{"-//XAPIA/CSA/SUBTYPE//NONSGML Subtype Miscellaneous//EN", "Subtype Miscellaneous"},
{"-//XAPIA/CSA/SUBTYPE//NONSGML Subtype Phone Call//EN", "Subtype Phone Call"},
{"-//XAPIA/CSA/SUBTYPE//NONSGML Subtype Sick Day//EN", "Subtype Sick Day"},
{"-//XAPIA/CSA/SUBTYPE//NONSGML Subtype Special Occasion//EN", "Subtype Special Occasion"},
{"-//XAPIA/CSA/SUBTYPE//NONSGML Subtype Travel//EN", "Subtype Travel"},
{"-//XAPIA/CSA/SUBTYPE//NONSGML Subtype Vacation//EN", "Subtype Vacation"},
{0,0}
};
char * shorten(char * arg, int doit)
{
if (!doit)
return arg;
else {
int i;
for(i=0;short_names[i].l;i++)
if (strEQ(short_names[i].l,arg))
return short_names[i].s;
return arg;
}
}
char * lengthen(char * arg)
{
int i;
for(i=0;short_names[i].s;i++)
if (strEQ(short_names[i].s,arg))
return short_names[i].l;
return arg;
}
void * Csa_safe_calloc(int nelem, size_t elsize)
{
void *ptr;
ptr = calloc(nelem, elsize);
if (ptr == NULL)
{
croak("out of memory");
}
return ptr;
}
void * Csa_safe_malloc(int size)
{
void *ptr;
ptr = malloc(size);
if (ptr == NULL)
{
croak("out of memory");
}
return ptr;
}