1 package Gruta
::Source
::Mbox
;
3 # WARNING: This backend is DEPRECATED. Use it at your own risk.
5 use base
'Gruta::Source::BASE';
12 sub _rfc822_to_gruta
{
13 # converts an RFC822-style Date to Gruta
17 $date =~ s/^\w{3},\s+//;
18 my ($d, $m, $y, $H, $M, $S) =
19 ($date =~ /(\d+)\s+(\w+)\s+(\d+)\s(\d+):(\d+):(\d+)/);
21 return sprintf("%04d%02d%02d%02d%02d%02d",
22 $y, $self->{_month_hash
}->{$m}, $d, $H, $M, $S);
26 package Gruta
::Data
::Mbox
::BASE
;
31 package Gruta
::Data
::Mbox
::Story
;
35 use base
'Gruta::Data::Story';
36 use base
'Gruta::Data::Mbox::BASE';
42 $driver = $self->source( $driver );
44 if (my $s = $driver->{stories_h
}->{$self->get('id')}) {
47 open F
, $driver->{file
} or
48 croak
"Can't open '$driver->{file}'";
50 seek F
, $s->{offset
}, 0;
60 $self->set('title', $s->{title
});
61 $self->set('date', $s->{date
});
62 $self->set('format', $s->{format
} || 'grutatxt');
63 $self->set('hits', 0);
64 $self->set('ctime', 0);
65 $self->set('userid', '');
66 $self->set('content', $c);
77 # get tags from the index
78 my $s = $self->source->{stories_h
}->{$self->get('id')};
80 @ret = split(/\s*,\s*/, $s->{tags
});
86 package Gruta
::Data
::Mbox
::Topic
;
88 use base
'Gruta::Data::Topic';
89 use base
'Gruta::Data::Mbox::BASE';
91 package Gruta
::Source
::Mbox
;
98 $self->{file
} or croak
"Mandatory file";
106 open M
, $self->{file
} or
107 croak
"Can't open '$self->{file}'";
116 if (/^From / .. /^$/) {
122 if (/^Message-ID:\s*(.+)$/i) {
125 my $md5 = Digest
::MD5
->new();
128 $r->{id
} = $md5->hexdigest();
130 elsif (/^Subject:\s*(.+)$/i) {
133 elsif (/^Date:\s*(.+)$/i) {
134 $r->{date
} = $self->_rfc822_to_gruta($1);
136 elsif (/^X-Format:\s*(.+)$/i) {
139 elsif (/^Content-Type:\s*.*text\/html
/i
and not $r->{format
}) {
140 $r->{format
} = 'filtered_html';
142 elsif (/^X-Tags:\s*(.+)$/i || /^Keywords:\s*(.+)$/i) {
146 $r->{offset
} = tell(M
);
156 # store stories in reverse date order
157 $self->{stories_l
} = [ sort { $b->{date
} <=> $a->{date
} } @s ];
158 $self->{stories_h
} = { %h };
167 open O
, '>' . $self->{index_file
} or
168 croak
"Can't write '$self->{index_file}'";
171 foreach my $s (@
{ $self->{stories_l
} }) {
172 print O
join('|', $s->{id
}, $s->{title
},
173 $s->{date
}, $s->{offset
},
174 $s->{format
} || 'grutatxt', $s->{tags
} || ''),
187 open I
, $self->{index_file
} or
188 croak
"Can't open '$self->{index_file}'";
198 ($r->{id
}, $r->{title
}, $r->{date
},
199 $r->{offset
}, $r->{format
}, $r->{tags
}) =
205 $self->{stories_l
} = [ @s ];
206 $self->{stories_h
} = { %h };
217 if (not -f
$self->{index_file
} or
218 -M
$self->{index_file
} > -M
$self->{file
}) {
219 $self->_build_index->_save_index();
222 $self->_load_index();
235 if ($self->{topic_id
} eq $id) {
236 $topic = Gruta
::Data
::Mbox
::Topic
->new(
238 name
=> $self->{topic_name
},
249 return ($_[0]->{topic_id
}) ;
254 my $topic_id = shift;
259 if ($self->{topic_id
} eq $topic_id) {
261 $story = Gruta
::Data
::Mbox
::Story
->new (
262 id
=> $id, topic_id
=> $topic_id )->load($self);
270 my $topic_id = shift;
274 if ($self->{topic_id
} eq $topic_id) {
275 @r = map { $_->{id
} } @
{ $self->{stories_l
} };
282 sub stories_by_date
{
290 $topic_id = $self->{topic_id
};
293 $topic_id = $topics->[0];
297 $args{offset
} = 0 if $args{offset
} < 0;
302 if ($self->{topic_id
} eq $topic_id) {
303 foreach my $s (@
{ $self->{stories_l
} }) {
304 my $date = $s->{date
};
306 # skip future stories
307 next if not $args{future
} and
309 $date > $args{today
};
311 # skip if date is above the threshold
312 next if $args{'to'} and $date > $args{'to'};
314 # exit if date is below the threshold
315 last if $args{'from'} and $date < $args{'from'};
317 # skip offset stories
318 next if $args{'offset'} and ++$o <= $args{'offset'};
320 push(@r, [ $topic_id, $s->{id
}, $date ]);
322 # exit if we have all we need
323 last if $args{'num'} and $args{'num'} == scalar(@r);
332 my $topic_id = shift;
336 # not this topic? return
337 if ($self->{topic_id
} ne $topic_id) {
342 my @q = split(/\s+/,$query);
344 foreach my $e (@
{$self->{stories_l
}}) {
346 my $story = $self->story($topic_id, $e->{id
});
347 my $content = $story->get('content');
350 # try complete query first
351 if ($content =~ /\b$query\b/i) {
357 if(length($q) > 1 and $content =~ /\b$q\b/i) {
363 push(@ret, $e->{id
}) if $found == scalar(@q);
378 $topic_id = $self->{topic_id
};
381 $topic_id = $topics->[0];
384 # not this topic? return
385 if ($self->{topic_id
} ne $topic_id) {
389 my @tags = map { lc($_) } split(/\s*,\s*/, $tag);
392 foreach my $e (@
{$self->{stories_l
}}) {
393 my @ts = split(/\s*,\s*/, $e->{tags
});
395 # skip stories with less tags than the wanted ones
396 if (scalar(@ts) < scalar(@tags)) {
403 foreach my $t (@ts) {
404 if (grep(/^\Q$t\E$/, @tags)) {
409 if ($c >= scalar(@tags)) {
411 # if no future stories are wanted, discard them
413 if ($e->{date
} > Gruta
::Data
::today
()) {
418 push(@ret, [ $topic_id, $e->{id
}, $e->{date
} ]);
432 foreach my $e (@
{$self->{stories_l
}}) {
433 my $tags = $e->{tags
};
435 foreach my $t (split(/\s*,\s*/, $tags)) {
440 foreach my $k (keys(%h)) {
441 push(@ret, [ $k, $h{$k} ]);
451 my $s = bless( { @_ }, $class);
455 if (!$s->{topic_id
}) {
456 my ($topic_id) = ($s->{file
} =~ /^(\w+)\.?.*$/);
457 $s->{topic_id
} = $topic_id;
460 if (!$s->{topic_name
}) {
461 $s->{topic_name
} = $s->{topic_id
};
464 if (!$s->{index_file
}) {
465 $s->{index_file
} = '/tmp/' . $s->{topic_id
} . '.idx';
469 my %m = map { $_ => ++$n }
470 qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
472 $s->{_month_hash
} = { %m };