+sub open_browser{
+ my ($file) = @_;
+ fork_exec('sensible-browser',$file);
+}
+
+sub open_entry{
+ my ($dbh,$sth,$entry,$options) = @_;
+
+ return unless defined $entry and ref $entry and keys %{$entry};
+ if ($DEBUG) {
+ print STDERR "Entry: \n";
+ p $entry;
+ }
+ if (defined $entry->{file_name} and length $entry->{file_name}) {
+ my $paper = select_one($dbh,$sth->{select_papers_by_name},$entry->{file_name});
+ if (not defined $paper) {
+ my ($pmid) = $entry->{file_name} =~ /pmid_(\d+)/;
+ if (defined $pmid and length $pmid) {
+ $paper = select_one($dbh,$sth->{select_papers_by_pmid},'%pmid_'.$pmid.'.%');
+ }
+ }
+ p $paper if $DEBUG;
+ print STDERR $entry->{file_name} if $DEBUG;
+ if (defined $paper) {
+ if ($options->{only_print}) {
+ print $paper->{path};
+ return;
+ }
+ open_pdf($paper->{path},$options,$paper->{has_xoj});
+ return;
+ } else {
+ print STDERR "Unable to find paper\n" if $DEBUG;
+ }
+ }
+ if (defined $entry->{doi}) {
+ if ($options->{only_print}) {
+ print $entry->{doi};
+ return;
+ }
+ my $url = $entry->{doi};
+ $url =~ s{^doi://}{http://dx.doi.org/};
+ open_browser($url,$options);
+ return;
+ }
+ if (defined $entry->{html}) {
+ if ($options->{only_print}) {
+ print $entry->{html};
+ return;
+ }
+ open_browser($entry->{html},$options);
+ return;
+ }
+}
+
+sub select_entry_from_pmid{
+ my ($dbh,$sth,$pmid) = @_;
+
+ return select_one($dbh,$sth->{select_bibtex_by_pmid},$pmid);
+}
+
+
+sub select_entry_from_bibtex_key{
+ my ($dbh,$sth,$bibtex_key) = @_;
+
+ my $entry = select_one($dbh,$sth->{select_bibtex_by_key},$bibtex_key);
+ if (not defined $entry) {
+ print STDERR "Unable to find entry by exact search\n" if $DEBUG;
+ $bibtex_key =~ s/:.*$//;
+ $entry = select_one($dbh,$sth->{select_bibtex_by_approximate_key},$bibtex_key.'%');
+ }
+ print STDERR "Found entry\n" if $DEBUG and defined $entry;
+ return $entry;
+}
+
+sub select_one{
+ my ($dbh,$sth,@bind_vals) = @_;
+ $sth->execute(@bind_vals) or
+ die "Unable to select one: ".$dbh->errstr();
+ my $results = $sth->fetchall_arrayref({});
+ $sth->finish();
+ return ref($results)?$results->[0]:undef;
+}
+
+sub parse_bibtex_file {
+ my ($file,$entries) = @_;
+
+ my $bibfile = Text::BibTeX::File->new($file)
+ or die "Unable to open $file for reading: $!";
+ my @entry_comments;
+ my $entry;
+ while ($entry = Text::BibTeX::Entry->new($bibfile)) {
+ print STDERR "In Entry ".$entry->metatype() if $DEBUG;
+ if ($entry->metatype() == BTE_COMMENT) {
+ push @entry_comments,$entry->value();
+ } elsif ($entry->metatype() == BTE_REGULAR) {
+ my $entry_key = $entry->key();
+ if (not defined $entry_key) {
+ @entry_comments = ();
+ next;
+ }
+ my %entry_data;
+ # if there is a file comment, use it as the file name
+ for my $comment (@entry_comments) {
+ next unless $comment =~ /^\s*file(?:name)?:?\s*(.+?)\s*$/i;
+ next unless length $1;
+ $entry_data{file_name} = $1.'.pdf';
+ last;
+ }
+ my %field_prefix = (doi => 'doi://',
+ html => 'http://',
+ file => '',
+ pmid => '',
+ );
+ my %field_name = (doi => 'doi',
+ html => 'html',
+ pmid => 'pmid',
+ file => 'file_name',);
+ for my $field (qw(file doi html pmid)) {
+ my $field_value = $entry->get($field);
+ if (defined $field_value and $field_value =~ /\S+/) {
+ $entry_data{$field_name{$field}} =
+ $field_prefix{$field}.$field_value if
+ not defined $entry_data{$field_name{$field}};
+ }
+ }
+ $entries->{$entry_key} = {} if not defined $entries->{$entry_key};
+ for my $field (keys %entry_data) {
+ $entries->{$entry_key}{$field} = $entry_data{$field} if
+ defined $entry_data{$field};
+ }
+ # reset the entry comments
+ @entry_comments = ();
+ } else {
+ # do nothing
+ }
+ print STDERR "\n" if $DEBUG;
+ }
+ return $entries;
+}
+
+
+sub initialize_database {
+ my ($cache) = @_;
+ return open_cache($cache,1);
+}
+
+sub open_cache {
+ my ($cache,$initialize) = @_;
+ my $dbh = DBI->connect("dbi:SQLite:dbname=$cache","","") or
+ die "Unable to open/create database $cache";
+ if ($initialize) {
+ $dbh->do("DROP TABLE IF EXISTS bibtex;");
+ $dbh->do("DROP TABLE IF EXISTS papers;");
+ $dbh->do(<<EOF);
+CREATE TABLE bibtex (
+bibtex_key TEXT PRIMARY KEY,
+file_name TEXT,
+pmid TEXT,
+doi TEXT,
+html TEXT
+);
+EOF
+ $dbh->do(<<EOF);
+CREATE UNIQUE INDEX bibtex_file_name ON bibtex(file_name);
+EOF
+ $dbh->do(<<EOF);
+CREATE UNIQUE INDEX bibtex_bibtex_key ON bibtex(bibtex_key);
+EOF
+ $dbh->do(<<EOF);
+CREATE INDEX bibtex_pmid ON bibtex(pmid);
+EOF
+ $dbh->do(<<EOF);
+CREATE TABLE papers (
+file_name TEXT PRIMARY KEY,
+path TEXT,
+has_xoj BOOLEAN
+);
+EOF
+ $dbh->do(<<EOF);
+CREATE UNIQUE INDEX papers_path ON papers(path);
+EOF
+ $dbh->do(<<EOF);
+CREATE UNIQUE INDEX papers_file_name ON papers(file_name);
+EOF
+ }
+ my %s =
+ (insert_papers => <<'EOF',
+INSERT OR REPLACE INTO papers(file_name,path,has_xoj) VALUES (?,?,?);
+EOF
+ insert_bibtex => <<'EOF',
+INSERT OR REPLACE INTO bibtex (bibtex_key,file_name,pmid,doi,html) VALUES (?,?,?,?,?);
+EOF
+ select_papers_by_name => <<'EOF',
+SELECT * FROM papers WHERE file_name = ?;
+EOF
+ select_papers_by_pmid => <<'EOF',
+SELECT * FROM papers WHERE file_name LIKE ?;
+EOF
+ select_papers_by_path => <<'EOF',
+SELECT * FROM papers WHERE path = ?;
+EOF
+ select_bibtex_by_key => <<'EOF',
+SELECT * FROM bibtex WHERE bibtex_key = ?;
+EOF
+ select_bibtex_by_approximate_key => <<'EOF',
+SELECT * FROM bibtex WHERE bibtex_key LIKE ?;
+EOF
+ select_bibtex_by_file_name => <<'EOF',
+SELECT * FROM bibtex WHERE file_name = ?;
+EOF
+ select_bibtex_by_pmid => <<'EOF',
+SELECT * FROM bibtex WHERE pmid = ?;
+EOF
+ clear_papers_cache => <<'EOF',
+DELETE FROM papers;
+EOF
+ clear_bibtex_cache => <<'EOF',
+DELETE FROM bibtex;
+EOF
+ );
+ my $st;
+ for my $key (keys %s) {
+ $st->{$key}=$dbh->prepare($s{$key}) //
+ die "Unable to prepare sql statement: ".$dbh->errstr;
+ }
+ return ($dbh,$st);
+}