]> git.proxmox.com Git - pmg-api.git/blame - PMG/Fetchmail.pm
PMG/Cluster.pm - correctly update fetchmailrc
[pmg-api.git] / PMG / Fetchmail.pm
CommitLineData
26be105b
DM
1package PMG::Fetchmail;
2
3use strict;
4use warnings;
cde18a76 5use Data::Dumper;
26be105b
DM
6
7use PVE::Tools;
8use PVE::INotify;
9
cde18a76
DM
10use PMG::Config;
11
26be105b
DM
12my $inotify_file_id = 'fetchmailrc';
13my $config_filename = '/etc/pmg/fetchmailrc';
14
cde18a76
DM
15my $set_fetchmail_defaults = sub {
16 my ($item) = @_;
17
18 $item->{protocol} //= 'pop3';
19 $item->{interval} //= 1;
004cc4f3 20 $item->{enable} //= 0;
cde18a76
DM
21
22 if (!$item->{port}) {
23 if ($item->{protocol} eq 'pop3') {
24 if ($item->{ssl}) {
25 $item->{port} = 995;
26 } else {
27 $item->{port} = 110;
28 }
29 } elsif ($item->{protocol} eq 'imap') {
30 if ($item->{ssl}) {
31 $item->{port} = 993;
32 } else {
33 $item->{port} = 143;
34 }
35 } else {
36 die "unknown fetchmail protocol '$item->{protocol}'\n";
37 }
38 }
39
40 return $item;
41};
42
26be105b
DM
43sub read_fetchmail_conf {
44 my ($filename, $fh) = @_;
45
46 my $cfg = {};
47
48 if ($fh) {
49
cde18a76 50 # scan for proxmox marker - skip non proxmox lines
26be105b 51 while (defined(my $line = <$fh>)) {
cde18a76 52 last if $line =~ m/^\#\s+proxmox\s+settings.*$/;
26be105b 53 }
cde18a76
DM
54 # now parse the rest
55
56 my $data = '';
57 my $linenr = 0;
58
59 my $get_next_token = sub {
60
61 do {
96845248 62 while ($data =~ /\G("([^"]*)"|\S+|)(?:\s|$)/g) {
5072afa7 63 my ($token, $string) = ($1, $2);
cde18a76 64 if ($1 ne '') {
719ea622 65 $string =~ s/\\x([0-9A-Fa-f]{2})/chr(hex($1))/eg
96845248 66 if defined($string);
5072afa7 67 return wantarray ? ($token, $string) : $token;
cde18a76
DM
68 }
69 }
70 $data = <$fh>;
71 $linenr = $fh->input_line_number();
72 } while (defined($data));
73
74 return undef; # EOF
75 };
76
77 my $get_token_argument = sub {
78 my ($token, $string) = $get_next_token->();
79 die "line $linenr: missing token arguemnt\n" if !$token;
80 return $string // $token;
81 };
82
83 my $finalize_item = sub {
84 my ($item) = @_;
85 $cfg->{$item->{id}} = $item;
86 };
87
88 my $item;
89 while (my ($token, $string) = $get_next_token->()) {
90 last if !defined($token);
91 if ($token eq 'poll' || $token eq 'skip') {
92 $finalize_item->($item) if defined($item);
93 my $id = $get_token_argument->();
94 $item = { id => $id };
2d4e40c3 95 $item->{enable} = $token eq 'poll' ? 1 : 0;
cde18a76
DM
96 next;
97 }
98
99 die "line $linenr: unexpected token '$token'\n"
100 if !defined($item);
101
102 if ($token eq 'user') {
103 $item->{user} = $get_token_argument->();
104 } elsif ($token eq 'via') {
105 $item->{server} = $get_token_argument->();
106 } elsif ($token eq 'pass') {
107 $item->{pass} = $get_token_argument->();
108 } elsif ($token eq 'to') {
109 $item->{target} = $get_token_argument->();
110 } elsif ($token eq 'protocol') {
111 $item->{protocol} = $get_token_argument->();
112 } elsif ($token eq 'port') {
113 $item->{port} = $get_token_argument->();
114 } elsif ($token eq 'interval') {
115 $item->{interval} = $get_token_argument->();
116 } elsif ($token eq 'ssl' || $token eq 'keep' ||
117 $token eq 'dropdelivered') {
118 $item->{$token} = 1;
119 } else {
120 die "line $linenr: unexpected token '$token' inside entry '$item->{id}'\n";
121 }
122 }
123 $finalize_item->($item) if defined($item);
26be105b
DM
124 }
125
126 return $cfg;
127}
128
129sub write_fetchmail_conf {
cde18a76
DM
130 my ($filename, $fh, $fmcfg) = @_;
131
5072afa7
DM
132 my $data = {};
133
134 # Note: we correctly quote data here to make fetchmailrc.tt simpler
135
cde18a76 136 foreach my $id (keys %$fmcfg) {
5072afa7
DM
137 my $org = $fmcfg->{$id};
138 my $item = { id => $id };
139 foreach my $k (keys %$org) {
140 my $v = $org->{$k};
96845248 141 $v =~ s/([^A-Za-z0-9\:\@\-\._~])/sprintf "\\x%02x",ord($1)/eg;
5072afa7
DM
142 $item->{$k} = $v;
143 }
cde18a76
DM
144 $set_fetchmail_defaults->($item);
145 my $options = [ 'dropdelivered' ];
146 push @$options, 'ssl' if $item->{ssl};
147 push @$options, 'keep' if $item->{keep};
148 $item->{options} = join(' ', @$options);
5072afa7 149 $data->{$id} = $item;
cde18a76 150 }
26be105b
DM
151
152 my $raw = '';
153
cde18a76
DM
154 my $pmgcfg = PMG::Config->new();
155 my $vars = $pmgcfg->get_template_vars();
5072afa7 156 $vars->{fetchmail_users} = $data;
cde18a76
DM
157
158 my $tt = PMG::Config::get_template_toolkit();
159 $tt->process('fetchmailrc.tt', $vars, \$raw) ||
160 die $tt->error() . "\n";
161
162 my (undef, undef, $uid, $gid) = getpwnam('fetchmail');
163 chown($uid, $gid, $fh) if defined($uid) && defined($gid);
164 chmod(0600, $fh);
26be105b
DM
165
166 PVE::Tools::safe_print($filename, $fh, $raw);
167}
168
169PVE::INotify::register_file(
170 $inotify_file_id, $config_filename,
171 \&read_fetchmail_conf,
172 \&write_fetchmail_conf,
173 undef,
174 always_call_parser => 1);
175
26be105b 1761;