summaryrefslogtreecommitdiff
path: root/localmarkdown2sms
blob: 6a4a9cf82d2c045a1bb262d208686956cdb2d080 (plain)
  1. #!/usr/bin/perl
  2. #
  3. # /usr/local/sbin/localmarkdown2sms
  4. # Copyright 2009 Jonas Smedegaard <dr@jones.dk>
  5. #
  6. # Send series of messages through Kannel from simplified Markdown files
  7. # * Lines starting with "#" are "keywords" activating a message series
  8. # * write only a single word
  9. # * use each keyword only once across the whole system
  10. # * use only minuscles (not majuscles, i.e. CAPITAL LETTERS)
  11. # * Lines starting with "##" express pauses
  12. # * a pause is a number + a single letter, without spaces between
  13. # * a pause line can contain multiple pauses, separated by space
  14. # Suggestion for writing style:
  15. #
  16. # * Write explicitly how to activate next series
  17. # * pick keywords tied to nex series rather than the previous
  18. # * use same instruction jargon across all series in the system
  19. use strict;
  20. use warnings;
  21. use Env qw[$DEBUG $DUMMY $NOSLEEP];
  22. use File::Spec;
  23. use File::Slurp;
  24. use Time::Duration::Parse;
  25. #use Proc::Daemon;
  26. use Proc::Fork;
  27. #use IO::Pipe;
  28. #Proc::Daemon::Init;
  29. my (%delay, %reply);
  30. my ($path) = shift @ARGV;
  31. foreach my $file (read_dir( $path )) {
  32. my ($key, $i);
  33. next unless ($file =~ /\.mdwn$/);
  34. foreach my $line (read_file( File::Spec->catfile($path, $file))) {
  35. chomp $line;
  36. my $content;
  37. # headline
  38. if ($line =~ /^(#+)\s*(.*?)\s*$/) {
  39. # tidy latest reply (TODO: use sub)
  40. if (defined($i) and defined($reply{$key}[$i])) {
  41. $reply{$key}[$i] =~ s/^\s*(\w.*?)\s*$/$1/s || delete $reply{$key}[$i];
  42. }
  43. my $level = length($1);
  44. $content = $2;
  45. # key
  46. if ($level == 1 and $content =~ /(\w+)/) {
  47. $key = lc($1);
  48. $i = 0;
  49. if (lc($content) ne $key) {
  50. warn( "key \"$key\" extracted from fuzzy string \"$content\" in file \"$file\"" );
  51. }
  52. if (!defined( $delay{$key})) {
  53. $delay{$key}[0] = 0;
  54. } else {
  55. warn( "skipping non-unique key \"$key\" in file \"$file\"" );
  56. $key = undef;
  57. }
  58. # delay
  59. } elsif ($level == 2 and $content =~ /(\d+[sm](\s+|\Z))+/) {
  60. if (defined( $key)) {
  61. my $delay = parse_duration($1);
  62. if (defined($reply{$key}[$i])) {
  63. $i++;
  64. $delay{$key}[$i] = $delay{$key}[$i - 1];
  65. }
  66. $delay{$key}[$i] += $delay;
  67. if ($content ne $1) {
  68. warn( "delay (${delay}s) resolved from fuzzy string \"$content\" in file \"$file\"" );
  69. }
  70. } else {
  71. warn( "skipping non-key'ed delay line \"$1\" in file \"$file\"" );
  72. }
  73. } else {
  74. warn( "skipping non-parsable headline \"$line\" in file \"$file\"");
  75. }
  76. # reply
  77. } else {
  78. $content = $reply{$key}[$i] if (defined($reply{$key}[$i]));
  79. $content .= $line . "\n";
  80. $content =~ s/^\h*$//g; # clean virtually empty lines
  81. $content =~ s/(\S)\h$/$1/g; # strip single trailing space
  82. $content =~ s/\n\n+/\n\n/g; # strip excess newlines
  83. $content =~ s/(\S)\n([^\n])/$1 $2/g; # convert newline to space
  84. $content =~ s/\h*$//g; # strip all trailing spaces
  85. if ( defined( $key )) {
  86. $reply{$key}[$i] = $content;
  87. } else {
  88. warn( "skipping non-key'ed content \"$1\" in file \"$file\"" );
  89. }
  90. }
  91. }
  92. # tidy latest reply (TODO: use sub)
  93. if (defined($i) and defined($reply{$key}[$i])) {
  94. $reply{$key}[$i] =~ s/^\s*(\w.*?)\s*$/$1/s || delete $reply{$key}[$i];
  95. }
  96. }
  97. my ($phone) = shift @ARGV;
  98. my ($key) = shift @ARGV;
  99. my $num_children = $#{ $reply{$key} } + 1; # How many children we'll create
  100. $SIG{CHLD} = 'IGNORE'; # Don't worry about reaping zombies
  101. # Spawn off some children
  102. if ($DEBUG) {
  103. print STDERR "queueing $num_children replies:";
  104. for my $num ( 0 .. $num_children - 1 ) {
  105. print STDERR " [" . $delay{$key}[$num] . "s]";
  106. }
  107. print STDERR "\n";
  108. }
  109. for my $num ( 0 .. $num_children - 1 ) {
  110. run_fork {
  111. child {
  112. sleep($delay{$key}[$num]) unless ($NOSLEEP);
  113. unless ($DUMMY) {
  114. system {'/usr/share/kannel/contrib/sendsms' } $phone, $reply{$key}[$num];
  115. print STDERR "Done reply #$num [" . $delay{$key}[$num] . "s]\n" if ($DEBUG);
  116. } else {
  117. print STDERR "\n[" . $delay{$key}[$num] . "s]\n";
  118. print STDERR $reply{$key}[$num] . "\n";
  119. }
  120. exit;
  121. }
  122. parent {
  123. if ($DEBUG) {
  124. my $child_pid = shift;
  125. waitpid $child_pid, 0;
  126. }
  127. }
  128. }
  129. }
  130. 1;