#!/usr/bin/perl
my $cwd=".";
use lib ".";
################################################################
# #
# ToDo 1.1 #
# (C) 2000-2001 Arvydas Strausas #
# For more information, see: http://www.cgibiz.com/ #
# #
################################################################
# #
# This program is free software; you can redistribute it #
# and/or modify it under the terms of the GNU General Public #
# License as published by the Free Software Foundation; either #
# version 2 of the License, or (at your option) any later #
# version. #
# #
# This program is distributed in the hope that it will be #
# useful, but WITHOUT ANY WARRANTY; without even the implied #
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR #
# PURPOSE. See the GNU General Public License for more #
# details. #
# #
################################################################
use integer;
use Time::Local;
use cg;
require "todo.ini";
$cg::params{"version"} = "Powered by ToDo 1.1";
my $db = $cg::params{"db"};
my $password = $cg::params{"password"};
my $expires = $cg::params{"remember"} eq "yes" ? -1 : 0;
my $crypted = -1;
my $command = $cg::params{"command"};
my $display = $cg::params{"display"}; $display = $ini::default_display if !$display;
my $template = $cg::params{"template"}; $template = $ini::default_template if !$template;
my $task_id = $cg::params{"task_id"};
my @categories;
my @tasks;
my $i;
my $s;
my @ar;
foreach("db", "password", "remember", "show_due", "show_category", "show_priority", "show_done", "sort_field", "sort_order") {
cg::cookie($_, $cg::params{$_}, $expires);
}
cg::content_type("text/html");
if($command eq "prepare") {
$crypted = encrypt($password, $db);
mkdir("$ini::data_dir/$db", 0755) or cg::error("$ini::data_dir/$db");
open(PASSWORD, ">$ini::data_dir/$db/password.txt") or cg::error("$ini::data_dir/$db/password.txt");
print(PASSWORD $crypted);
close(PASSWORD);
@categories = @ini::default_categories;
save_categories();
open(TASKS, ">$ini::data_dir/$db/tasks.txt") or cg::error("$ini::data_dir/$db/tasks.txt");
close(TASKS);
} else {
if(open(PASSWORD, "$ini::data_dir/$db/password.txt")) {
$crypted = ;
close(PASSWORD);
}
}
if($command eq "signup") {
$display = $template = "signup";
} elsif(encrypt($password, $db) ne $crypted) {
$display = $template = "signin";
} else {
if($command ne "prepare") {
open(CATEGORIES, "$ini::data_dir/$db/categories.txt") or cg::error("$ini::data_dir/$db/categories.txt");
while() {
chop; push(@categories, $_ eq "" ? "n/a" : $_);
}
close(CATEGORIES);
}
if($command eq "show") {
if($task_id) {
open(TASKS, "$ini::data_dir/$db/tasks.txt") or cg::error("$ini::data_dir/$db/tasks.txt");
while() {
if(index($_, $task_id) == 0) {
set_task_params(split(/\t/));
last;
}
}
close(TASKS);
}
} elsif($command eq "save") {
my $task_due = $cg::params{"task_due"};
my $task_category = $cg::params{"task_category"};
my $task_priority = $cg::params{"task_priority"};
my $task = $cg::params{"task"}; $task =~ s/\"/\"\;/gos;
my $task_note = $cg::params{"task_note"}; $task_note =~ s/\n/\%0A/go; $task_note =~ s/\"/\"\;/gos;
my $task_done = $cg::params{"task_done"} eq "yes" ? "!\n" : "\n";
if($task_due eq "today") {
$task_due = $cg::now - $cg::now % 86400 + 86399;
} elsif($task_due eq "tomorrow") {
$task_due = $cg::now - $cg::now % 86400 + 172799;
} elsif($task_due eq "next_week") {
$task_due = $cg::now - $cg::now % 86400 + 604799;
} elsif(index($task_due, "/") > 0) {
@ar = split(/\//, $task_due);
$task_due = timegm(0, 0, 0, $ar[1], $ar[0] - 1, $ar[2] > 99 ? $ar[2] : $ar[2] + 2000) + 86399 - $ini::time_offset;
}
if(($i = get_category_index($task_category)) >= @categories) {
push(@categories, $task_category);
save_categories();
}
$task_category = $i;
@ar = ($task_id, $task_due, $task_category, $task_priority, $task, $task_note, $task_done);
open(TASKS, "+<$ini::data_dir/$db/tasks.txt") or cg::error("$ini::data_dir/$db/tasks.txt");
@tasks = ;
seek(TASKS, 0, 0);
if($task_id) {
delete_task();
} else {
$ar[0] = $cg::now;
}
if($task_due) {
for($i = 0; $i < @tasks; $i++) {
$s = (split(/\t/, $tasks[$i]))[1];
if($s > $task_due || !$s) {
last;
}
}
@tasks = (@tasks[0..$i - 1], join("\t", @ar), @tasks[$i..@tasks - 1]);
} else {
push(@tasks, join("\t", @ar));
}
print(TASKS @tasks);
truncate(TASKS, tell(TASKS));
close(TASKS);
set_task_params(@ar);
} elsif($command eq "delete") {
open(TASKS, "+<$ini::data_dir/$db/tasks.txt") or cg::error("$ini::data_dir/$db/tasks.txt");
@tasks = ;
seek(TASKS, 0, 0);
delete_task();
print(TASKS @tasks);
truncate(TASKS, tell(TASKS));
close(TASKS);
}
}
if($display eq "list") {
my $show_due = $cg::params{"show_due"};
my $show_category = $cg::params{"show_category"}; $show_category = get_category_index($show_category) if $show_category;
my $show_priority = $cg::params{"show_priority"}; $show_priority = "LMH" if !$show_priority;
my $show_done = $cg::params{"show_done"} eq "yes" ? 2 : 1;
my $sort_field = $cg::params{"sort_field"};
my $sort_order = $cg::params{"sort_order"};
my $since = 0;
my $until = 1999999999;
my $j;
if($show_due eq "past") {
$since = 1;
$until = $cg::now;
} elsif($show_due eq "today") {
$since = $cg::now / 86400 * 86400;
$until = $since + 86399;
} elsif($show_due eq "tomorrow") {
$since = $cg::now / 86400 * 86400 + 86400;
$until = $since + 86399;
} elsif($show_due eq "week") {
$since = get_week($cg::now);
$until = $since + 604799;
} elsif($show_due eq "month") {
$since = get_month($cg::now);
$until = $since + 86400 * days_in_month($cg::now) - 1;
}
if(!@tasks) {
open(TASKS, "$ini::data_dir/$db/tasks.txt") or cg::error("$ini::data_dir/$db/tasks.txt");
@tasks = ;
close(TASKS);
}
for($i = 0, $j = 0; $i < @tasks; $i++) {
my @ar = split(/\t/, $tasks[$i]);
if($since <= $ar[1] && $ar[1] <= $until &&
(!$show_category || $show_category == $ar[2]) &&
index($show_priority, $ar[3]) >= 0 &&
length($ar[6]) <= $show_done) {
$tasks[$j++] = \@ar;
}
}
@tasks = @tasks[0..$j - 1];
if($sort_field >= 0) {
@tasks = $sort_order < 0
? sort({$a->[$sort_field] cmp $b->[$sort_field]} @tasks)
: sort({$b->[$sort_field] cmp $a->[$sort_field]} @tasks);
}
} else {
undef(@tasks);
}
open(TEMPLATE, "$ini::templates_dir/$template.html") or cg::error("$ini::templates_dir/$template.html");
while(defined($s = )) {
if(index($s, "\$category") >= 0) {
foreach(@categories) {
$cg::params{"category"} = $_;
$i = $s; $i =~ s/\$(\w+)/$cg::params{$1}/ges;
cg::print($i);
}
} elsif(index($s, "\$task") >= 0 && @tasks) {
foreach(@tasks) {
set_task_params(@{$_});
$i = $s; $i =~ s/\$(\w+)/$cg::params{$1}/ges;
cg::print($i);
}
} else {
$s =~ s/\$(\w+)/$cg::params{$1}/ges;
cg::print($s);
}
}
close(TEMPLATE);
#######
sub encrypt { # $encrypted ($password, $key)
#######
return $_[0] ? crypt($_[0], $_[1]) : "";
}
########
sub get_week { # ($time)
########
my($second,
$minute,
$hour,
$day,
$month,
$year,
$wday) = gmtime($_[0]);
return $_[0] / 86400 * 86400 - ($wday ? $wday - 1 : 6) * 86400;
}
#########
sub get_month { # ($time)
#########
my($second,
$minute,
$hour,
$day,
$month,
$year) = gmtime($_[0]);
return $_[0] / 86400 * 86400 - ($day - 1) * 86400;
}
#############
sub days_in_month { # ($time)
#############
my($second,
$minute,
$hour,
$day,
$month,
$year) = gmtime($_[0]);
if(!($year % 4) && $month == 2) {
return 28;
}
return 31 - $month % 2;
}
##################
sub get_category_index { # $index ($category) {@categories}
##################
my $i;
for($i = 0; $i < @categories; $i++) {
if($categories[$i] eq $_[0]) {
last;
}
}
return $i;
}
###############
sub save_categories {
###############
open(CATEGORIES, ">$ini::data_dir/$db/categories.txt") or cg::error("$ini::data_dir/$db/categories.txt");
$, = "\n";
print(CATEGORIES @categories);
print(CATEGORIES "\n");
$, = "";
close(CATEGORIES);
}
###########
sub delete_task { {$task_id}
###########
my $i;
for($i = 0; $i < @tasks; $i++) {
if(index($tasks[$i], $task_id) == 0) {
@tasks = (@tasks[0..$i - 1], @tasks[$i + 1..@tasks - 1]);
last;
}
}
}
###############
sub set_task_params { # (@task)
###############
$cg::params{"task_id"} = $_[0];
$cg::params{"task_due"} = $_[1] ? format_time($_[1]) : "";
$cg::params{"task_category"} = $categories[$_[2]];
$cg::params{"task_priority"} = $_[3];
$cg::params{"task"} = $_[4];
$cg::params{"encoded_task_note"} = $_[5];
$cg::params{"task_note"} = $_[5]; $cg::params{"task_note"} =~ s/\%0A/\n/gos;
$cg::params{"task_done"} = length($_[6]) > 1 ? "yes" : "no";
}
###########
sub format_time { # $time ($time)
###########
my($second,
$minute,
$hour,
$day,
$month,
$year) = gmtime($_[0] + $ini::time_offset);
return sprintf("%02d/%02d/%02d", $month + 1, $day, $year > 99 ? $year - 100 : $year);
}