first commit

This commit is contained in:
bgraansm
2017-08-26 08:54:02 -04:00
commit a136a92053
19 changed files with 6167 additions and 0 deletions

199
calmodule.c Normal file
View File

@@ -0,0 +1,199 @@
/* calmodule.c
* Author: Bronson Graansma 0872249
* Contact: bgraansm@mail.uoguelph.ca
* Date: March 17, 2016
* Description: python - c extension for xcal */
#include <Python.h>
#include "calutil.h"
#include <stdio.h>
#include <string.h>
static char* parseError(char* file, CalStatus status) {
char* err = "UNKNOWN";
char* out = NULL;
switch(status.code) {
case OK : err = "OK"; break;
case AFTEND: err = "AFTEND"; break;
case BADVER: err = "BADVER"; break;
case BEGEND: err = "BEGEND"; break;
case IOERR : err = "IOERR"; break;
case NOCAL : err = "NOCAL"; break;
case NOCRNL: err = "NOCRNL"; break;
case NODATA: err = "NODATA"; break;
case NOPROD: err = "NOPROD"; break;
case SUBCOM: err = "SUBCOM"; break;
case SYNTAX: err = "SYNTAX"; break;
}
out = malloc(strlen(err) + strlen(file) + 30);
sprintf(out, "%s: %s in lines %d-%d\n",
file, err, status.linefrom, status.lineto);
return out;
}
static char* formatTime(char* str) {
//'YYYY-MM-DD HH:MM:SS'
char* format = malloc(20);
assert(format != NULL);
if(str == NULL || strlen(str) < 15) {
free(format);
return "0000-00-00 00:00:00";
}
for(int i = 0; i < 19; i++) {
format[i] = ' ';
}
for(int i = 0; i < 4; i++) {
format[i] = str[i];
}
for(int i = 0; i < 2; i++) {
format[i + 5] = str[i + 4];
format[i + 8] = str[i + 6];
format[i + 11] = str[i + 9];
format[i + 14] = str[i + 11];
format[i + 17] = str[i + 13];
}
format[4] = '-';
format[7] = '-';
format[13] = ':';
format[16] = ':';
format[19] = '\0';
return format;
}
static PyObject *Cal_readFile( PyObject *self, PyObject *args ) {
CalStatus status = initCalStatus(OK, 0,0);
char *filename = NULL;
PyObject *result = PyTuple_New(2);
PyObject *tuple = NULL;
FILE* ics = NULL;
CalComp* pcal = NULL;
PyArg_ParseTuple(args, "s", &filename);
ics = fopen(filename, "r");
if(ics == NULL) {
PyTuple_SetItem(result, 0, Py_BuildValue("s", "error"));
PyTuple_SetItem(result, 1, Py_BuildValue("s", strerror(errno)));
return result;
} else {
status = readCalFile(ics, &pcal);
}
fclose(ics);
if(status.code != OK) {
char* out = parseError(filename, status);
PyTuple_SetItem(result, 0, Py_BuildValue("s", "error"));
PyTuple_SetItem(result, 1, Py_BuildValue("s", out));
free(out);
return result;
}
tuple = PyTuple_New(pcal->ncomps);
for(int i = 0; i < pcal->ncomps; i++) {
char* summary = " ";
char* orgName = " ";
char* orgInfo = " ";
char* locaton = " ";
char* priorty = " ";
char* dtstart = "0000-00-00 00:00:00";
CalProp* prop = pcal->comp[i]->prop;
PyObject *tmp = NULL;
for(int j = 0; j < pcal->comp[i]->nprops; j++) {
if(strcmp(prop->name, "ORGANIZER") == 0) {
CalParam* param = prop->param;
for(int k = 0; k < prop->nparams; k++) {
if(strcmp(param->name, "CN") == 0) {
orgName = param->value[0];
break;
}
param = param->next;
}
orgInfo = prop->value;
} else if(strcmp(prop->name, "DTSTART") == 0) {
dtstart = formatTime(prop->value);
} else if(strcmp(prop->name, "LOCATION") == 0) {
locaton = prop->value;
} else if(strcmp(prop->name, "PRIORITY") == 0) {
priorty = prop->value;
} else if(strcmp(prop->name, "SUMMARY") == 0) {
summary = prop->value;
}
prop = prop->next;
}
tmp = Py_BuildValue("(s,i,i,s,s,s,s,s,s)",pcal->comp[i]->name,
pcal->comp[i]->nprops, pcal->comp[i]->ncomps, summary,
orgName, orgInfo, dtstart, locaton, priorty);
PyTuple_SetItem(tuple, i, tmp);
if(strcmp(dtstart, "0000-00-00 00:00:00") != 0) {
free(dtstart);
}
}
PyTuple_SetItem(result, 0, Py_BuildValue("k", (unsigned long*)pcal));
PyTuple_SetItem(result, 1, tuple);
return result;
}
static PyObject *Cal_writeFile(PyObject *self, PyObject *args ) {
CalStatus status = initCalStatus(OK, 0, 0);
char *filename = NULL;
CalComp *pcal = NULL;
FILE* ics = NULL;
int compNum = 0;
PyArg_ParseTuple(args, "ski", &filename, (unsigned long*)&pcal, &compNum);
ics = fopen(filename, "w");
if(ics == NULL) {
return Py_BuildValue("s", strerror(errno));
} else if(compNum > -1) {
status = writeCalComp(ics, pcal->comp[compNum]);
} else {
status = writeCalComp(ics, pcal);
}
fclose(ics);
if(status.code != OK) {
char* out = parseError(filename, status);
PyObject* pOut = Py_BuildValue("s", out);
free(out);
return pOut;
}
return Py_BuildValue("s", "OK");
}
static PyObject *Cal_freeFile( PyObject *self, PyObject *args ) {
CalComp *pcal;
PyArg_ParseTuple(args, "k", (unsigned long*)&pcal);
freeCalComp(pcal);
return Py_BuildValue("");
}
static PyMethodDef CalMethods[] = {
{"readFile", Cal_readFile, METH_VARARGS},
{"writeFile", Cal_writeFile, METH_VARARGS},
{"freeFile", Cal_freeFile, METH_VARARGS},
{NULL, NULL}
};
static struct PyModuleDef calModuleDef = {PyModuleDef_HEAD_INIT, "Cal", NULL, -1, CalMethods};
PyMODINIT_FUNC PyInit_Cal(void) {
return PyModule_Create(&calModuleDef);
}

1028
caltool.c Normal file
View File

File diff suppressed because it is too large Load Diff

39
caltool.h Normal file
View File

@@ -0,0 +1,39 @@
/* caltool.h
* Author: Bronson Graansma 0872249
* Contact: bgraansm@mail.uoguelph.ca
* Date: Feb 21, 2016
* Description: Public Interface for caltool. */
#ifndef CALTOOL_H
#define CALTOOL_H A2_RevA
#define _GNU_SOURCE // for getdate_r
#define _XOPEN_SOURCE // for strptime
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <stdbool.h>
#include "calutil.h"
/* Symbols used to send options to command execution modules */
typedef enum {
OEVENT, // events
OPROP, // properties
OTODO, // to-do items
} CalOpt;
/* iCalendar tool functions */
CalStatus calInfo( const CalComp *comp, int lines, FILE *const txtfile );
CalStatus calExtract( const CalComp *comp, CalOpt kind, FILE *const txtfile );
CalStatus calFilter( const CalComp *comp, CalOpt content, time_t datefrom,
time_t dateto, FILE *const icsfile );
CalStatus calCombine( const CalComp *comp1, const CalComp *comp2,
FILE *const icsfile );
#endif

987
calutil.c Normal file
View File

@@ -0,0 +1,987 @@
/* calutil.c
* Author: Bronson Graansma 0872249
* Contact: bgraansm@mail.uoguelph.ca
* Date: Feb 21, 2016
* Description: Reads in an ics file and stores meaningful info in memory.
* Various status codes are provided in order to discern what
* went wrong in the file while reading it. */
#include "calutil.h"
#define BUFF_LEN 1024
/* Function name: initCalStatus
* Description: Initialize a CalStatus' members.
* Args: Code and lines to initilaize your CalStatus with.
* Returns: A CalStatus with values you passed. */
CalStatus initCalStatus(CalError code, int linefrom, int lineto) {
CalStatus status;
status.code = code;
status.linefrom = linefrom;
status.lineto = lineto;
return status;
}
/* Function name: initCalProp
* Description: Initialize a CalProp's members.
* Returns: A CalProp with nul or 0 values. */
static CalProp initCalProp(void) {
CalProp prop;
prop.name = NULL;
prop.value = NULL;
prop.nparams = 0;
prop.param = NULL;
prop.next = NULL;
return prop;
}
/* Function name: initCalComp
* Description: Initialize a CalComp's members to nul or 0
* Args: The adress of the CalComp to initialize. */
static void initCalComp(CalComp* comp) {
comp->name = NULL;
comp->prop = NULL;
comp->ncomps = 0;
comp->nprops = 0;
}
/* Function name: printBuffer
* Description: Prints a string to a file, and folds any strings that
* are longer than FOLD_LEN bytes.
* Args: The char* to print, and the stream to print it to.
* Returns: The number of lines written, or it's negative if an error. */
static int printBuffer(char* buff, FILE* ics) {
int len = strlen(buff);
int lines = 0;
int count = 0;
for(int i = 0; i < len; i++) {
if(fprintf(ics, "%c", buff[i]) < 0) {
return lines * (-1);
}
count++;
if(i == len - 1) {
if(fprintf(ics, "\r\n") < 0) {
return lines * (-1);
}
lines++;
break;
}
if(count == FOLD_LEN) {
if(fprintf(ics, "\r\n ") < 0) {
return lines * (-1);
}
lines++;
count = 1;
}
}
return lines;
}
/* Function name: printParam
* Description: Formats a string to match iCalandar syntax for parameters.
* Args: The parameter to format a string for, and the string to store it in.*/
static void printParam(CalParam* param, char** buff) {
char* comma = "";
char* temp = NULL;
if(param == NULL) {
return;
} else if(*buff == NULL) {
*buff = malloc(1);
(*buff)[0] = '\0';
assert(*buff != NULL);
}
*buff = realloc(*buff, strlen(*buff) + strlen(param->name) + 3);
assert(*buff != NULL);
temp = malloc(strlen(*buff) + strlen(param->name) + 3);
assert(temp != NULL);
sprintf(temp, "%s;%s=", *buff, param->name);
sprintf(*buff, "%s", temp);
for(int i = 0; i < param->nvalues; i++) {
*buff = realloc(*buff, strlen(*buff) + strlen(param->value[i]) + 2);
temp = realloc(temp , strlen(temp ) + strlen(param->value[i]) + 2);
assert(*buff != NULL && temp != NULL);
sprintf(temp, "%s", *buff);
sprintf(*buff, "%s%s%s", temp, comma, param->value[i]);;
comma = ",";
}
free(temp);
printParam(param->next, buff);
}
/* Function name: printProp
* Description: Recursively prints a property to a stream in iCalandar syntax.
* Args: The property to print, and the stream to print it to.
* Returns: The number of lines written, or it's negative if an error. */
static int printProp(CalProp* prop, FILE* ics) {
char* buff = NULL;
char* temp = NULL;
int lines = 0;
int ioerr = 0;
int len = 0;
if(prop == NULL) {
return 0;
} else if(prop->name == NULL) {
len = 0;
} else {
len = strlen(prop->name);
}
buff = malloc(len + 1);
assert(buff != NULL);
sprintf(buff, "%s", prop->name);
printParam(prop->param, &buff);
temp = malloc(strlen(buff) + strlen(prop->value) + 4);
assert(temp != NULL);
sprintf(temp, "%s:%s", buff, prop->value);
free(buff);
lines = printBuffer(temp, ics);
free(temp);
if(lines < 0) {
return lines;
}
ioerr = printProp(prop->next, ics);
if(ioerr < 0) {
return ((-1) * lines) + ioerr;
}
return lines + ioerr;
}
/* Function name: printComp
* Description: Recursively prints a component to a stream in iCalandar syntax.
* Args: The component to print, and the stream to print it to.
* Returns: The number of lines written, or it's negative if an error. */
static int printComp(const CalComp* comp, FILE* ics) {
int lines = 0;
int ioerr = 0;
char* buff = NULL;
if(comp == NULL) {
return 0;
}
buff = malloc(strlen(comp->name) + 9);
assert(buff != NULL);
sprintf(buff, "BEGIN:%s", comp->name);
lines = printBuffer(buff, ics);
free(buff);
if(lines < 0) {
return lines;
}
buff = NULL;
ioerr = printProp(comp->prop, ics);
if(ioerr < 0) {
return ((-1) * lines) + ioerr;
}
lines += ioerr;
for(int i = 0; i < comp->ncomps; i++) {
ioerr = printComp(comp->comp[i], ics);
if(ioerr < 0) {
return ((-1) * lines) + ioerr;
}
lines += ioerr;
}
buff = malloc(strlen(comp->name) + 7);
assert(buff != NULL);
sprintf(buff, "END:%s", comp->name);
ioerr = printBuffer(buff, ics);
free(buff);
if(ioerr < 0) {
return ((-1) * lines) + ioerr;
}
return lines + ioerr;
}
/* Function name: validateProp
* Description: Validates that there is only 1 version, and that it matches
* VCAL_VER macro. Also validates that there is only 1 prodid.
* Note: To reset static variables safely, call with (NULL, true).
* Args: The CalProp to validate
* Returns: The error code if any, OK otherwise. */
static CalError validateProp(CalComp* comp) {
int nprodid = 0;
int nversion = 0;
for(CalProp* prop = comp->prop; prop != NULL; prop = prop->next) {
if(strcmp(prop->name, "VERSION") == 0) {
nversion++;
if(strcmp(prop->value, VCAL_VER) != 0) {
return BADVER;
}
} else if (strcmp(prop->name, "PRODID") == 0) {
nprodid++;
}
}
if(nversion != 1) {
return BADVER;
} else if(nprodid != 1) {
return NOPROD;
}
return OK;
}
/* Function name: validateComp
* Description: Validates that at least one component starts with V,
* and that there is atleast one component.
* Args: The CalComp to validate.
* Returns: The error code if any, OK otherwise. */
static CalError validateComp(CalComp* comp) {
int vCount = 0; /* must have at least one comp stating with "V" */
for(int i = 0; i < comp->ncomps; i++) {
if((comp->comp[i])->name[0] == 'V') {
vCount++;
}
}
if(comp->ncomps == 0 || vCount == 0) {
return NOCAL;
}
return OK;
}
/* Function name: displace
* Description: Moves each character in a string forward by the amount of
* characters specified.
* Args: String to displace, and the number of characters to offset it by. */
static void displace(char* str, int offset) {
int len = strlen(str);
for(int i = 0; i < len - offset; i++) {
str[i] = str[i + offset];
}
str[len - offset] = '\0';
}
/* Function name: removeCRNL
* Description: Checks for \r\n sequence and removes it.
* Args: The string to search for CRNL.
* Returns: True if CRNL was found and removed, false otherwise. */
static bool removeCRNL(char* str) {
int len = strlen(str);
for(int i = 0; i < len; i++) {
switch(str[i]) {
case '\r':
str[i] = '\0';
return str[i + 1] == '\n';
case '\n':
str[i] = '\0';
return str[i - 1] == '\r';
}
}
return false;
}
/* Function name: isEmpty
* Description: Checks if a string contains only whitespace.
* Args: The string to check.
* Returns: True if string is all whitespace, false otherwise. */
static bool isEmpty(char* str) {
int len = strlen(str);
for(int i = 0; i < len; i++) {
if(isspace(str[i]) == false) {
return false;
}
}
return true;
}
/* Function name: removeLead
* Description: Checks for and removes a leading whitespace character.
* Args: The string to check for and remove leading whitespace from.
* Returns: True if string began with whitespace, false otherwise. */
static bool removeLead(char* str) {
int len = strlen(str);
int i = 0;
if(str[0] == ' ' || str[0] == '\t') {
for(i = 0; i < len - 1; i++) {
if(str[i] == '\0') {
break;
}
str[i] = str[i + 1];
}
str[i] = '\0';
return true;
}
return false;
}
/* Function name: capitalize
* Description: Converts a string to uppercase.
* Args: The string to make uppercase. */
static void capitalize(char* str) {
int len = strlen(str);
for(int i = 0; i < len; i++) {
str[i] = toupper(str[i]);
}
}
/* Function name: checkStart
* Description: Determines if a prop matches "BEGIN:VCALENDAR".
* Args: The prop to check.
* Returns: True if prop matches "BEGIN:VCALENDAR", false otherwise. */
static bool checkStart(CalProp prop) {
bool check = false;
if(prop.name == NULL || prop.value == NULL) {
return false;
}
capitalize(prop.value);
check = strcmp(prop.name, "BEGIN") == 0;
check = check && strcmp(prop.value, "VCALENDAR") == 0;
check = check && prop.nparams == 0;
return check;
}
/* Function name: parseName
* Description: Identifies the name in this string and stores it in prop->name.
* Also removes the name from the string to simplify future parse.
* Args: The string to parse a name out of, and the prop to store it in.
* Returns: True if a name was found, false otherwise. */
static bool parseName(char* str, CalProp* prop) {
int offset = 0;
int len = strlen(str);
bool success = false;
int i = 0;
if(str == NULL) {
return false;
}
for(i = 0; i < len + 1; i++) {
if(str[i] == ';' || str[i] == ':') { /* property name ends here */
if(i == 0) {
return false;
}
offset = i;
success = true;
break;
} else if(str[i] == '\0' || str[i] == '\"' || isspace(str[i])) {
free(prop->name); /* property doesn't have a value, or it has */
prop->name = NULL; /* quotes or whitespace in it */
return false;
}
prop->name = realloc(prop->name, i + 2);
assert(prop->name != NULL);
prop->name[i] = str[i];
}
prop->name[i] = '\0';
displace(str, offset);
capitalize(prop->name);
if(strlen(prop->name) == 0) {
free(prop->name);
prop->name = NULL;
success = false;
}
return success;
}
/* Function name: parseParam
* Description: Identifies the parameters in this string, and stores them in
* prop->param linked list, and increments prop->nparams for each.
* Also removes the params from string to simplify future parse.
* Args: The string to parse patameters out of, and the prop to store them in.
* Note: If a parameter contains a syntax error, str will be damaged in order
* for parseValue to throw the SYNTAX error.
* Returns: True if any parameters were found, false otherwise. */
static bool parseParam(char* str, CalProp* prop) {
int len = strlen(str);
int i = 0;
int j = 0;
int vals = 0;
int offset = 0;
CalParam* param = prop->param;
bool quoted = false;
char name [len + 1];
char value[len + 1];
char temp [len + 1];
if(str == NULL || str[0] != ';' || len == 0) {
return false;
}
for(i = 1; i < len; i++) { /* parse parameter name out */
if(str[i] == ':' || str[i] == ';') {
offset = i; /* parameter name ends here if no value */
break;
} else if(str[i] == '\"' || str[i] == ' ' || str[i] == '\t') {
str[i] = '\"';
str[0] = '\0';
return false;
} else if(quoted == false && str[i] == '=') {
vals = 1;
offset = i + 1;
break; /* parameter name ends here */
}
name[i - 1] = str[i];
}
name[i - 1] = '\0';
if(vals != 1) { /* param wasn't proper */
str[i] = '\"';
str[0] = '\0';
return false; /* return while buffer is wrecked, so future parsing */
} /* returns a SYNTAX error */
capitalize(name);
displace(str, offset);
if(strlen(name) == 0) {
return false;
}
len = strlen(str);
offset = 0;
for(i = 0; i < len; i++) { /* parse parameter value out */
if(quoted == false && (str[i] == ':' || str[i] == ';')) {
offset = i; /* parameter value ends here */
break;
} else if(quoted == false && isspace(str[i]) == true) {
str[i] = '\"';
str[0] = '\0';
return false;
}else if(str[i] == '\"') {
quoted = !quoted;
} else if(quoted == false && str[i] == ',') {
vals++; /* this parameter has multiple values */
}
value[i] = str[i];
}
value[i] = '\0';
displace(str, offset);
for(param = prop->param; param != NULL; param = param->next) {
if(param->next == NULL) { /* find the end of linked list */
break; /* parameters will be copied into the end of list */
}
}
if(prop->nparams == 0) { /* this is first parameter */
prop->param = malloc(sizeof(CalParam) + (vals * sizeof(char*)));
assert(prop->param != NULL);
param = prop->param;
} else { /* copy into the end of the linked list */
param->next = malloc(sizeof(CalParam) + (vals * sizeof(char*)));
assert(param->next != NULL);
param = param->next;
}
prop->nparams++;
param->nvalues = vals;
param->next = NULL;
param->name = malloc(strlen(name) + 1);
assert(param->name != NULL);
strncpy(param->name, name, strlen(name));
param->name[strlen(name)] = '\0';
for(i = 0; i < vals; i++) { /* seperate the values */
offset = 0;
len = strlen(value);
for(j = 0; j < len; j++) {
if(value[j] == '\"') {
quoted = !quoted;
} else if(quoted == false && value[j] == ',') {
offset = j + 1; /* a value ends here */
break;
} else if(j == len - 1) {
offset = j; /* the last value ends here */
}
temp[j] = value[j];
}
temp[j] = '\0';
displace(value, offset);
param->value[i] = malloc(strlen(temp) + 1);
assert(param->value[i] != NULL);
strncpy(param->value[i], temp, strlen(temp));
(param->value[i])[strlen(temp)] = '\0';
}
return true;
}
/* Function name: parseValue
* Description: Identifies the value in this string and stores it in prop.
* Args: The string to parse the value out of, and the prop to store it in.
* Returns: True if the value was found, false otherwise. */
static bool parseValue(char* str, CalProp* prop) {
int len = strlen(str);
if(str == NULL || str[0] != ':' || strlen(str) == 0) {
return false;
}
prop->value = malloc(len);
assert(prop->value != NULL);
for(int i = 0; i < len; i++) { /* copy the string without the colon ':' */
prop->value[i] = str[i + 1]; /* includes null terminator */
}
return true;
}
/* Function name: freeCalParam
* Description: Recursively frees allocated CalParams in this linked list.
* Args: The head of the linked list of CalParams to free. */
static void freeCalParam(CalParam* param) {
if(param == NULL) {
return;
}
free(param->name);
param->name = NULL;
freeCalParam(param->next);
free(param->next);
param->next = NULL;
for(int i = 0; i < param->nvalues; i++) {
free(param->value[i]);
param->value[i] = NULL;
}
param->nvalues = 0;
}
/* Function name: freeCalProp
* Description: Recursively frees allocated CalProp in this linked list.
* Args: The head of the linked list of CalProps to free. */
static void freeCalProp(CalProp* prop) {
if(prop == NULL) {
return;
}
free(prop->name);
prop->name = NULL;
free(prop->value);
prop->value = NULL;
freeCalParam(prop->param);
free(prop->param);
prop->param = NULL;
freeCalProp(prop->next);
free(prop->next);
prop->next = NULL;
prop->nparams = 0;
}
CalStatus readCalFile( FILE *const ics, CalComp **const pcomp ) {
CalStatus status = initCalStatus(OK, 0, 0);
char* line = NULL;
assert(ics != NULL && pcomp != NULL);
readCalLine(NULL, NULL);
*pcomp = malloc(sizeof(CalComp));
assert(*pcomp != NULL);
initCalComp(*pcomp);
status = readCalComp(ics, pcomp);
if(status.code != OK) {
freeCalComp(*pcomp);
*pcomp = NULL;
return status;
}
/* file has been read successfully. performing validations below */
status.code = validateProp(*pcomp);
if(status.code != OK) {
freeCalComp(*pcomp);
*pcomp = NULL;
return status;
}
status.code = validateComp(*pcomp);
if(status.code != OK) {
freeCalComp(*pcomp);
*pcomp = NULL;
return status;
}
readCalLine(ics, &line);
if(line != NULL) {
status.code = AFTEND;
status.linefrom++;
status.lineto++;
freeCalComp(*pcomp);
*pcomp = NULL;
}
return status;
}
CalStatus readCalComp( FILE *const ics, CalComp **const pcomp ) {
CalComp comp;
CalStatus status = initCalStatus(OK, 0, 0);
CalProp prop = initCalProp();
CalProp *temp = NULL;
char* line = NULL;
static int depth = 0; /* keeps track of nested begins */
static bool firstCall = true;
const size_t size = sizeof(CalComp); /* these constants are purely for */
const size_t sizePtr = sizeof(CalComp*); /* managing readability */
int num = 0;
int lineStart = 0;
int linesRead = 0;
if(ics == NULL && pcomp == NULL) { /* reset static var */
depth = 0;
firstCall = true;
return status;
}
initCalComp(&comp);
do {
free(line);
line = NULL;
status = readCalLine(ics, &line);
if(line == NULL || status.code != OK) {
if(firstCall == true) {
lineStart = status.linefrom + 1;
linesRead = status.lineto + 1;
status = initCalStatus(NOCAL, 0, 0);
}
break;
}
if(line == NULL && depth != 0) {
status.code = BEGEND;
break;
}
status.code = parseCalProp(line, &prop);
if(status.code != OK) {
freeCalProp(&prop);
break;
}
if((*pcomp)->name == NULL && checkStart(prop) == false) {
status.code = NOCAL; /* first component isnt BEGIN:VCALENDAR */
freeCalProp(&prop);
break;
} else if((*pcomp)->name == NULL) { /* create the first compnent */
(*pcomp)->name = malloc(strlen(prop.value) + 1);
assert((*pcomp)->name != NULL);
strncpy((*pcomp)->name, prop.value, strlen(prop.value));
(*pcomp)->name[strlen(prop.value)] = '\0';
depth = 1;
freeCalProp(&prop);
prop = initCalProp();
continue;
}
if(strcmp(prop.name, "BEGIN") == 0) {
capitalize(prop.value);
if(depth >= 3) {
status.code = SUBCOM;
freeCalProp(&prop);
break;
} else { /* create a new compnent with values from prop */
comp.name = malloc(strlen(prop.value) + 1);
assert(comp.name != NULL);
strncpy(comp.name, prop.value, strlen(prop.value));
comp.name[strlen(prop.value)] = '\0';
depth++;
freeCalProp(&prop);
prop = initCalProp();
num = (*pcomp)->ncomps;
(*pcomp)->ncomps++;
*pcomp = realloc(*pcomp, size + ((*pcomp)->ncomps) * sizePtr);
(*pcomp)->comp[num] = malloc(size);
assert((*pcomp != NULL) && ((*pcomp)->comp[num] != NULL));
*((*pcomp)->comp[num]) = comp;
/* put newly created comp into the flexible array member */
status = readCalComp(ics, &((*pcomp)->comp[num]));
/* read the next compnents into the new one */
if(status.code != OK) {
break;
}
}
} else if(strcmp(prop.name, "END") == 0) {
capitalize(prop.value);
if((*pcomp)->ncomps == 0 && (*pcomp)->nprops == 0) {
status.code = NODATA;
freeCalProp(&prop);
break;
}
if(strcmp(prop.value, (*pcomp)->name) == 0) {
if(strcmp(prop.value, "VCALENDAR") != 0) {
depth--;
} /* else we are done */
freeCalProp(&prop);
break;
} else {
status.code = BEGEND;
freeCalProp(&prop);
break;
}
} else { /* ordinary property */
for(temp = (*pcomp)->prop; temp != NULL; temp = temp->next) {
if(temp->next == NULL) {
break; /* find place in linked list to copy to */
}
}
if(temp != NULL) { /* append to linked list */
temp->next = malloc(sizeof(CalProp));
assert(temp->next != NULL);
*temp->next = prop;
temp->next->next = NULL;
} else { /* start a linked list */
(*pcomp)->prop = malloc(sizeof(CalProp));
assert((*pcomp)->prop != NULL);
*(*pcomp)->prop = prop;
(*pcomp)->prop->next = NULL;
}
(*pcomp)->nprops++;
prop = initCalProp();
}
} while(line != NULL);
if(status.code == NOCAL && depth != 0) {
status = initCalStatus(BEGEND, lineStart, linesRead);
}
firstCall = false;
free(line);
return status;
}
CalStatus readCalLine( FILE *const ics, char **const pbuff ) {
static char* readAhead = NULL; /* buffer containing content on next line */
static int linesRead = 0; /* total number of lines read thus far */
static bool lastLine = false; /* used to check if EOF was hit or not */
CalError status = OK;
char buffer[BUFF_LEN] = {'\0'};
char temp [BUFF_LEN] = {'\0'};
bool folded = true;
int startLine = linesRead + 1;
int len = 0;
int i = 0;
if(ics == NULL || pbuff == NULL) { /* NULL args | prepare for a new file */
readCalComp(NULL, NULL);
free(readAhead);
readAhead = NULL;
linesRead = 0;
lastLine = false;
return initCalStatus(OK, 0, 0);
}
assert(ics != NULL && pbuff != NULL);
if(lastLine == true) { /* EOF was hit last call */
*pbuff = NULL;
return initCalStatus(status, linesRead-1, linesRead-1);
}
if(readAhead == NULL && lastLine == false) { /* first call */
if(fgets(buffer, BUFF_LEN - 1, ics) == NULL){ /* empty file */
*pbuff = NULL;
lastLine = true;
return initCalStatus(OK, 0, 0);
} else {
linesRead++;
}
if(removeCRNL(buffer) == false) {
if(fgets(temp, BUFF_LEN - 1, ics) != NULL) {
free(*pbuff);
*pbuff = NULL;
status = NOCRNL;
folded = false;
}
} else {
*pbuff = malloc(strlen(buffer) + 1);
assert(*pbuff != NULL);
strncpy(*pbuff, buffer, strlen(buffer));
(*pbuff)[strlen(buffer)] = '\0';
}
} else { /* a string was stored last call for me */
*pbuff = malloc(strlen(readAhead) + 1);
assert(*pbuff != NULL);
strncpy(*pbuff, readAhead, strlen(readAhead));
(*pbuff)[strlen(readAhead)] = '\0';
free(readAhead);
readAhead = NULL;
linesRead++;
}
while(folded == true) {
for(i = 0; i < BUFF_LEN; i++) {
buffer[i] = '\0';
}
if(fgets(buffer, BUFF_LEN - 1, ics) == NULL) {
lastLine = true; /* let next call know not to read any further */
folded = false; /* proccess remaining string, quit afterward */
free(readAhead);
readAhead = NULL;
} else if(removeCRNL(buffer) == false) {
if(fgets(temp, BUFF_LEN - 1, ics) != NULL) {
free(*pbuff);
*pbuff = NULL;
status = NOCRNL;
break;
}
}
if(isEmpty(buffer) == true) {
linesRead++;
}
folded = removeLead(buffer) && status == OK;
if(strlen(buffer) == 0) {
if(*pbuff == NULL) {
*pbuff = malloc(1);
assert(*pbuff != NULL);
(*pbuff)[0] = '\0';
}
continue;
} else if(folded == true) { /* append buffer to the end of pbuff */
if(*pbuff == NULL) {
len = strlen(buffer) + 1;
*pbuff = malloc(len);
} else {
len = strlen(*pbuff) + strlen(buffer) + 1;
*pbuff = realloc(*pbuff, len);
}
assert(*pbuff != NULL);
strncat(*pbuff, buffer, strlen(buffer));
(*pbuff)[len - 1] = '\0';
linesRead++;
} else { /* store buffer away for use on next call */
readAhead = malloc(strlen(buffer) + 1);
assert(readAhead != NULL);
strncpy(readAhead, buffer, strlen(buffer));
readAhead[strlen(buffer)] = '\0';
}
}
if(lastLine == true) {
linesRead--;
}
return initCalStatus(status, startLine, linesRead);
}
CalError parseCalProp( char *const buff, CalProp *const prop ) {
int len = strlen(buff);
char buffer[len + 1];
*prop = initCalProp();
assert(buff != NULL && prop != NULL);
strncpy(buffer, buff, len);
buffer[len] = '\0';
if(parseName(buffer, prop) == false) {
freeCalProp(prop);
*prop = initCalProp();
return SYNTAX;
}
while(parseParam(buffer, prop) == true) {
/* optional parameters */
}
if(parseValue(buffer, prop) == false) {
freeCalProp(prop);
*prop = initCalProp();
return SYNTAX;
}
return OK;
}
void freeCalComp( CalComp *const comp ) {
if(comp == NULL) {
return;
}
free(comp->name);
comp->name = NULL;
freeCalProp(comp->prop);
free(comp->prop);
comp->prop = NULL;
for(int i = 0; i < comp->ncomps; i++) {
freeCalComp(comp->comp[i]);
comp->comp[i] = NULL;
}
free(comp);
}
CalStatus writeCalComp( FILE *const ics, const CalComp *comp ) {
int lines = 0;
if(ics == NULL || comp == NULL) {
return initCalStatus(IOERR, 0, 0);
}
lines = printComp(comp, ics);
if(lines < 1) {
return initCalStatus(IOERR, (-1) * lines, (-1) * lines);
}
return initCalStatus(OK, lines, lines);
}

83
calutil.h Normal file
View File

@@ -0,0 +1,83 @@
/* caltool.h
* Author: Bronson Graansma 0872249
* Contact: bgraansm@mail.uoguelph.ca
* Date: Feb 21, 2016
* Description: Public Interface for calutil. */
#ifndef CALUTIL_H
#define CALUTIL_H A2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <stdbool.h>
#define FOLD_LEN 75 // fold lines longer than this length (RFC 5545 3.1)
#define VCAL_VER "2.0" // version of standard accepted
/* data structures for ICS file in memory */
typedef struct CalParam CalParam;
typedef struct CalParam { // property's parameter
char *name; // uppercase
CalParam *next; // linked list of parameters (ends with NULL)
int nvalues; // no. of values
char *value[]; // uppercase or "..." (flexible array member)
} CalParam;
typedef struct CalProp CalProp;
typedef struct CalProp { // (sub)component's property (=contentline)
char *name; // uppercase
char *value;
int nparams; // no. of parameters
CalParam *param; // -> first parameter (or NULL)
CalProp *next; // linked list of properties (ends with NULL)
} CalProp;
typedef struct CalComp CalComp;
typedef struct CalComp { // calendar's (sub)component
char *name; // uppercase
int nprops; // no. of properties
CalProp *prop; // -> first property (or NULL)
int ncomps; // no. of subcomponents
CalComp *comp[]; // component pointers (flexible array member)
} CalComp;
/* General status return from functions */
typedef enum { OK=0,
AFTEND, // more text found after end of calendar
BADVER, // version missing or wrong
BEGEND, // BEGIN...END not found as expected
IOERR, // I/O error
NOCAL, // outer block not VCALENDAR, or no V components found
NOCRNL, // CRNL missing at end of line
NODATA, // nothing between BEGIN...END
NOPROD, // PRODID missing
SUBCOM, // subcomponent not allowed
SYNTAX, // property not in valid form0; k < prop->nparams; k++) {
} CalError;
typedef struct {
CalError code; // error code
int linefrom, lineto; // line numbers where error occurred
} CalStatus;
/* File I/O functions */
CalStatus initCalStatus(CalError code, int linefrom, int lineto);
CalStatus readCalFile( FILE *const ics, CalComp **const pcomp );
CalStatus readCalComp( FILE *const ics, CalComp **const pcomp );
CalStatus readCalLine( FILE *const ics, char **const pbuff );
CalError parseCalProp( char *const buff, CalProp *const prop );
CalStatus writeCalComp( FILE *const ics, const CalComp *comp );
void freeCalComp( CalComp *const comp );
#endif

7
crnl.pl Normal file
View File

@@ -0,0 +1,7 @@
while(<>) {
chomp($_);
if(substr($_, length($_)-1, 1) eq "\r") {
chomp($_);
}
print("$_\r\n");
}

28
datemsk Normal file
View File

@@ -0,0 +1,28 @@
#ident "@(#)datemsk.template 1.2 99/05/10 SMI"
%m/%d/%y %I:%M:%S %p
%m/%d/%Y %I:%M:%S %p
%m/%d/%y %H:%M:%S
%m/%d/%Y %H:%M:%S
%m/%d/%y %I:%M %p
%m/%d/%Y %I:%M %p
%m/%d/%y %H:%M
%m/%d/%Y %H:%M
%m/%d/%y
%m/%d/%Y
%m/%d
%b %d, %Y %I:%M:%S %p
%b %d, %Y %H:%M:%S
%B %d, %Y %I:%M:%S %p
%B %d, %Y %H:%M:%S
%b %d, %Y %I:%M %p
%b %d, %Y %H:%M
%B %d, %Y %I:%M %p
%B %d, %Y %H:%M
%b %d, %Y
%B %d, %Y
%b %d
%B %d
%m%d%H%M%y
%m%d%H%M%Y
%m%d%H%M
%m%d

BIN
ical.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

31
ics files/a.ics Normal file
View File

@@ -0,0 +1,31 @@
BEGIN:VCALENDAR
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
VERSION:2.0
BEGIN:VTODO
LAST-MODIFIED:20160218T180655Z
DTSTAMP:20160218T180655Z
UID:3e6715c9-d01b-4166-91cb-bf9ecfc14b45
SUMMARY:Return library book
PRIORITY:1
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
erw@uoguelph.ca
DUE;TZID=America/Toronto:20160303T140000
CLASS:PUBLIC
SEQUENCE:2
X-YAHOO-YID:woofus
X-MOZ-GENERATION:2
END:VTODO
BEGIN:VTODO
LAST-MODIFIED:20160218T180738Z
DTSTAMP:20160218T180738Z
UID:1a267af7-d217-4e4e-9d14-cb998af26d36
SUMMARY:Renew magazine subscription
PRIORITY:0
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
erw@uoguelph.ca
DUE;TZID=America/Toronto:20160331T170000
CLASS:PUBLIC
SEQUENCE:0
X-YAHOO-YID:woofus
END:VTODO
END:VCALENDAR

31
ics files/b.ics Normal file
View File

@@ -0,0 +1,31 @@
BEGIN:VCALENDAR
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
VERSION:2.0
BEGIN:VTODO
LAST-MODIFIED:20160218T180655Z
DTSTAMP:20160218T180655Z
UID:3e6715c9-d01b-4166-91cb-bf9ecfc14b45
SUMMARY:Return library book
PRIORITY:1
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
erw@uoguelph.ca
DUE;TZID=America/Toronto:20160303T140000
CLASS:PUBLIC
SEQUENCE:2
X-YAHOO-YID:woofus
X-MOZ-GENERATION:2
END:VTODO
BEGIN:VTODO
LAST-MODIFIED:20160218T180738Z
DTSTAMP:20160218T180738Z
UID:1a267af7-d217-4e4e-9d14-cb998af26d36
SUMMARY:Renew magazine subscription
PRIORITY:0
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
erw@uoguelph.ca
DUE;TZID=America/Toronto:20160331T170000
CLASS:PUBLIC
SEQUENCE:0
X-YAHOO-YID:woofus
END:VTODO
END:VCALENDAR

57
ics files/demo.ics Normal file
View File

@@ -0,0 +1,57 @@
BEGIN:VCALENDAR
PRODID:demo.ics
VERSION:2.0
BEGIN:VTODO
SUMMARY:Finish A4 for Angel of Death
PRIORITY:1
ORGANIZER;CN=William Gardner:mailto:gardnerw@uoguelph.ca
LOCATION:Guelph
DTSTART:20160408T235900Z
END:VTODO
BEGIN:VTODO
SUMMARY:Finish Final Project for Marketing
PRIORITY:2
ORGANIZER;CN=Sergio Meza:mailto:smeza@uoguelph.ca
LOCATION:Guelph
DTSTART:20160409T235900Z
END:VTODO
BEGIN:VTODO
SUMMARY:Do MyEconLab
PRIORITY:3
ORGANIZER;CN=Eveline Adomait:mailto:eadomait@uoguelph.ca
LOCATION:Online
DTSTART:20160410T235900Z
END:VTODO
BEGIN:VEVENT
SUMMARY:Recruitment Session
ORGANIZER;CN=Patricia Kopec:mailto:patricia@intrigueme.ca
LOCATION:Innovation Guelph
DTSTART:20160414T190000Z
END:VEVENT
BEGIN:VEVENT
SUMMARY:PKing
ORGANIZER;CN=Bronson Graansma:mailto:bgraansm@mail.uoguelph.ca
LOCATION:Online
DTSTART:20160429T220000Z
END:VEVENT
BEGIN:VTODO
SUMMARY:Defeat the Ender Dragon
PRIORITY:4
ORGANIZER;CN=Bronson Graansma:mailto:bgraansm@mail.uoguelph.ca
LOCATION:Online
DTSTART:20160430T220000Z
END:VTODO
BEGIN:VTODO
PRIORITY:5
SUMMARY:Acquire Thunderfury, Blessed Blade of the Windseeker
ORGANIZER;CN=Bronson Graansma:mailto:bgraansm@mail.uoguelph.ca
LOCATION:Online
DTSTART:20160503T220000Z
END:VTODO
BEGIN:VEVENT
SUMMARY:New episode of Itachi-chan
ORGANIZER;CN=Rachel Beimers:mailto:rachelbunny66@hotmail.com
LOCATION:Woodstock
DTSTART:20160407T063000Z
END:VEVENT
END:VCALENDAR

1878
ics files/events.ics Normal file
View File

File diff suppressed because it is too large Load Diff

234
ics files/samp1.ics Normal file
View File

@@ -0,0 +1,234 @@
BEGIN:VCALENDAR
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/Toronto
BEGIN:DAYLIGHT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20160218T175508Z
LAST-MODIFIED:20160218T175549Z
DTSTAMP:20160218T175549Z
UID:2c8fd444-306e-416f-98ff-6af9b3a15b9b
SUMMARY:Xmas Eve
DTSTART;TZID=America/Toronto:20151224T183000
DTEND;TZID=America/Toronto:20151224T220000
TRANSP:OPAQUE
LOCATION:Sister's house
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT30M
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T175723Z
LAST-MODIFIED:20160218T175805Z
DTSTAMP:20160218T175805Z
UID:6a3af4de-8f0b-4e1f-a5eb-a89e12ec5c49
SUMMARY:choral concert
DTSTART;TZID=America/Toronto:20151214T193000
DTEND;TZID=America/Toronto:20151214T220000
TRANSP:OPAQUE
LOCATION:River Run Ctr
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT1H
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T175816Z
LAST-MODIFIED:20160218T175906Z
DTSTAMP:20160218T175906Z
UID:82c6a6d0-df41-47b7-a138-7aa089bd0fe7
SUMMARY:visit Sarah
CATEGORIES:An Outing
DTSTART;TZID=America/Toronto:20160113T190000
DTEND;TZID=America/Toronto:20160113T210000
TRANSP:OPAQUE
LOCATION:Milton
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT1H
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VEVENT
LAST-MODIFIED:20160218T180006Z
DTSTAMP:20160218T180006Z
UID:8b0ed4cb-0414-481f-9b06-0f7bdbb915d9
SUMMARY:play
PRIORITY:0
STATUS:CONFIRMED
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:ga
rdnerw@uoguelph.ca
CATEGORIES:An Outing
DTSTART;TZID=America/Toronto:20160130T143000
DTEND;TZID=America/Toronto:20160130T170000
CLASS:PUBLIC
LOCATION:Centre in Sq
SEQUENCE:0
X-YAHOO-YID:woofus
TRANSP:OPAQUE
X-YAHOO-USER-STATUS:BUSY
X-YAHOO-EVENT-STATUS:BUSY
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT1H
DESCRIPTION:Default Mozilla Description
X-LIC-ERROR;X-LIC-ERRORTYPE=VALUE-PARSE-ERROR:No value for DESCRIPTION pro
perty. Removing entire property:
END:VALARM
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T180026Z
LAST-MODIFIED:20160218T180053Z
DTSTAMP:20160218T180053Z
UID:94b97c74-9f38-4f7b-8866-f68d983db10a
SUMMARY:reading
DTSTART;TZID=America/Toronto:20160212T100000
DTEND;TZID=America/Toronto:20160212T120000
TRANSP:OPAQUE
LOCATION:library
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT15M
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T180103Z
LAST-MODIFIED:20160218T180147Z
DTSTAMP:20160218T180147Z
UID:0542340e-961a-4314-8d53-1cd84c4362b3
DTSTART;TZID=America/Toronto:20160309T080000
DTEND;TZID=America/Toronto:20160309T170000
TRANSP:OPAQUE
LOCATION:home
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T180223Z
LAST-MODIFIED:20160218T180256Z
DTSTAMP:20160218T180256Z
UID:78dfde7f-daf0-4eac-8c47-ce7c3d2c6134
SUMMARY:dinner
CATEGORIES:An Outing
DTSTART;TZID=America/Toronto:20160321T180000
DTEND;TZID=America/Toronto:20160321T200000
TRANSP:OPAQUE
LOCATION:Boston Pizza
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT30M
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T175604Z
LAST-MODIFIED:20160218T175703Z
DTSTAMP:20160218T175703Z
UID:4ec7e127-7710-43ef-b330-9125741e0b4a
SUMMARY:workout
RRULE:FREQ=WEEKLY;UNTIL=20160601T000000Z;BYDAY=TU,TH,SA
DTSTART;TZID=America/Toronto:20151201T163000
DTEND;TZID=America/Toronto:20151201T173000
TRANSP:OPAQUE
LOCATION:gym
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT15M
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VTODO
LAST-MODIFIED:20160218T180655Z
DTSTAMP:20160218T180655Z
UID:3e6715c9-d01b-4166-91cb-bf9ecfc14b45
SUMMARY:Return library book
PRIORITY:1
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:ga
rdnerw@uoguelph.ca
DUE;TZID=America/Toronto:20160303T140000
CLASS:PUBLIC
SEQUENCE:2
X-YAHOO-YID:woofus
X-MOZ-GENERATION:2
END:VTODO
BEGIN:VTODO
LAST-MODIFIED:20160218T180738Z
DTSTAMP:20160218T180738Z
UID:1a267af7-d217-4e4e-9d14-cb998af26d36
SUMMARY:Renew magazine subscription
PRIORITY:0
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:ga
rdnerw@uoguelph.ca
DUE;TZID=America/Toronto:20160331T170000
CLASS:PUBLIC
SEQUENCE:0
X-YAHOO-YID:woofus
END:VTODO
BEGIN:VTODO
LAST-MODIFIED:20160218T180836Z
DTSTAMP:20160218T180836Z
UID:58c98df4-1491-4df6-8888-cec2fe5761f5
SUMMARY:Wash car
PRIORITY:0
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:ga
rdnerw@uoguelph.ca
CLASS:PUBLIC
SEQUENCE:0
X-YAHOO-YID:woofus
END:VTODO
BEGIN:VTODO
LAST-MODIFIED:20160218T180850Z
DTSTAMP:20160218T180850Z
UID:474530b5-2ec4-410b-84a5-c6e7c279875f
SUMMARY:Buy bird seed
PRIORITY:1
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:ga
rdnerw@uoguelph.ca
CLASS:PUBLIC
SEQUENCE:1
X-YAHOO-YID:woofus
X-MOZ-GENERATION:1
END:VTODO
BEGIN:VTODO
LAST-MODIFIED:20160218T180902Z
DTSTAMP:20160218T180902Z
UID:56cdb5de-94c1-4333-bfb1-00664f91aa61
SUMMARY:Organize photos
PRIORITY:0
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:ga
rdnerw@uoguelph.ca
CLASS:PUBLIC
SEQUENCE:0
X-YAHOO-YID:woofus
END:VTODO
BEGIN:VTODO
LAST-MODIFIED:20160218T180917Z
DTSTAMP:20160218T180917Z
UID:d8040743-b11e-49b9-9e9a-41708b6bc2c8
SUMMARY:Clean out basement
PRIORITY:9
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:ga
rdnerw@uoguelph.ca
CLASS:PUBLIC
SEQUENCE:1
X-YAHOO-YID:woofus
X-MOZ-GENERATION:1
END:VTODO
END:VCALENDAR

49
ics files/samp2.ics Normal file
View File

@@ -0,0 +1,49 @@
BEGIN:VCALENDAR
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/Toronto
BEGIN:DAYLIGHT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20160218T191200Z
LAST-MODIFIED:20160218T191224Z
DTSTAMP:20160218T191224Z
UID:47889016-f868-4042-a374-bf93d2faedbc
SUMMARY:midterm exam
DTSTART;TZID=America/Toronto:20160229T123000
DTEND;TZID=America/Toronto:20160229T132000
TRANSP:OPAQUE
LOCATION:RICH 2520
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT15M
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VTODO
LAST-MODIFIED:20160218T191305Z
DTSTAMP:20160218T191305Z
UID:bf83033a-7568-42d1-a904-c7b9b5d067b2
SUMMARY:study for midterm
PRIORITY:0
ORGANIZER;CN=Joe Young;SENT-BY="mailto:jyoung@yahoo.com":mailto:youngj
@uoguelph.ca
CLASS:PUBLIC
SEQUENCE:0
X-YAHOO-YID:jyoung
END:VTODO
END:VCALENDAR

279
ics files/samp3.ics Normal file
View File

@@ -0,0 +1,279 @@
BEGIN:VCALENDAR
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:America/Toronto
BEGIN:DAYLIGHT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20160218T175508Z
LAST-MODIFIED:20160218T175549Z
DTSTAMP:20160218T175549Z
UID:2c8fd444-306e-416f-98ff-6af9b3a15b9b
SUMMARY:Xmas Eve
DTSTART;TZID=America/Toronto:20151224T183000
DTEND;TZID=America/Toronto:20151224T220000
TRANSP:OPAQUE
LOCATION:Sister's house
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT30M
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T175723Z
LAST-MODIFIED:20160218T175805Z
DTSTAMP:20160218T175805Z
UID:6a3af4de-8f0b-4e1f-a5eb-a89e12ec5c49
SUMMARY:choral concert
DTSTART;TZID=America/Toronto:20151214T193000
DTEND;TZID=America/Toronto:20151214T220000
TRANSP:OPAQUE
LOCATION:River Run Ctr
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT1H
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T175816Z
LAST-MODIFIED:20160218T175906Z
DTSTAMP:20160218T175906Z
UID:82c6a6d0-df41-47b7-a138-7aa089bd0fe7
SUMMARY:visit Sarah
CATEGORIES:An Outing
DTSTART;TZID=America/Toronto:20160113T190000
DTEND;TZID=America/Toronto:20160113T210000
TRANSP:OPAQUE
LOCATION:Milton
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT1H
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VEVENT
LAST-MODIFIED:20160218T180006Z
DTSTAMP:20160218T180006Z
UID:8b0ed4cb-0414-481f-9b06-0f7bdbb915d9
SUMMARY:play
PRIORITY:0
STATUS:CONFIRMED
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
erw@uoguelph.ca
CATEGORIES:An Outing
DTSTART;TZID=America/Toronto:20160130T143000
DTEND;TZID=America/Toronto:20160130T170000
CLASS:PUBLIC
LOCATION:Centre in Sq
SEQUENCE:0
X-YAHOO-YID:woofus
TRANSP:OPAQUE
X-YAHOO-USER-STATUS:BUSY
X-YAHOO-EVENT-STATUS:BUSY
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT1H
DESCRIPTION:Default Mozilla Description
X-LIC-ERROR;X-LIC-ERRORTYPE=VALUE-PARSE-ERROR:No value for DESCRIPTION prop
erty. Removing entire property:
END:VALARM
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T180026Z
LAST-MODIFIED:20160218T180053Z
DTSTAMP:20160218T180053Z
UID:94b97c74-9f38-4f7b-8866-f68d983db10a
SUMMARY:reading
DTSTART;TZID=America/Toronto:20160212T100000
DTEND;TZID=America/Toronto:20160212T120000
TRANSP:OPAQUE
LOCATION:library
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT15M
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T180103Z
LAST-MODIFIED:20160218T180147Z
DTSTAMP:20160218T180147Z
UID:0542340e-961a-4314-8d53-1cd84c4362b3
DTSTART;TZID=America/Toronto:20160309T080000
DTEND;TZID=America/Toronto:20160309T170000
TRANSP:OPAQUE
LOCATION:home
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T180223Z
LAST-MODIFIED:20160218T180256Z
DTSTAMP:20160218T180256Z
UID:78dfde7f-daf0-4eac-8c47-ce7c3d2c6134
SUMMARY:dinner
CATEGORIES:An Outing
DTSTART;TZID=America/Toronto:20160321T180000
DTEND;TZID=America/Toronto:20160321T200000
TRANSP:OPAQUE
LOCATION:Boston Pizza
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT30M
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T175604Z
LAST-MODIFIED:20160218T175703Z
DTSTAMP:20160218T175703Z
UID:4ec7e127-7710-43ef-b330-9125741e0b4a
SUMMARY:workout
RRULE:FREQ=WEEKLY;UNTIL=20160601T000000Z;BYDAY=TU,TH,SA
DTSTART;TZID=America/Toronto:20151201T163000
DTEND;TZID=America/Toronto:20151201T173000
TRANSP:OPAQUE
LOCATION:gym
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT15M
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VTODO
LAST-MODIFIED:20160218T180655Z
DTSTAMP:20160218T180655Z
UID:3e6715c9-d01b-4166-91cb-bf9ecfc14b45
SUMMARY:Return library book
PRIORITY:1
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
erw@uoguelph.ca
DUE;TZID=America/Toronto:20160303T140000
CLASS:PUBLIC
SEQUENCE:2
X-YAHOO-YID:woofus
X-MOZ-GENERATION:2
END:VTODO
BEGIN:VTODO
LAST-MODIFIED:20160218T180738Z
DTSTAMP:20160218T180738Z
UID:1a267af7-d217-4e4e-9d14-cb998af26d36
SUMMARY:Renew magazine subscription
PRIORITY:0
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
erw@uoguelph.ca
DUE;TZID=America/Toronto:20160331T170000
CLASS:PUBLIC
SEQUENCE:0
X-YAHOO-YID:woofus
END:VTODO
BEGIN:VTODO
LAST-MODIFIED:20160218T180836Z
DTSTAMP:20160218T180836Z
UID:58c98df4-1491-4df6-8888-cec2fe5761f5
SUMMARY:Wash car
PRIORITY:0
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
erw@uoguelph.ca
CLASS:PUBLIC
SEQUENCE:0
X-YAHOO-YID:woofus
END:VTODO
BEGIN:VTODO
LAST-MODIFIED:20160218T180850Z
DTSTAMP:20160218T180850Z
UID:474530b5-2ec4-410b-84a5-c6e7c279875f
SUMMARY:Buy bird seed
PRIORITY:1
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
erw@uoguelph.ca
CLASS:PUBLIC
SEQUENCE:1
X-YAHOO-YID:woofus
X-MOZ-GENERATION:1
END:VTODO
BEGIN:VTODO
LAST-MODIFIED:20160218T180902Z
DTSTAMP:20160218T180902Z
UID:56cdb5de-94c1-4333-bfb1-00664f91aa61
SUMMARY:Organize photos
PRIORITY:0
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
erw@uoguelph.ca
CLASS:PUBLIC
SEQUENCE:0
X-YAHOO-YID:woofus
END:VTODO
BEGIN:VTODO
LAST-MODIFIED:20160218T180917Z
DTSTAMP:20160218T180917Z
UID:d8040743-b11e-49b9-9e9a-41708b6bc2c8
SUMMARY:Clean out basement
PRIORITY:9
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
erw@uoguelph.ca
CLASS:PUBLIC
SEQUENCE:1
X-YAHOO-YID:woofus
X-MOZ-GENERATION:1
END:VTODO
BEGIN:VTIMEZONE
TZID:America/Toronto
BEGIN:DAYLIGHT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20160218T191200Z
LAST-MODIFIED:20160218T191224Z
DTSTAMP:20160218T191224Z
UID:47889016-f868-4042-a374-bf93d2faedbc
SUMMARY:midterm exam
DTSTART;TZID=America/Toronto:20160229T123000
DTEND;TZID=America/Toronto:20160229T132000
TRANSP:OPAQUE
LOCATION:RICH 2520
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT15M
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VTODO
LAST-MODIFIED:20160218T191305Z
DTSTAMP:20160218T191305Z
UID:bf83033a-7568-42d1-a904-c7b9b5d067b2
SUMMARY:study for midterm
PRIORITY:0
ORGANIZER;CN=Joe Young;SENT-BY="mailto:jyoung@yahoo.com":mailto:youngj@uogu
elph.ca
CLASS:PUBLIC
SEQUENCE:0
X-YAHOO-YID:jyoung
END:VTODO
END:VCALENDAR

140
ics files/samp4.ics Normal file
View File

@@ -0,0 +1,140 @@
BEGIN:VCALENDAR
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
VERSION:2.0
BEGIN:VEVENT
CREATED:20160218T175508Z
LAST-MODIFIED:20160218T175549Z
DTSTAMP:20160218T175549Z
UID:2c8fd444-306e-416f-98ff-6af9b3a15b9b
SUMMARY:Xmas Eve
DTSTART;TZID=America/Toronto:20151224T183000
DTEND;TZID=America/Toronto:20151224T220000
TRANSP:OPAQUE
LOCATION:Sister's house
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT30M
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T175723Z
LAST-MODIFIED:20160218T175805Z
DTSTAMP:20160218T175805Z
UID:6a3af4de-8f0b-4e1f-a5eb-a89e12ec5c49
SUMMARY:choral concert
DTSTART;TZID=America/Toronto:20151214T193000
DTEND;TZID=America/Toronto:20151214T220000
TRANSP:OPAQUE
LOCATION:River Run Ctr
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT1H
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T175816Z
LAST-MODIFIED:20160218T175906Z
DTSTAMP:20160218T175906Z
UID:82c6a6d0-df41-47b7-a138-7aa089bd0fe7
SUMMARY:visit Sarah
CATEGORIES:An Outing
DTSTART;TZID=America/Toronto:20160113T190000
DTEND;TZID=America/Toronto:20160113T210000
TRANSP:OPAQUE
LOCATION:Milton
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT1H
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VEVENT
LAST-MODIFIED:20160218T180006Z
DTSTAMP:20160218T180006Z
UID:8b0ed4cb-0414-481f-9b06-0f7bdbb915d9
SUMMARY:play
PRIORITY:0
STATUS:CONFIRMED
ORGANIZER;CN=William Gardner;SENT-BY="mailto:woofus@yahoo.com":mailto:gardn
erw@uoguelph.ca
CATEGORIES:An Outing
DTSTART;TZID=America/Toronto:20160130T143000
DTEND;TZID=America/Toronto:20160130T170000
CLASS:PUBLIC
LOCATION:Centre in Sq
SEQUENCE:0
X-YAHOO-YID:woofus
TRANSP:OPAQUE
X-YAHOO-USER-STATUS:BUSY
X-YAHOO-EVENT-STATUS:BUSY
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT1H
DESCRIPTION:Default Mozilla Description
X-LIC-ERROR;X-LIC-ERRORTYPE=VALUE-PARSE-ERROR:No value for DESCRIPTION prop
erty. Removing entire property:
END:VALARM
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T180026Z
LAST-MODIFIED:20160218T180053Z
DTSTAMP:20160218T180053Z
UID:94b97c74-9f38-4f7b-8866-f68d983db10a
SUMMARY:reading
DTSTART;TZID=America/Toronto:20160212T100000
DTEND;TZID=America/Toronto:20160212T120000
TRANSP:OPAQUE
LOCATION:library
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT15M
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T180103Z
LAST-MODIFIED:20160218T180147Z
DTSTAMP:20160218T180147Z
UID:0542340e-961a-4314-8d53-1cd84c4362b3
DTSTART;TZID=America/Toronto:20160309T080000
DTEND;TZID=America/Toronto:20160309T170000
TRANSP:OPAQUE
LOCATION:home
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T180223Z
LAST-MODIFIED:20160218T180256Z
DTSTAMP:20160218T180256Z
UID:78dfde7f-daf0-4eac-8c47-ce7c3d2c6134
SUMMARY:dinner
CATEGORIES:An Outing
DTSTART;TZID=America/Toronto:20160321T180000
DTEND;TZID=America/Toronto:20160321T200000
TRANSP:OPAQUE
LOCATION:Boston Pizza
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT30M
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
BEGIN:VEVENT
CREATED:20160218T175604Z
LAST-MODIFIED:20160218T175703Z
DTSTAMP:20160218T175703Z
UID:4ec7e127-7710-43ef-b330-9125741e0b4a
SUMMARY:workout
RRULE:FREQ=WEEKLY;UNTIL=20160601T000000Z;BYDAY=TU,TH,SA
DTSTART;TZID=America/Toronto:20151201T163000
DTEND;TZID=America/Toronto:20151201T173000
TRANSP:OPAQUE
LOCATION:gym
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-PT15M
DESCRIPTION:Default Mozilla Description
END:VALARM
END:VEVENT
END:VCALENDAR

0
ics files/test.ics Normal file
View File

19
makefile Normal file
View File

@@ -0,0 +1,19 @@
CC = gcc
CFLAGS = -Wall -std=c11 -g -fPIC `pkg-config --cflags python3`
LDFLAGS =
all: caltool Cal.so
caltool: caltool.o calutil.o
caltool.o: caltool.c caltool.h
calutil.o: calutil.c calutil.h
Cal.so: calmodule.o calutil.o
$(CC) -shared $^ $(LDFLAGS) -o $@
calmodule.o: calmodule.c calutil.h
clean:
rm -f *.o caltool Cal.so

1078
xcal.py Executable file
View File

File diff suppressed because it is too large Load Diff