/[smecontribs]/rpms/smeserver-sme9admin/contribs9/smeserver-sme9admin-1.5-bz10409-altqmail.patch
ViewVC logotype

Contents of /rpms/smeserver-sme9admin/contribs9/smeserver-sme9admin-1.5-bz10409-altqmail.patch

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download)
Tue Aug 15 00:22:51 2017 UTC (7 years, 3 months ago) by unnilennium
Branch: MAIN
CVS Tags: smeserver-sme9admin-1_5-29_el6_sme, smeserver-sme9admin-1_5-30_el6_sme, smeserver-sme9admin-1_5-27_el6_sme, smeserver-sme9admin-1_5-28_el6_sme, HEAD
Error occurred while calculating annotation data.
* Mon Aug 14 2017 Jean-Philipe Pialasse <tests@pialasse.com> 1.5-27.sme
- add support for altqmail [SME: 10409]

1 --- smeserver-sme9admin-1.5/root/usr/bin/sme9admind.altqmail 2017-03-25 22:23:50.000000000 -0400
2 +++ smeserver-sme9admin-1.5/root/usr/bin/sme9admind 2017-08-14 20:00:50.324239696 -0400
3 @@ -94,6 +94,7 @@
4 "sshd/current", #pour les connexions ssh
5 "messages",
6 "qmail/current", #pour les mails IN/OUT
7 + "altqmail/current", #pour les mails OUT
8 "qpsmtpd/current", #pour les SPAM/VIRUS ??
9 "sqpsmtpd/current", #idem pour les connexions securisées
10 "proftpd/current", #pour la date de fin de connection FTP
11 @@ -177,6 +178,16 @@
12 $cntqm{$_} = 0;
13 $cntqmlocal{$_} = 0;
14 }
15 +# pour altqmail
16 +my ($localaqueue,$remoteaqueue);
17 +my @resultsaqm = qw(failure deferral success total);
18 +my %cntaqm;
19 +my %cntaqmlocal;
20 +foreach (@resultsaqm){
21 + $cntaqm{$_} = 0;
22 + $cntaqmlocal{$_} = 0;
23 +}
24 +my $net_amail_out=0;
25
26 #------------------------
27 #declaration de fonctions
28 @@ -516,7 +527,7 @@
29
30
31 # reset all counter before checking logs
32 - ($net_dhcp,$net_mail_in,$net_mail_out,$net_spam,$net_virus)=(0,0,0,0,0);
33 + ($net_dhcp,$net_mail_in,$net_mail_out,$net_amail_out,$net_spam,$net_virus)=(0,0,0,0,0,0);
34 foreach (keys %denied, @others){
35 $cnt{$_} = 0;
36 }
37 @@ -524,6 +535,10 @@
38 $cntqm{$_} = 0;
39 $cntqmlocal{$_} = 0;
40 }
41 + foreach (@resultsaqm){
42 + $cntaqm{$_} = 0;
43 + $cntaqmlocal{$_} = 0;
44 + }
45 foreach my $nom (@logs) {
46 # on recupere un file handle positionné comme il faut
47 my $fh = seek_log("$logdir$nom");
48 @@ -683,6 +698,40 @@
49 $net_mail_out=$cntqm{total};
50
51 }
52 + elsif ($nom =~ /^altqmail\/current$/) {
53 + while ( defined(my $l = <$fh>)) {
54 + # accounting for remote connections
55 + # @400000004994ad092afa867c delivery 96906: success etc...
56 + if ($l =~ m/^\@[0-9a-f]{24} delivery \d+: (success|failure|deferral).*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|CNAME_lookup_failed_temporarily|Sorry,_I_wasn't_able_to_establish_an_SMTP_connection)/i) {
57 + my $result = $1;
58 + $cntaqm{$result}++;
59 + next;
60 + }
61 + # accounting for local connections have to be after the remote
62 + if ($l =~ m/^\@[0-9a-f]{24} delivery \d+: (success|failure|deferral).*/i) {
63 + my $result = $1;
64 + $cntaqmlocal{$result}++;
65 + next;
66 + }
67 +
68 +
69 + }
70 +
71 + # Calcul des totaux:
72 + foreach (@resultsqm){
73 + $cntaqm{total} = $cntaqm{total} + $cntaqm{$_} if $_ !~ /total/;
74 + $cntaqmlocal{total} = $cntaqmlocal{total} + $cntaqmlocal{$_} if $_ !~ /total/;
75 + }
76 + ## add qmail local queue
77 + $localaqueue=`find /var/service/altqmail/root/var/qmail/queue/local/ -type f | wc -l`;
78 + $localaqueue=~ s/\D+//g;
79 + ### add qmail remote queue
80 + $remoteaqueue=`find /var/service/altqmail/root/var/qmail/queue/remote/ -type f | wc -l`;
81 + $remoteaqueue=~ s/\D+//g;
82 + $net_amail_out=$cntaqm{total};
83 +
84 + }
85 +
86 elsif ($nom =~ /^s?qpsmtpd\/current$/) {
87 while ( defined(my $l = <$fh>)) {
88 # following code is copy paste from util_parse_mail from Daniel Berteaud for Zabbix monitoring
89 @@ -1307,7 +1356,7 @@
90 # print "if_ext_bin=$if_ext_bin,if_ext_bout=$if_ext_bout,if_ext_pin=$if_ext_pin,if_ext_pout=$if_ext_pout\n";
91 # print "net_samba=$net_samba,net_minlatency=$net_minlatency,net_avglatency=$net_avglatency,";
92 # print "net_maxlatency=$net_maxlatency,net_loss=$net_loss,net_spam=$net_spam,net_virus=$net_virus,";
93 - print "net_dhcp=$net_dhcp,net_mail_in=$net_mail_in,net_mail_out=$net_mail_out\n";
94 +# print "net_dhcp=$net_dhcp,net_mail_in=$net_mail_in,net_mail_out=$net_mail_out\n";
95 # print "cpu_total=$cpu_total,cpu_idle=$cpu_idle,cpu_system=$cpu_system,cpu_user=$cpu_user\n";
96 # print "cpu_nice=$cpu_nice,cpu_plist=$cpu_plist,cpu_runq=$cpu_runq";
97 # print "cpu_load1=$cpu_load1,cpu_load5=$cpu_load5,cpu_load15=$cpu_load15,cpu_uptime=$cpu_uptime\n";
98 @@ -1321,14 +1370,19 @@
99 # print "squid cpu=$squid_cpu, mem=$squid_mem, nb=$squid_nbproc\n";
100 # print "sessions_ftp=$sessions_ftp,sessions_ssh=$sessions_ssh,";
101 # print "sessions_vpn=$sessions_vpn,sessions_netbios=$sessions_netbios\n";
102 -#print "check_basicheaders=$mail_in_check_basicheaders,check_earlytalker=$mail_in_check_earlytalker,check_goodrcptto=$mail_in_check_goodrcptto,check_spamhelo=$mail_in_check_spamhelo,"
103 +# print "check_basicheaders=$mail_in_check_basicheaders,check_earlytalker=$mail_in_check_earlytalker,check_goodrcptto=$mail_in_check_goodrcptto,check_spamhelo=$mail_in_check_spamhelo,"
104 #."clamav=$mail_in_clamav,dmarc=$mail_in_dmarc,dnsbl=$mail_in_dnsbl,fcrdns=$mail_in_fcrdns,karma=$mail_in_karma,other_denied=$mail_in_other_denied,queued=$mail_in_queued,resolvable_fromhost=$mail_in_resolvable_fromhost,"
105 #."rhsbl=$mail_in_rhsbl,spam_denied=$mail_in_spam_denied,spam_queued=$mail_in_spam_queued,spf=$mail_in_spf,tls_failed=$mail_in_tls_failed,total=$mail_in_total,total_denied=$mail_in_total_denied,uribl=$mail_in_uribl\n";
106 # foreach (keys %denied,@others){ print "$_: $cnt{$_},";}; print "\n";
107 # print join(':', map {$cnt{$_}} keys %denied,@others); print "\n";
108 + print "qmail ";
109 foreach (@resultsqm){ print "local_$_:$cntqmlocal{$_},";}; foreach (@resultsqm){ print "$_:$cntqm{$_},";};
110 print "localqueue=$localqueue,remotequeue=$remotequeue\n";
111 - print join(':', map {$cntqmlocal{$_}} @resultsqm) .":". join(':', map {$cntqm{$_}} @resultsqm); print ":". $localqueue .":". $remotequeue; print "\n";
112 +# print join(':', map {$cntqmlocal{$_}} @resultsqm) .":". join(':', map {$cntqm{$_}} @resultsqm); print ":". $localqueue .":". $remotequeue; print "\n";
113 + print "altqmail ";
114 + foreach (@resultsaqm){ print "local_$_:$cntaqmlocal{$_},";}; foreach (@resultsaqm){ print "$_:$cntaqm{$_},";};
115 + print "localqueue=$localaqueue,remotequeue=$remoteaqueue\n";
116 +# print join(':', map {$cntaqmlocal{$_}} @resultsaqm) .":". join(':', map {$cntaqm{$_}} @resultsaqm); print ":". $localaqueue .":". $remoteaqueue; print "\n";
117
118 my %rrds=(
119 "sensors"=>"$sensors_temp1:$sensors_temp2:$sensors_temp_hd1:$sensors_temp_hd2:$sensors_fan_speed:$sensors_fan2_speed:$sensors_temp_hd3:$sensors_temp_hd4:$sensors_temp_hd5:$sensors_temp_hd6",
120 @@ -1344,8 +1398,8 @@
121 "squid"=>"$squid_cpu:$squid_mem:$squid_nbproc",
122 "sessions"=>"$sessions_ssh:$sessions_ftp:$sessions_vpn:$sessions_netbios:$sessions_afp",
123 "qpsmtpd" => join(':', map {$cnt{$_}} keys %denied,@others),
124 - "qmail" => join(':', map {$cntqmlocal{$_}} @resultsqm) .":". join(':', map {$cntqm{$_}} @resultsqm) . ":". $localqueue .":". $remotequeue);
125 -
126 + "qmail" => join(':', map {$cntqmlocal{$_}} @resultsqm) .":". join(':', map {$cntqm{$_}} @resultsqm) . ":". $localqueue .":". $remotequeue,
127 + "altqmail" => join(':', map {$cntaqmlocal{$_}} @resultsaqm) .":". join(':', map {$cntaqm{$_}} @resultsaqm) . ":". $localaqueue .":". $remoteaqueue);
128 my $error;
129
130 foreach my $rrd (keys %rrds) {
131 --- smeserver-sme9admin-1.5/root/usr/share/doc/smeserver-sme9admin/create-rrd.sh.altqmail 2017-03-25 22:23:50.000000000 -0400
132 +++ smeserver-sme9admin-1.5/root/usr/share/doc/smeserver-sme9admin/create-rrd.sh 2017-07-10 14:08:12.687683984 -0400
133 @@ -506,6 +506,36 @@
134 RRA:MIN:0.5:24:372 \
135 RRA:MIN:0.5:288:365 \
136
137 +# nombre et raisons de connexions refusées ou acceptées et file d'attente
138 +rrdtool create /var/lib/sme9admin/altqmail.rrd -s 300 \
139 + DS:local_failure:GAUGE:600:0:U \
140 + DS:local_deferral:GAUGE:600:0:U \
141 + DS:local_success:GAUGE:600:0:U \
142 + DS:local_total:GAUGE:600:0:U \
143 + DS:remote_failure:GAUGE:600:0:U \
144 + DS:remote_deferral:GAUGE:600:0:U \
145 + DS:remote_success:GAUGE:600:0:U \
146 + DS:remote_total:GAUGE:600:0:U \
147 + DS:local_queue:GAUGE:600:0:U \
148 + DS:remote_queue:GAUGE:600:0:U \
149 + RRA:AVERAGE:0.5:1:12 \
150 + RRA:AVERAGE:0.5:1:72 \
151 + RRA:AVERAGE:0.5:1:288 \
152 + RRA:AVERAGE:0.5:6:336 \
153 + RRA:AVERAGE:0.5:24:372 \
154 + RRA:AVERAGE:0.5:288:365 \
155 + RRA:MAX:0.5:1:12 \
156 + RRA:MAX:0.5:1:72 \
157 + RRA:MAX:0.5:1:288 \
158 + RRA:MAX:0.5:6:336 \
159 + RRA:MAX:0.5:24:372 \
160 + RRA:MAX:0.5:288:365 \
161 + RRA:MIN:0.5:1:12 \
162 + RRA:MIN:0.5:1:72 \
163 + RRA:MIN:0.5:1:288 \
164 + RRA:MIN:0.5:6:336 \
165 + RRA:MIN:0.5:24:372 \
166 + RRA:MIN:0.5:288:365 \
167
168
169 echo -e "Creation of rrds files :\t\t[OK]"
170 --- smeserver-sme9admin-1.5/root/etc/e-smith/web/functions/sme9admin.altqmail 2017-03-25 22:23:50.000000000 -0400
171 +++ smeserver-sme9admin-1.5/root/etc/e-smith/web/functions/sme9admin 2017-07-10 14:16:57.349464605 -0400
172 @@ -370,7 +370,7 @@
173 "#".gettext("Administrative services"), "sshd", "sme9admind",
174 "#".gettext("Network services"),"wan","dhcpd","pptpd","ippp",
175 "#".gettext("File-sharing services"),"smb","smbd","nmbd","ftp",
176 - "#".gettext("E-mail services"),"pop3","pop3s","dovecot","imaps","imap","qmail","qpsmtpd","sqpsmtpd", "clamd", "freshclam","spamd",#mail
177 + "#".gettext("E-mail services"),"pop3","pop3s","dovecot","imaps","imap","qmail","altqmail","qpsmtpd","sqpsmtpd", "clamd", "freshclam","spamd",#mail
178 "#".gettext("DNS services"),"tinydns","dnscache", #dns
179 "#".gettext("Authentication services"),"oidentd","ldap","smtp-auth-proxy","radiusd", #auth
180 "#".gettext("Misc. services"),"mysqld","ntpd","lpd", #misc
181 @@ -401,7 +401,7 @@
182 else
183 {
184 #si c'est un service pour lequel on a des infos complementaires...
185 - if($svc=~/^(httpd-e-smith|httpd-admin|smb|smbd|nmbd|squid|pptpd|dhcpd|sshd|ftp|pppoe|pppd|wan|qmail|qpsmtpd|sqpsmtpd)$/) {$details=1;}
186 + if($svc=~/^(httpd-e-smith|httpd-admin|smb|smbd|nmbd|squid|pptpd|dhcpd|sshd|ftp|pppoe|pppd|wan|altqmail|qmail|qpsmtpd|sqpsmtpd)$/) {$details=1;}
187 if ( -d "/service/$svc") {$cmd = "/usr/bin/sv s $svc";} # was -d /var/service or -d /service/
188 elsif ($svc=~/^(imaps|imap)$/) { $cmd = "/usr/bin/sv s dovecot"; }
189 else {$cmd = "/sbin/e-smith/service $svc status|/bin/grep $svc";}
190 @@ -1066,6 +1066,7 @@
191 elsif ($q->param('service') eq 'pppoe' || $q->param('service') eq 'wan' || $q->param('service') eq 'pppd' ) {showPppoe();}
192 elsif ($q->param('service') eq 'qpsmtpd' || $q->param('service') eq 'sqpsmtpd' ) {showQpsmtpd();}
193 elsif ($q->param('service') eq 'qmail') {showQmail();}
194 + elsif ($q->param('service') eq 'altqmail') {showQmail();}
195 }
196
197 #----------------------------------------------------------------
198 @@ -1085,7 +1086,7 @@
199 print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
200 #qmail local and remote email
201 createGraphQmail($start);
202 -
203 + createGraphAltQmail($start);
204 }
205 #----------------------------------------------------------------
206 #details du service s?qpsmtpd
207 @@ -1927,6 +1928,39 @@
208
209 }
210
211 +sub createGraphAltQmail {
212 + my($start)=(@_);
213 + #qmail entrant/sortant
214 + createShowGraph(gettext("Number of remote e-mails handled by the alternative mail service (altqmail)."),"altqmail",
215 + "--title=".gettext("Remote e-mails (altqmail)"),
216 + "--start=$start",
217 + "DEF:local_failure=$rrddir/altqmail.rrd:local_failure:AVERAGE","DEF:maxlocal_failure=$rrddir/altqmail.rrd:local_failure:MAX","DEF:minlocal_failure=$rrddir/altqmail.rrd:local_failure:MIN",
218 + "DEF:local_deferral=$rrddir/altqmail.rrd:local_deferral:AVERAGE","DEF:maxlocal_deferral=$rrddir/altqmail.rrd:local_deferral:MAX","DEF:minlocal_deferral=$rrddir/altqmail.rrd:local_deferral:MIN",
219 + "DEF:local_success=$rrddir/altqmail.rrd:local_success:AVERAGE","DEF:maxlocal_success=$rrddir/altqmail.rrd:local_success:MAX","DEF:minlocal_success=$rrddir/altqmail.rrd:local_success:MIN",
220 + "DEF:local_total=$rrddir/altqmail.rrd:local_total:AVERAGE","DEF:maxlocal_total=$rrddir/altqmail.rrd:local_total:MAX","DEF:minlocal_total=$rrddir/altqmail.rrd:local_total:MIN",
221 + "DEF:remote_failure=$rrddir/altqmail.rrd:remote_failure:AVERAGE","DEF:maxremote_failure=$rrddir/altqmail.rrd:remote_failure:MAX","DEF:minremote_failure=$rrddir/altqmail.rrd:remote_failure:MIN",
222 + "DEF:remote_deferral=$rrddir/altqmail.rrd:remote_deferral:AVERAGE","DEF:maxremote_deferral=$rrddir/altqmail.rrd:remote_deferral:MAX","DEF:minremote_deferral=$rrddir/altqmail.rrd:remote_deferral:MIN",
223 + "DEF:remote_success=$rrddir/altqmail.rrd:remote_success:AVERAGE","DEF:maxremote_success=$rrddir/altqmail.rrd:remote_success:MAX","DEF:minremote_success=$rrddir/altqmail.rrd:remote_success:MIN",
224 + "DEF:remote_total=$rrddir/altqmail.rrd:remote_total:AVERAGE","DEF:maxremote_total=$rrddir/altqmail.rrd:remote_total:MAX","DEF:minremote_total=$rrddir/altqmail.rrd:remote_total:MIN",
225 + "DEF:local_queue=$rrddir/altqmail.rrd:local_queue:AVERAGE","DEF:maxlocal_queue=$rrddir/altqmail.rrd:local_queue:MAX","DEF:minlocal_queue=$rrddir/altqmail.rrd:local_queue:MIN",
226 + "DEF:remote_queue=$rrddir/altqmail.rrd:remote_queue:AVERAGE","DEF:maxremote_queue=$rrddir/altqmail.rrd:remote_queue:MAX","DEF:minremote_queue=$rrddir/altqmail.rrd:remote_queue:MIN",
227 + "CDEF:adj_remote_total=0,remote_total,-", "CDEF:adj_remote_queue=0,remote_queue,-",
228 + "CDEF:adj_remote_failure=0,remote_failure,-", "CDEF:adj_remote_deferral=0,remote_deferral,-","CDEF:adj_remote_success=0,remote_success,-",
229 + "COMMENT:Last\\t Min\\t Avg\\t Max\\r",
230 + "COMMENT:\\n","AREA:local_total#1ED408:".gettext("Total local e-mails"),"COMMENT:\\u","GPRINT:local_total:LAST:%4.0lf ","GPRINT:minlocal_total:MIN:%4.0lf ","GPRINT:local_total:AVERAGE:%4.0lf ","GPRINT:maxlocal_total:MAX:%4.0lf \\r",
231 + "COMMENT:\\n","COMMENT: ".gettext("Total remote e-mails"), "COMMENT:\\u","GPRINT:remote_total:LAST:%4.0lf ","GPRINT:minremote_total:MIN:%4.0lf ","GPRINT:remote_total:AVERAGE:%4.0lf ","GPRINT:maxremote_total:MAX:%4.0lf \\r",
232 +
233 + "COMMENT:\\n","COMMENT: ","AREA:adj_remote_success#0000ff:".gettext("Remote e-mail success"), "COMMENT:\\u","GPRINT:remote_success:LAST:%4.0lf ","GPRINT:minremote_success:MIN:%4.0lf ","GPRINT:remote_success:AVERAGE:%4.0lf ","GPRINT:maxremote_success:MAX:%4.0lf \\r",
234 + "COMMENT:\\n","COMMENT: ","AREA:adj_remote_deferral#ffff00:".gettext("Remote e-mail deferral").":STACK", "COMMENT:\\u","GPRINT:remote_deferral:LAST:%4.0lf ","GPRINT:minremote_deferral:MIN:%4.0lf ","GPRINT:remote_deferral:AVERAGE:%4.0lf ","GPRINT:maxremote_deferral:MAX:%4.0lf \\r",
235 + "COMMENT:\\n","COMMENT: ","AREA:adj_remote_failure#ff0000:".gettext("Remote e-mail failure").":STACK", "COMMENT:\\u","GPRINT:remote_failure:LAST:%4.0lf ","GPRINT:minremote_failure:MIN:%4.0lf ","GPRINT:remote_failure:AVERAGE:%4.0lf ","GPRINT:maxremote_failure:MAX:%4.0lf \\r",
236 +
237 + "COMMENT:\\n","LINE2:local_queue#666666:".gettext("Local queue"),"COMMENT:\\u", "GPRINT:local_queue:LAST:%4.0lf ","GPRINT:minlocal_queue:MIN:%4.0lf ","GPRINT:local_queue:AVERAGE:%4.0lf ","GPRINT:maxlocal_queue:MAX:%4.0lf \\r",
238 + "COMMENT:\\n","LINE2:adj_remote_queue#000000:".gettext("Remote queue"),"COMMENT:\\u", "GPRINT:remote_queue:LAST:%4.0lf ","GPRINT:minremote_queue:MIN:%4.0lf ","GPRINT:remote_queue:AVERAGE:%4.0lf ","GPRINT:maxremote_queue:MAX:%4.0lf \\r",
239 + "COMMENT:\\n");
240 +
241 +
242 +}
243 +
244 sub createGraphQpsmtpd {
245 my($start)=(@_);
246 #qpsmtpd
247 --- smeserver-sme9admin-1.5/root/etc/e-smith/sql/init/sme9admin.altqmail 2017-08-14 20:11:09.554000000 -0400
248 +++ smeserver-sme9admin-1.5/root/etc/e-smith/sql/init/sme9admin 2017-08-14 20:18:50.221000000 -0400
249 @@ -118,3 +118,36 @@
250 RRA:MIN:0.5:24:372 \
251 RRA:MIN:0.5:288:365
252 fi
253 + if [[ ! -f /var/lib/sme9admin/altqmail.rrd ]]; then
254 + # nombre et raisons de connexions refusées ou acceptées et file d'attente
255 + rrdtool create /var/lib/sme9admin/altqmail.rrd -s 300 \
256 + DS:local_failure:GAUGE:600:0:U \
257 + DS:local_deferral:GAUGE:600:0:U \
258 + DS:local_success:GAUGE:600:0:U \
259 + DS:local_total:GAUGE:600:0:U \
260 + DS:remote_failure:GAUGE:600:0:U \
261 + DS:remote_deferral:GAUGE:600:0:U \
262 + DS:remote_success:GAUGE:600:0:U \
263 + DS:remote_total:GAUGE:600:0:U \
264 + DS:local_queue:GAUGE:600:0:U \
265 + DS:remote_queue:GAUGE:600:0:U \
266 + RRA:AVERAGE:0.5:1:12 \
267 + RRA:AVERAGE:0.5:1:72 \
268 + RRA:AVERAGE:0.5:1:288 \
269 + RRA:AVERAGE:0.5:6:336 \
270 + RRA:AVERAGE:0.5:24:372 \
271 + RRA:AVERAGE:0.5:288:365 \
272 + RRA:MAX:0.5:1:12 \
273 + RRA:MAX:0.5:1:72 \
274 + RRA:MAX:0.5:1:288 \
275 + RRA:MAX:0.5:6:336 \
276 + RRA:MAX:0.5:24:372 \
277 + RRA:MAX:0.5:288:365 \
278 + RRA:MIN:0.5:1:12 \
279 + RRA:MIN:0.5:1:72 \
280 + RRA:MIN:0.5:1:288 \
281 + RRA:MIN:0.5:6:336 \
282 + RRA:MIN:0.5:24:372 \
283 + RRA:MIN:0.5:288:365
284 + fi
285 +

admin@koozali.org
ViewVC Help
Powered by ViewVC 1.2.1 RSS 2.0 feed