]>
Commit | Line | Data |
---|---|---|
26be105b DM |
1 | package PMG::Fetchmail; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
cde18a76 | 5 | use Data::Dumper; |
26be105b DM |
6 | |
7 | use PVE::Tools; | |
8 | use PVE::INotify; | |
9 | ||
cde18a76 DM |
10 | use PMG::Config; |
11 | ||
26be105b DM |
12 | my $inotify_file_id = 'fetchmailrc'; |
13 | my $config_filename = '/etc/pmg/fetchmailrc'; | |
14 | ||
cde18a76 DM |
15 | my $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 |
43 | sub 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 { | |
62 | while ($data =~ /\G('([^']*)'|\S+|)(?:\s|$)/g) { | |
63 | if ($1 ne '') { | |
cde18a76 DM |
64 | return wantarray ? ($1, $2) : $1; |
65 | } | |
66 | } | |
67 | $data = <$fh>; | |
68 | $linenr = $fh->input_line_number(); | |
69 | } while (defined($data)); | |
70 | ||
71 | return undef; # EOF | |
72 | }; | |
73 | ||
74 | my $get_token_argument = sub { | |
75 | my ($token, $string) = $get_next_token->(); | |
76 | die "line $linenr: missing token arguemnt\n" if !$token; | |
77 | return $string // $token; | |
78 | }; | |
79 | ||
80 | my $finalize_item = sub { | |
81 | my ($item) = @_; | |
82 | $cfg->{$item->{id}} = $item; | |
83 | }; | |
84 | ||
85 | my $item; | |
86 | while (my ($token, $string) = $get_next_token->()) { | |
87 | last if !defined($token); | |
88 | if ($token eq 'poll' || $token eq 'skip') { | |
89 | $finalize_item->($item) if defined($item); | |
90 | my $id = $get_token_argument->(); | |
91 | $item = { id => $id }; | |
004cc4f3 | 92 | $item->{enable} = $token eq 'pass' ? 1 : 0; |
cde18a76 DM |
93 | next; |
94 | } | |
95 | ||
96 | die "line $linenr: unexpected token '$token'\n" | |
97 | if !defined($item); | |
98 | ||
99 | if ($token eq 'user') { | |
100 | $item->{user} = $get_token_argument->(); | |
101 | } elsif ($token eq 'via') { | |
102 | $item->{server} = $get_token_argument->(); | |
103 | } elsif ($token eq 'pass') { | |
104 | $item->{pass} = $get_token_argument->(); | |
105 | } elsif ($token eq 'to') { | |
106 | $item->{target} = $get_token_argument->(); | |
107 | } elsif ($token eq 'protocol') { | |
108 | $item->{protocol} = $get_token_argument->(); | |
109 | } elsif ($token eq 'port') { | |
110 | $item->{port} = $get_token_argument->(); | |
111 | } elsif ($token eq 'interval') { | |
112 | $item->{interval} = $get_token_argument->(); | |
113 | } elsif ($token eq 'ssl' || $token eq 'keep' || | |
114 | $token eq 'dropdelivered') { | |
115 | $item->{$token} = 1; | |
116 | } else { | |
117 | die "line $linenr: unexpected token '$token' inside entry '$item->{id}'\n"; | |
118 | } | |
119 | } | |
120 | $finalize_item->($item) if defined($item); | |
26be105b DM |
121 | } |
122 | ||
123 | return $cfg; | |
124 | } | |
125 | ||
126 | sub write_fetchmail_conf { | |
cde18a76 DM |
127 | my ($filename, $fh, $fmcfg) = @_; |
128 | ||
129 | foreach my $id (keys %$fmcfg) { | |
130 | my $item = $fmcfg->{$id}; | |
131 | $item->{id} = $id; | |
132 | $set_fetchmail_defaults->($item); | |
133 | my $options = [ 'dropdelivered' ]; | |
134 | push @$options, 'ssl' if $item->{ssl}; | |
135 | push @$options, 'keep' if $item->{keep}; | |
136 | $item->{options} = join(' ', @$options); | |
137 | } | |
26be105b DM |
138 | |
139 | my $raw = ''; | |
140 | ||
cde18a76 DM |
141 | |
142 | my $pmgcfg = PMG::Config->new(); | |
143 | my $vars = $pmgcfg->get_template_vars(); | |
144 | $vars->{fetchmail_users} = $fmcfg; | |
145 | ||
146 | my $tt = PMG::Config::get_template_toolkit(); | |
147 | $tt->process('fetchmailrc.tt', $vars, \$raw) || | |
148 | die $tt->error() . "\n"; | |
149 | ||
150 | my (undef, undef, $uid, $gid) = getpwnam('fetchmail'); | |
151 | chown($uid, $gid, $fh) if defined($uid) && defined($gid); | |
152 | chmod(0600, $fh); | |
26be105b DM |
153 | |
154 | PVE::Tools::safe_print($filename, $fh, $raw); | |
155 | } | |
156 | ||
157 | PVE::INotify::register_file( | |
158 | $inotify_file_id, $config_filename, | |
159 | \&read_fetchmail_conf, | |
160 | \&write_fetchmail_conf, | |
161 | undef, | |
162 | always_call_parser => 1); | |
163 | ||
26be105b | 164 | 1; |