xref: /aosp_15_r20/external/libcups/notifier/rss.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
1*5e7646d2SAndroid Build Coastguard Worker /*
2*5e7646d2SAndroid Build Coastguard Worker  * RSS notifier for CUPS.
3*5e7646d2SAndroid Build Coastguard Worker  *
4*5e7646d2SAndroid Build Coastguard Worker  * Copyright 2007-2015 by Apple Inc.
5*5e7646d2SAndroid Build Coastguard Worker  * Copyright 2007 by Easy Software Products.
6*5e7646d2SAndroid Build Coastguard Worker  *
7*5e7646d2SAndroid Build Coastguard Worker  * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
8*5e7646d2SAndroid Build Coastguard Worker  */
9*5e7646d2SAndroid Build Coastguard Worker 
10*5e7646d2SAndroid Build Coastguard Worker /*
11*5e7646d2SAndroid Build Coastguard Worker  * Include necessary headers...
12*5e7646d2SAndroid Build Coastguard Worker  */
13*5e7646d2SAndroid Build Coastguard Worker 
14*5e7646d2SAndroid Build Coastguard Worker #include <cups/cups.h>
15*5e7646d2SAndroid Build Coastguard Worker #include <sys/stat.h>
16*5e7646d2SAndroid Build Coastguard Worker #include <cups/language.h>
17*5e7646d2SAndroid Build Coastguard Worker #include <cups/string-private.h>
18*5e7646d2SAndroid Build Coastguard Worker #include <cups/array.h>
19*5e7646d2SAndroid Build Coastguard Worker #include <sys/select.h>
20*5e7646d2SAndroid Build Coastguard Worker #include <cups/ipp-private.h>	/* TODO: Update so we don't need this */
21*5e7646d2SAndroid Build Coastguard Worker 
22*5e7646d2SAndroid Build Coastguard Worker 
23*5e7646d2SAndroid Build Coastguard Worker /*
24*5e7646d2SAndroid Build Coastguard Worker  * Structures...
25*5e7646d2SAndroid Build Coastguard Worker  */
26*5e7646d2SAndroid Build Coastguard Worker 
27*5e7646d2SAndroid Build Coastguard Worker typedef struct _cups_rss_s		/**** RSS message data ****/
28*5e7646d2SAndroid Build Coastguard Worker {
29*5e7646d2SAndroid Build Coastguard Worker   int		sequence_number;	/* notify-sequence-number */
30*5e7646d2SAndroid Build Coastguard Worker   char		*subject,		/* Message subject/summary */
31*5e7646d2SAndroid Build Coastguard Worker 		*text,			/* Message text */
32*5e7646d2SAndroid Build Coastguard Worker 		*link_url;		/* Link to printer */
33*5e7646d2SAndroid Build Coastguard Worker   time_t	event_time;		/* When the event occurred */
34*5e7646d2SAndroid Build Coastguard Worker } _cups_rss_t;
35*5e7646d2SAndroid Build Coastguard Worker 
36*5e7646d2SAndroid Build Coastguard Worker 
37*5e7646d2SAndroid Build Coastguard Worker /*
38*5e7646d2SAndroid Build Coastguard Worker  * Local globals...
39*5e7646d2SAndroid Build Coastguard Worker  */
40*5e7646d2SAndroid Build Coastguard Worker 
41*5e7646d2SAndroid Build Coastguard Worker static char		*rss_password;	/* Password for remote RSS */
42*5e7646d2SAndroid Build Coastguard Worker 
43*5e7646d2SAndroid Build Coastguard Worker 
44*5e7646d2SAndroid Build Coastguard Worker /*
45*5e7646d2SAndroid Build Coastguard Worker  * Local functions...
46*5e7646d2SAndroid Build Coastguard Worker  */
47*5e7646d2SAndroid Build Coastguard Worker 
48*5e7646d2SAndroid Build Coastguard Worker static int		compare_rss(_cups_rss_t *a, _cups_rss_t *b);
49*5e7646d2SAndroid Build Coastguard Worker static void		delete_message(_cups_rss_t *msg);
50*5e7646d2SAndroid Build Coastguard Worker static void		load_rss(cups_array_t *rss, const char *filename);
51*5e7646d2SAndroid Build Coastguard Worker static _cups_rss_t	*new_message(int sequence_number, char *subject,
52*5e7646d2SAndroid Build Coastguard Worker 			             char *text, char *link_url,
53*5e7646d2SAndroid Build Coastguard Worker 				     time_t event_time);
54*5e7646d2SAndroid Build Coastguard Worker static const char	*password_cb(const char *prompt);
55*5e7646d2SAndroid Build Coastguard Worker static int		save_rss(cups_array_t *rss, const char *filename,
56*5e7646d2SAndroid Build Coastguard Worker 			         const char *baseurl);
57*5e7646d2SAndroid Build Coastguard Worker static char		*xml_escape(const char *s);
58*5e7646d2SAndroid Build Coastguard Worker 
59*5e7646d2SAndroid Build Coastguard Worker 
60*5e7646d2SAndroid Build Coastguard Worker /*
61*5e7646d2SAndroid Build Coastguard Worker  * 'main()' - Main entry for the test notifier.
62*5e7646d2SAndroid Build Coastguard Worker  */
63*5e7646d2SAndroid Build Coastguard Worker 
64*5e7646d2SAndroid Build Coastguard Worker int					/* O - Exit status */
main(int argc,char * argv[])65*5e7646d2SAndroid Build Coastguard Worker main(int  argc,				/* I - Number of command-line arguments */
66*5e7646d2SAndroid Build Coastguard Worker      char *argv[])			/* I - Command-line arguments */
67*5e7646d2SAndroid Build Coastguard Worker {
68*5e7646d2SAndroid Build Coastguard Worker   int		i;			/* Looping var */
69*5e7646d2SAndroid Build Coastguard Worker   ipp_t		*event;			/* Event from scheduler */
70*5e7646d2SAndroid Build Coastguard Worker   ipp_state_t	state;			/* IPP event state */
71*5e7646d2SAndroid Build Coastguard Worker   char		scheme[32],		/* URI scheme ("rss") */
72*5e7646d2SAndroid Build Coastguard Worker 		username[256],		/* Username for remote RSS */
73*5e7646d2SAndroid Build Coastguard Worker 		host[1024],		/* Hostname for remote RSS */
74*5e7646d2SAndroid Build Coastguard Worker 		resource[1024],		/* RSS file */
75*5e7646d2SAndroid Build Coastguard Worker 		*options;		/* Options */
76*5e7646d2SAndroid Build Coastguard Worker   int		port,			/* Port number for remote RSS */
77*5e7646d2SAndroid Build Coastguard Worker 		max_events;		/* Maximum number of events */
78*5e7646d2SAndroid Build Coastguard Worker   http_t	*http;			/* Connection to remote server */
79*5e7646d2SAndroid Build Coastguard Worker   http_status_t	status;			/* HTTP GET/PUT status code */
80*5e7646d2SAndroid Build Coastguard Worker   char		filename[1024],		/* Local filename */
81*5e7646d2SAndroid Build Coastguard Worker 		newname[1024];		/* filename.N */
82*5e7646d2SAndroid Build Coastguard Worker   cups_lang_t	*language;		/* Language information */
83*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *printer_up_time,	/* Timestamp on event */
84*5e7646d2SAndroid Build Coastguard Worker 		*notify_sequence_number,/* Sequence number */
85*5e7646d2SAndroid Build Coastguard Worker 		*notify_printer_uri;	/* Printer URI */
86*5e7646d2SAndroid Build Coastguard Worker   char		*subject,		/* Subject for notification message */
87*5e7646d2SAndroid Build Coastguard Worker 		*text,			/* Text for notification message */
88*5e7646d2SAndroid Build Coastguard Worker 		link_url[1024],		/* Link to printer */
89*5e7646d2SAndroid Build Coastguard Worker 		link_scheme[32],	/* Scheme for link */
90*5e7646d2SAndroid Build Coastguard Worker 		link_username[256],	/* Username for link */
91*5e7646d2SAndroid Build Coastguard Worker 		link_host[1024],	/* Host for link */
92*5e7646d2SAndroid Build Coastguard Worker 		link_resource[1024];	/* Resource for link */
93*5e7646d2SAndroid Build Coastguard Worker   int		link_port;		/* Link port */
94*5e7646d2SAndroid Build Coastguard Worker   cups_array_t	*rss;			/* RSS message array */
95*5e7646d2SAndroid Build Coastguard Worker   _cups_rss_t	*msg;			/* RSS message */
96*5e7646d2SAndroid Build Coastguard Worker   char		baseurl[1024];		/* Base URL */
97*5e7646d2SAndroid Build Coastguard Worker   fd_set	input;			/* Input set for select() */
98*5e7646d2SAndroid Build Coastguard Worker   struct timeval timeout;		/* Timeout for select() */
99*5e7646d2SAndroid Build Coastguard Worker   int		changed;		/* Has the RSS data changed? */
100*5e7646d2SAndroid Build Coastguard Worker   int		exit_status;		/* Exit status */
101*5e7646d2SAndroid Build Coastguard Worker 
102*5e7646d2SAndroid Build Coastguard Worker 
103*5e7646d2SAndroid Build Coastguard Worker   fprintf(stderr, "DEBUG: argc=%d\n", argc);
104*5e7646d2SAndroid Build Coastguard Worker   for (i = 0; i < argc; i ++)
105*5e7646d2SAndroid Build Coastguard Worker     fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);
106*5e7646d2SAndroid Build Coastguard Worker 
107*5e7646d2SAndroid Build Coastguard Worker  /*
108*5e7646d2SAndroid Build Coastguard Worker   * See whether we are publishing this RSS feed locally or remotely...
109*5e7646d2SAndroid Build Coastguard Worker   */
110*5e7646d2SAndroid Build Coastguard Worker 
111*5e7646d2SAndroid Build Coastguard Worker   if (httpSeparateURI(HTTP_URI_CODING_ALL, argv[1], scheme, sizeof(scheme),
112*5e7646d2SAndroid Build Coastguard Worker                       username, sizeof(username), host, sizeof(host), &port,
113*5e7646d2SAndroid Build Coastguard Worker 		      resource, sizeof(resource)) < HTTP_URI_OK)
114*5e7646d2SAndroid Build Coastguard Worker   {
115*5e7646d2SAndroid Build Coastguard Worker     fprintf(stderr, "ERROR: Bad RSS URI \"%s\"!\n", argv[1]);
116*5e7646d2SAndroid Build Coastguard Worker     return (1);
117*5e7646d2SAndroid Build Coastguard Worker   }
118*5e7646d2SAndroid Build Coastguard Worker 
119*5e7646d2SAndroid Build Coastguard Worker   max_events = 20;
120*5e7646d2SAndroid Build Coastguard Worker 
121*5e7646d2SAndroid Build Coastguard Worker   if ((options = strchr(resource, '?')) != NULL)
122*5e7646d2SAndroid Build Coastguard Worker   {
123*5e7646d2SAndroid Build Coastguard Worker     *options++ = '\0';
124*5e7646d2SAndroid Build Coastguard Worker 
125*5e7646d2SAndroid Build Coastguard Worker     if (!strncmp(options, "max_events=", 11))
126*5e7646d2SAndroid Build Coastguard Worker     {
127*5e7646d2SAndroid Build Coastguard Worker       max_events = atoi(options + 11);
128*5e7646d2SAndroid Build Coastguard Worker 
129*5e7646d2SAndroid Build Coastguard Worker       if (max_events <= 0)
130*5e7646d2SAndroid Build Coastguard Worker         max_events = 20;
131*5e7646d2SAndroid Build Coastguard Worker     }
132*5e7646d2SAndroid Build Coastguard Worker   }
133*5e7646d2SAndroid Build Coastguard Worker 
134*5e7646d2SAndroid Build Coastguard Worker   rss = cupsArrayNew((cups_array_func_t)compare_rss, NULL);
135*5e7646d2SAndroid Build Coastguard Worker 
136*5e7646d2SAndroid Build Coastguard Worker   if (host[0])
137*5e7646d2SAndroid Build Coastguard Worker   {
138*5e7646d2SAndroid Build Coastguard Worker    /*
139*5e7646d2SAndroid Build Coastguard Worker     * Remote feed, see if we can get the current file...
140*5e7646d2SAndroid Build Coastguard Worker     */
141*5e7646d2SAndroid Build Coastguard Worker 
142*5e7646d2SAndroid Build Coastguard Worker     int	fd;				/* Temporary file */
143*5e7646d2SAndroid Build Coastguard Worker 
144*5e7646d2SAndroid Build Coastguard Worker 
145*5e7646d2SAndroid Build Coastguard Worker     if ((rss_password = strchr(username, ':')) != NULL)
146*5e7646d2SAndroid Build Coastguard Worker       *rss_password++ = '\0';
147*5e7646d2SAndroid Build Coastguard Worker 
148*5e7646d2SAndroid Build Coastguard Worker     cupsSetPasswordCB(password_cb);
149*5e7646d2SAndroid Build Coastguard Worker     cupsSetUser(username);
150*5e7646d2SAndroid Build Coastguard Worker 
151*5e7646d2SAndroid Build Coastguard Worker     if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
152*5e7646d2SAndroid Build Coastguard Worker     {
153*5e7646d2SAndroid Build Coastguard Worker       fprintf(stderr, "ERROR: Unable to create temporary file: %s\n",
154*5e7646d2SAndroid Build Coastguard Worker               strerror(errno));
155*5e7646d2SAndroid Build Coastguard Worker 
156*5e7646d2SAndroid Build Coastguard Worker       return (1);
157*5e7646d2SAndroid Build Coastguard Worker     }
158*5e7646d2SAndroid Build Coastguard Worker 
159*5e7646d2SAndroid Build Coastguard Worker     if ((http = httpConnect(host, port)) == NULL)
160*5e7646d2SAndroid Build Coastguard Worker     {
161*5e7646d2SAndroid Build Coastguard Worker       fprintf(stderr, "ERROR: Unable to connect to %s on port %d: %s\n",
162*5e7646d2SAndroid Build Coastguard Worker               host, port, strerror(errno));
163*5e7646d2SAndroid Build Coastguard Worker 
164*5e7646d2SAndroid Build Coastguard Worker       close(fd);
165*5e7646d2SAndroid Build Coastguard Worker       unlink(filename);
166*5e7646d2SAndroid Build Coastguard Worker 
167*5e7646d2SAndroid Build Coastguard Worker       return (1);
168*5e7646d2SAndroid Build Coastguard Worker     }
169*5e7646d2SAndroid Build Coastguard Worker 
170*5e7646d2SAndroid Build Coastguard Worker     status = cupsGetFd(http, resource, fd);
171*5e7646d2SAndroid Build Coastguard Worker 
172*5e7646d2SAndroid Build Coastguard Worker     close(fd);
173*5e7646d2SAndroid Build Coastguard Worker 
174*5e7646d2SAndroid Build Coastguard Worker     if (status != HTTP_OK && status != HTTP_NOT_FOUND)
175*5e7646d2SAndroid Build Coastguard Worker     {
176*5e7646d2SAndroid Build Coastguard Worker       fprintf(stderr, "ERROR: Unable to GET %s from %s on port %d: %d %s\n",
177*5e7646d2SAndroid Build Coastguard Worker 	      resource, host, port, status, httpStatus(status));
178*5e7646d2SAndroid Build Coastguard Worker 
179*5e7646d2SAndroid Build Coastguard Worker       httpClose(http);
180*5e7646d2SAndroid Build Coastguard Worker       unlink(filename);
181*5e7646d2SAndroid Build Coastguard Worker 
182*5e7646d2SAndroid Build Coastguard Worker       return (1);
183*5e7646d2SAndroid Build Coastguard Worker     }
184*5e7646d2SAndroid Build Coastguard Worker 
185*5e7646d2SAndroid Build Coastguard Worker     strlcpy(newname, filename, sizeof(newname));
186*5e7646d2SAndroid Build Coastguard Worker 
187*5e7646d2SAndroid Build Coastguard Worker     httpAssembleURI(HTTP_URI_CODING_ALL, baseurl, sizeof(baseurl), "http",
188*5e7646d2SAndroid Build Coastguard Worker                     NULL, host, port, resource);
189*5e7646d2SAndroid Build Coastguard Worker   }
190*5e7646d2SAndroid Build Coastguard Worker   else
191*5e7646d2SAndroid Build Coastguard Worker   {
192*5e7646d2SAndroid Build Coastguard Worker     const char	*cachedir,		/* CUPS_CACHEDIR */
193*5e7646d2SAndroid Build Coastguard Worker 		*server_name,		/* SERVER_NAME */
194*5e7646d2SAndroid Build Coastguard Worker 		*server_port;		/* SERVER_PORT */
195*5e7646d2SAndroid Build Coastguard Worker 
196*5e7646d2SAndroid Build Coastguard Worker 
197*5e7646d2SAndroid Build Coastguard Worker     http = NULL;
198*5e7646d2SAndroid Build Coastguard Worker 
199*5e7646d2SAndroid Build Coastguard Worker     if ((cachedir = getenv("CUPS_CACHEDIR")) == NULL)
200*5e7646d2SAndroid Build Coastguard Worker       cachedir = CUPS_CACHEDIR;
201*5e7646d2SAndroid Build Coastguard Worker 
202*5e7646d2SAndroid Build Coastguard Worker     if ((server_name = getenv("SERVER_NAME")) == NULL)
203*5e7646d2SAndroid Build Coastguard Worker       server_name = "localhost";
204*5e7646d2SAndroid Build Coastguard Worker 
205*5e7646d2SAndroid Build Coastguard Worker     if ((server_port = getenv("SERVER_PORT")) == NULL)
206*5e7646d2SAndroid Build Coastguard Worker       server_port = "631";
207*5e7646d2SAndroid Build Coastguard Worker 
208*5e7646d2SAndroid Build Coastguard Worker     snprintf(filename, sizeof(filename), "%s/rss%s", cachedir, resource);
209*5e7646d2SAndroid Build Coastguard Worker     snprintf(newname, sizeof(newname), "%s.N", filename);
210*5e7646d2SAndroid Build Coastguard Worker 
211*5e7646d2SAndroid Build Coastguard Worker     httpAssembleURIf(HTTP_URI_CODING_ALL, baseurl, sizeof(baseurl), "http",
212*5e7646d2SAndroid Build Coastguard Worker                      NULL, server_name, atoi(server_port), "/rss%s", resource);
213*5e7646d2SAndroid Build Coastguard Worker   }
214*5e7646d2SAndroid Build Coastguard Worker 
215*5e7646d2SAndroid Build Coastguard Worker  /*
216*5e7646d2SAndroid Build Coastguard Worker   * Load the previous RSS file, if any...
217*5e7646d2SAndroid Build Coastguard Worker   */
218*5e7646d2SAndroid Build Coastguard Worker 
219*5e7646d2SAndroid Build Coastguard Worker   load_rss(rss, filename);
220*5e7646d2SAndroid Build Coastguard Worker 
221*5e7646d2SAndroid Build Coastguard Worker   changed = cupsArrayCount(rss) == 0;
222*5e7646d2SAndroid Build Coastguard Worker 
223*5e7646d2SAndroid Build Coastguard Worker  /*
224*5e7646d2SAndroid Build Coastguard Worker   * Localize for the user's chosen language...
225*5e7646d2SAndroid Build Coastguard Worker   */
226*5e7646d2SAndroid Build Coastguard Worker 
227*5e7646d2SAndroid Build Coastguard Worker   language = cupsLangDefault();
228*5e7646d2SAndroid Build Coastguard Worker 
229*5e7646d2SAndroid Build Coastguard Worker  /*
230*5e7646d2SAndroid Build Coastguard Worker   * Read events and update the RSS file until we are out of events.
231*5e7646d2SAndroid Build Coastguard Worker   */
232*5e7646d2SAndroid Build Coastguard Worker 
233*5e7646d2SAndroid Build Coastguard Worker   for (exit_status = 0, event = NULL;;)
234*5e7646d2SAndroid Build Coastguard Worker   {
235*5e7646d2SAndroid Build Coastguard Worker     if (changed)
236*5e7646d2SAndroid Build Coastguard Worker     {
237*5e7646d2SAndroid Build Coastguard Worker      /*
238*5e7646d2SAndroid Build Coastguard Worker       * Save the messages to the file again, uploading as needed...
239*5e7646d2SAndroid Build Coastguard Worker       */
240*5e7646d2SAndroid Build Coastguard Worker 
241*5e7646d2SAndroid Build Coastguard Worker       if (save_rss(rss, newname, baseurl))
242*5e7646d2SAndroid Build Coastguard Worker       {
243*5e7646d2SAndroid Build Coastguard Worker 	if (http)
244*5e7646d2SAndroid Build Coastguard Worker 	{
245*5e7646d2SAndroid Build Coastguard Worker 	 /*
246*5e7646d2SAndroid Build Coastguard Worker           * Upload the RSS file...
247*5e7646d2SAndroid Build Coastguard Worker 	  */
248*5e7646d2SAndroid Build Coastguard Worker 
249*5e7646d2SAndroid Build Coastguard Worker           if ((status = cupsPutFile(http, resource, filename)) != HTTP_CREATED)
250*5e7646d2SAndroid Build Coastguard Worker             fprintf(stderr, "ERROR: Unable to PUT %s from %s on port %d: %d %s\n",
251*5e7646d2SAndroid Build Coastguard Worker 	            resource, host, port, status, httpStatus(status));
252*5e7646d2SAndroid Build Coastguard Worker 	}
253*5e7646d2SAndroid Build Coastguard Worker 	else
254*5e7646d2SAndroid Build Coastguard Worker 	{
255*5e7646d2SAndroid Build Coastguard Worker 	 /*
256*5e7646d2SAndroid Build Coastguard Worker           * Move the new RSS file over top the old one...
257*5e7646d2SAndroid Build Coastguard Worker 	  */
258*5e7646d2SAndroid Build Coastguard Worker 
259*5e7646d2SAndroid Build Coastguard Worker           if (rename(newname, filename))
260*5e7646d2SAndroid Build Coastguard Worker             fprintf(stderr, "ERROR: Unable to rename %s to %s: %s\n",
261*5e7646d2SAndroid Build Coastguard Worker 	            newname, filename, strerror(errno));
262*5e7646d2SAndroid Build Coastguard Worker 	}
263*5e7646d2SAndroid Build Coastguard Worker 
264*5e7646d2SAndroid Build Coastguard Worker 	changed = 0;
265*5e7646d2SAndroid Build Coastguard Worker       }
266*5e7646d2SAndroid Build Coastguard Worker     }
267*5e7646d2SAndroid Build Coastguard Worker 
268*5e7646d2SAndroid Build Coastguard Worker    /*
269*5e7646d2SAndroid Build Coastguard Worker     * Wait up to 30 seconds for an event...
270*5e7646d2SAndroid Build Coastguard Worker     */
271*5e7646d2SAndroid Build Coastguard Worker 
272*5e7646d2SAndroid Build Coastguard Worker     timeout.tv_sec  = 30;
273*5e7646d2SAndroid Build Coastguard Worker     timeout.tv_usec = 0;
274*5e7646d2SAndroid Build Coastguard Worker 
275*5e7646d2SAndroid Build Coastguard Worker     FD_ZERO(&input);
276*5e7646d2SAndroid Build Coastguard Worker     FD_SET(0, &input);
277*5e7646d2SAndroid Build Coastguard Worker 
278*5e7646d2SAndroid Build Coastguard Worker     if (select(1, &input, NULL, NULL, &timeout) < 0)
279*5e7646d2SAndroid Build Coastguard Worker       continue;
280*5e7646d2SAndroid Build Coastguard Worker     else if (!FD_ISSET(0, &input))
281*5e7646d2SAndroid Build Coastguard Worker     {
282*5e7646d2SAndroid Build Coastguard Worker       fprintf(stderr, "DEBUG: %s is bored, exiting...\n", argv[1]);
283*5e7646d2SAndroid Build Coastguard Worker       break;
284*5e7646d2SAndroid Build Coastguard Worker     }
285*5e7646d2SAndroid Build Coastguard Worker 
286*5e7646d2SAndroid Build Coastguard Worker    /*
287*5e7646d2SAndroid Build Coastguard Worker     * Read the next event...
288*5e7646d2SAndroid Build Coastguard Worker     */
289*5e7646d2SAndroid Build Coastguard Worker 
290*5e7646d2SAndroid Build Coastguard Worker     event = ippNew();
291*5e7646d2SAndroid Build Coastguard Worker     while ((state = ippReadFile(0, event)) != IPP_DATA)
292*5e7646d2SAndroid Build Coastguard Worker     {
293*5e7646d2SAndroid Build Coastguard Worker       if (state <= IPP_IDLE)
294*5e7646d2SAndroid Build Coastguard Worker         break;
295*5e7646d2SAndroid Build Coastguard Worker     }
296*5e7646d2SAndroid Build Coastguard Worker 
297*5e7646d2SAndroid Build Coastguard Worker     if (state == IPP_ERROR)
298*5e7646d2SAndroid Build Coastguard Worker       fputs("DEBUG: ippReadFile() returned IPP_ERROR!\n", stderr);
299*5e7646d2SAndroid Build Coastguard Worker 
300*5e7646d2SAndroid Build Coastguard Worker     if (state <= IPP_IDLE)
301*5e7646d2SAndroid Build Coastguard Worker       break;
302*5e7646d2SAndroid Build Coastguard Worker 
303*5e7646d2SAndroid Build Coastguard Worker    /*
304*5e7646d2SAndroid Build Coastguard Worker     * Collect the info from the event...
305*5e7646d2SAndroid Build Coastguard Worker     */
306*5e7646d2SAndroid Build Coastguard Worker 
307*5e7646d2SAndroid Build Coastguard Worker     printer_up_time        = ippFindAttribute(event, "printer-up-time",
308*5e7646d2SAndroid Build Coastguard Worker                                               IPP_TAG_INTEGER);
309*5e7646d2SAndroid Build Coastguard Worker     notify_sequence_number = ippFindAttribute(event, "notify-sequence-number",
310*5e7646d2SAndroid Build Coastguard Worker                                 	      IPP_TAG_INTEGER);
311*5e7646d2SAndroid Build Coastguard Worker     notify_printer_uri     = ippFindAttribute(event, "notify-printer-uri",
312*5e7646d2SAndroid Build Coastguard Worker                                 	      IPP_TAG_URI);
313*5e7646d2SAndroid Build Coastguard Worker     subject                = cupsNotifySubject(language, event);
314*5e7646d2SAndroid Build Coastguard Worker     text                   = cupsNotifyText(language, event);
315*5e7646d2SAndroid Build Coastguard Worker 
316*5e7646d2SAndroid Build Coastguard Worker     if (printer_up_time && notify_sequence_number && subject && text)
317*5e7646d2SAndroid Build Coastguard Worker     {
318*5e7646d2SAndroid Build Coastguard Worker      /*
319*5e7646d2SAndroid Build Coastguard Worker       * Create a new RSS message...
320*5e7646d2SAndroid Build Coastguard Worker       */
321*5e7646d2SAndroid Build Coastguard Worker 
322*5e7646d2SAndroid Build Coastguard Worker       if (notify_printer_uri)
323*5e7646d2SAndroid Build Coastguard Worker       {
324*5e7646d2SAndroid Build Coastguard Worker         httpSeparateURI(HTTP_URI_CODING_ALL,
325*5e7646d2SAndroid Build Coastguard Worker 	                notify_printer_uri->values[0].string.text,
326*5e7646d2SAndroid Build Coastguard Worker 			link_scheme, sizeof(link_scheme),
327*5e7646d2SAndroid Build Coastguard Worker                         link_username, sizeof(link_username),
328*5e7646d2SAndroid Build Coastguard Worker 			link_host, sizeof(link_host), &link_port,
329*5e7646d2SAndroid Build Coastguard Worker 		        link_resource, sizeof(link_resource));
330*5e7646d2SAndroid Build Coastguard Worker         httpAssembleURI(HTTP_URI_CODING_ALL, link_url, sizeof(link_url),
331*5e7646d2SAndroid Build Coastguard Worker 	                "http", link_username, link_host, link_port,
332*5e7646d2SAndroid Build Coastguard Worker 			link_resource);
333*5e7646d2SAndroid Build Coastguard Worker       }
334*5e7646d2SAndroid Build Coastguard Worker 
335*5e7646d2SAndroid Build Coastguard Worker       msg = new_message(notify_sequence_number->values[0].integer,
336*5e7646d2SAndroid Build Coastguard Worker                         xml_escape(subject), xml_escape(text),
337*5e7646d2SAndroid Build Coastguard Worker 			notify_printer_uri ? xml_escape(link_url) : NULL,
338*5e7646d2SAndroid Build Coastguard Worker 			printer_up_time->values[0].integer);
339*5e7646d2SAndroid Build Coastguard Worker 
340*5e7646d2SAndroid Build Coastguard Worker       if (!msg)
341*5e7646d2SAndroid Build Coastguard Worker       {
342*5e7646d2SAndroid Build Coastguard Worker         fprintf(stderr, "ERROR: Unable to create message: %s\n",
343*5e7646d2SAndroid Build Coastguard Worker 	        strerror(errno));
344*5e7646d2SAndroid Build Coastguard Worker         exit_status = 1;
345*5e7646d2SAndroid Build Coastguard Worker 	break;
346*5e7646d2SAndroid Build Coastguard Worker       }
347*5e7646d2SAndroid Build Coastguard Worker 
348*5e7646d2SAndroid Build Coastguard Worker      /*
349*5e7646d2SAndroid Build Coastguard Worker       * Add it to the array...
350*5e7646d2SAndroid Build Coastguard Worker       */
351*5e7646d2SAndroid Build Coastguard Worker 
352*5e7646d2SAndroid Build Coastguard Worker       cupsArrayAdd(rss, msg);
353*5e7646d2SAndroid Build Coastguard Worker 
354*5e7646d2SAndroid Build Coastguard Worker       changed = 1;
355*5e7646d2SAndroid Build Coastguard Worker 
356*5e7646d2SAndroid Build Coastguard Worker      /*
357*5e7646d2SAndroid Build Coastguard Worker       * Trim the array as needed...
358*5e7646d2SAndroid Build Coastguard Worker       */
359*5e7646d2SAndroid Build Coastguard Worker 
360*5e7646d2SAndroid Build Coastguard Worker       while (cupsArrayCount(rss) > max_events)
361*5e7646d2SAndroid Build Coastguard Worker       {
362*5e7646d2SAndroid Build Coastguard Worker         msg = cupsArrayFirst(rss);
363*5e7646d2SAndroid Build Coastguard Worker 
364*5e7646d2SAndroid Build Coastguard Worker 	cupsArrayRemove(rss, msg);
365*5e7646d2SAndroid Build Coastguard Worker 
366*5e7646d2SAndroid Build Coastguard Worker 	delete_message(msg);
367*5e7646d2SAndroid Build Coastguard Worker       }
368*5e7646d2SAndroid Build Coastguard Worker     }
369*5e7646d2SAndroid Build Coastguard Worker 
370*5e7646d2SAndroid Build Coastguard Worker     if (subject)
371*5e7646d2SAndroid Build Coastguard Worker       free(subject);
372*5e7646d2SAndroid Build Coastguard Worker 
373*5e7646d2SAndroid Build Coastguard Worker     if (text)
374*5e7646d2SAndroid Build Coastguard Worker       free(text);
375*5e7646d2SAndroid Build Coastguard Worker 
376*5e7646d2SAndroid Build Coastguard Worker     ippDelete(event);
377*5e7646d2SAndroid Build Coastguard Worker     event = NULL;
378*5e7646d2SAndroid Build Coastguard Worker   }
379*5e7646d2SAndroid Build Coastguard Worker 
380*5e7646d2SAndroid Build Coastguard Worker  /*
381*5e7646d2SAndroid Build Coastguard Worker   * We only get here when idle or error...
382*5e7646d2SAndroid Build Coastguard Worker   */
383*5e7646d2SAndroid Build Coastguard Worker 
384*5e7646d2SAndroid Build Coastguard Worker   ippDelete(event);
385*5e7646d2SAndroid Build Coastguard Worker 
386*5e7646d2SAndroid Build Coastguard Worker   if (http)
387*5e7646d2SAndroid Build Coastguard Worker   {
388*5e7646d2SAndroid Build Coastguard Worker     unlink(filename);
389*5e7646d2SAndroid Build Coastguard Worker     httpClose(http);
390*5e7646d2SAndroid Build Coastguard Worker   }
391*5e7646d2SAndroid Build Coastguard Worker 
392*5e7646d2SAndroid Build Coastguard Worker   return (exit_status);
393*5e7646d2SAndroid Build Coastguard Worker }
394*5e7646d2SAndroid Build Coastguard Worker 
395*5e7646d2SAndroid Build Coastguard Worker 
396*5e7646d2SAndroid Build Coastguard Worker /*
397*5e7646d2SAndroid Build Coastguard Worker  * 'compare_rss()' - Compare two messages.
398*5e7646d2SAndroid Build Coastguard Worker  */
399*5e7646d2SAndroid Build Coastguard Worker 
400*5e7646d2SAndroid Build Coastguard Worker static int				/* O - Result of comparison */
compare_rss(_cups_rss_t * a,_cups_rss_t * b)401*5e7646d2SAndroid Build Coastguard Worker compare_rss(_cups_rss_t *a,		/* I - First message */
402*5e7646d2SAndroid Build Coastguard Worker             _cups_rss_t *b)		/* I - Second message */
403*5e7646d2SAndroid Build Coastguard Worker {
404*5e7646d2SAndroid Build Coastguard Worker   return (a->sequence_number - b->sequence_number);
405*5e7646d2SAndroid Build Coastguard Worker }
406*5e7646d2SAndroid Build Coastguard Worker 
407*5e7646d2SAndroid Build Coastguard Worker 
408*5e7646d2SAndroid Build Coastguard Worker /*
409*5e7646d2SAndroid Build Coastguard Worker  * 'delete_message()' - Free all memory used by a message.
410*5e7646d2SAndroid Build Coastguard Worker  */
411*5e7646d2SAndroid Build Coastguard Worker 
412*5e7646d2SAndroid Build Coastguard Worker static void
delete_message(_cups_rss_t * msg)413*5e7646d2SAndroid Build Coastguard Worker delete_message(_cups_rss_t *msg)	/* I - RSS message */
414*5e7646d2SAndroid Build Coastguard Worker {
415*5e7646d2SAndroid Build Coastguard Worker   if (msg->subject)
416*5e7646d2SAndroid Build Coastguard Worker     free(msg->subject);
417*5e7646d2SAndroid Build Coastguard Worker 
418*5e7646d2SAndroid Build Coastguard Worker   if (msg->text)
419*5e7646d2SAndroid Build Coastguard Worker     free(msg->text);
420*5e7646d2SAndroid Build Coastguard Worker 
421*5e7646d2SAndroid Build Coastguard Worker   if (msg->link_url)
422*5e7646d2SAndroid Build Coastguard Worker     free(msg->link_url);
423*5e7646d2SAndroid Build Coastguard Worker 
424*5e7646d2SAndroid Build Coastguard Worker   free(msg);
425*5e7646d2SAndroid Build Coastguard Worker }
426*5e7646d2SAndroid Build Coastguard Worker 
427*5e7646d2SAndroid Build Coastguard Worker 
428*5e7646d2SAndroid Build Coastguard Worker /*
429*5e7646d2SAndroid Build Coastguard Worker  * 'load_rss()' - Load an existing RSS feed file.
430*5e7646d2SAndroid Build Coastguard Worker  */
431*5e7646d2SAndroid Build Coastguard Worker 
432*5e7646d2SAndroid Build Coastguard Worker static void
load_rss(cups_array_t * rss,const char * filename)433*5e7646d2SAndroid Build Coastguard Worker load_rss(cups_array_t *rss,		/* I - RSS messages */
434*5e7646d2SAndroid Build Coastguard Worker          const char   *filename)	/* I - File to load */
435*5e7646d2SAndroid Build Coastguard Worker {
436*5e7646d2SAndroid Build Coastguard Worker   FILE		*fp;			/* File pointer */
437*5e7646d2SAndroid Build Coastguard Worker   char		line[4096],		/* Line from file */
438*5e7646d2SAndroid Build Coastguard Worker 		*subject,		/* Subject */
439*5e7646d2SAndroid Build Coastguard Worker 		*text,			/* Text */
440*5e7646d2SAndroid Build Coastguard Worker 		*link_url,		/* Link URL */
441*5e7646d2SAndroid Build Coastguard Worker 		*start,			/* Start of element */
442*5e7646d2SAndroid Build Coastguard Worker 		*end;			/* End of element */
443*5e7646d2SAndroid Build Coastguard Worker   time_t	event_time;		/* Event time */
444*5e7646d2SAndroid Build Coastguard Worker   int		sequence_number;	/* Sequence number */
445*5e7646d2SAndroid Build Coastguard Worker   int		in_item;		/* In an item */
446*5e7646d2SAndroid Build Coastguard Worker   _cups_rss_t	*msg;			/* New message */
447*5e7646d2SAndroid Build Coastguard Worker 
448*5e7646d2SAndroid Build Coastguard Worker 
449*5e7646d2SAndroid Build Coastguard Worker   if ((fp = fopen(filename, "r")) == NULL)
450*5e7646d2SAndroid Build Coastguard Worker   {
451*5e7646d2SAndroid Build Coastguard Worker     if (errno != ENOENT)
452*5e7646d2SAndroid Build Coastguard Worker       fprintf(stderr, "ERROR: Unable to open %s: %s\n", filename,
453*5e7646d2SAndroid Build Coastguard Worker               strerror(errno));
454*5e7646d2SAndroid Build Coastguard Worker 
455*5e7646d2SAndroid Build Coastguard Worker     return;
456*5e7646d2SAndroid Build Coastguard Worker   }
457*5e7646d2SAndroid Build Coastguard Worker 
458*5e7646d2SAndroid Build Coastguard Worker   subject         = NULL;
459*5e7646d2SAndroid Build Coastguard Worker   text            = NULL;
460*5e7646d2SAndroid Build Coastguard Worker   link_url        = NULL;
461*5e7646d2SAndroid Build Coastguard Worker   event_time      = 0;
462*5e7646d2SAndroid Build Coastguard Worker   sequence_number = 0;
463*5e7646d2SAndroid Build Coastguard Worker   in_item         = 0;
464*5e7646d2SAndroid Build Coastguard Worker 
465*5e7646d2SAndroid Build Coastguard Worker   while (fgets(line, sizeof(line), fp))
466*5e7646d2SAndroid Build Coastguard Worker   {
467*5e7646d2SAndroid Build Coastguard Worker     if (strstr(line, "<item>"))
468*5e7646d2SAndroid Build Coastguard Worker       in_item = 1;
469*5e7646d2SAndroid Build Coastguard Worker     else if (strstr(line, "</item>") && in_item)
470*5e7646d2SAndroid Build Coastguard Worker     {
471*5e7646d2SAndroid Build Coastguard Worker       if (subject && text)
472*5e7646d2SAndroid Build Coastguard Worker       {
473*5e7646d2SAndroid Build Coastguard Worker         msg = new_message(sequence_number, subject, text, link_url,
474*5e7646d2SAndroid Build Coastguard Worker 	                  event_time);
475*5e7646d2SAndroid Build Coastguard Worker 
476*5e7646d2SAndroid Build Coastguard Worker         if (msg)
477*5e7646d2SAndroid Build Coastguard Worker 	  cupsArrayAdd(rss, msg);
478*5e7646d2SAndroid Build Coastguard Worker 
479*5e7646d2SAndroid Build Coastguard Worker       }
480*5e7646d2SAndroid Build Coastguard Worker       else
481*5e7646d2SAndroid Build Coastguard Worker       {
482*5e7646d2SAndroid Build Coastguard Worker         if (subject)
483*5e7646d2SAndroid Build Coastguard Worker 	  free(subject);
484*5e7646d2SAndroid Build Coastguard Worker 
485*5e7646d2SAndroid Build Coastguard Worker 	if (text)
486*5e7646d2SAndroid Build Coastguard Worker 	  free(text);
487*5e7646d2SAndroid Build Coastguard Worker 
488*5e7646d2SAndroid Build Coastguard Worker 	if (link_url)
489*5e7646d2SAndroid Build Coastguard Worker 	  free(link_url);
490*5e7646d2SAndroid Build Coastguard Worker       }
491*5e7646d2SAndroid Build Coastguard Worker 
492*5e7646d2SAndroid Build Coastguard Worker       subject         = NULL;
493*5e7646d2SAndroid Build Coastguard Worker       text            = NULL;
494*5e7646d2SAndroid Build Coastguard Worker       link_url        = NULL;
495*5e7646d2SAndroid Build Coastguard Worker       event_time      = 0;
496*5e7646d2SAndroid Build Coastguard Worker       sequence_number = 0;
497*5e7646d2SAndroid Build Coastguard Worker       in_item         = 0;
498*5e7646d2SAndroid Build Coastguard Worker     }
499*5e7646d2SAndroid Build Coastguard Worker     else if (!in_item)
500*5e7646d2SAndroid Build Coastguard Worker       continue;
501*5e7646d2SAndroid Build Coastguard Worker     else if ((start = strstr(line, "<title>")) != NULL)
502*5e7646d2SAndroid Build Coastguard Worker     {
503*5e7646d2SAndroid Build Coastguard Worker       start += 7;
504*5e7646d2SAndroid Build Coastguard Worker       if ((end = strstr(start, "</title>")) != NULL)
505*5e7646d2SAndroid Build Coastguard Worker       {
506*5e7646d2SAndroid Build Coastguard Worker         *end    = '\0';
507*5e7646d2SAndroid Build Coastguard Worker 	subject = strdup(start);
508*5e7646d2SAndroid Build Coastguard Worker       }
509*5e7646d2SAndroid Build Coastguard Worker     }
510*5e7646d2SAndroid Build Coastguard Worker     else if ((start = strstr(line, "<description>")) != NULL)
511*5e7646d2SAndroid Build Coastguard Worker     {
512*5e7646d2SAndroid Build Coastguard Worker       start += 13;
513*5e7646d2SAndroid Build Coastguard Worker       if ((end = strstr(start, "</description>")) != NULL)
514*5e7646d2SAndroid Build Coastguard Worker       {
515*5e7646d2SAndroid Build Coastguard Worker         *end = '\0';
516*5e7646d2SAndroid Build Coastguard Worker 	text = strdup(start);
517*5e7646d2SAndroid Build Coastguard Worker       }
518*5e7646d2SAndroid Build Coastguard Worker     }
519*5e7646d2SAndroid Build Coastguard Worker     else if ((start = strstr(line, "<link>")) != NULL)
520*5e7646d2SAndroid Build Coastguard Worker     {
521*5e7646d2SAndroid Build Coastguard Worker       start += 6;
522*5e7646d2SAndroid Build Coastguard Worker       if ((end = strstr(start, "</link>")) != NULL)
523*5e7646d2SAndroid Build Coastguard Worker       {
524*5e7646d2SAndroid Build Coastguard Worker         *end     = '\0';
525*5e7646d2SAndroid Build Coastguard Worker 	link_url = strdup(start);
526*5e7646d2SAndroid Build Coastguard Worker       }
527*5e7646d2SAndroid Build Coastguard Worker     }
528*5e7646d2SAndroid Build Coastguard Worker     else if ((start = strstr(line, "<pubDate>")) != NULL)
529*5e7646d2SAndroid Build Coastguard Worker     {
530*5e7646d2SAndroid Build Coastguard Worker       start += 9;
531*5e7646d2SAndroid Build Coastguard Worker       if ((end = strstr(start, "</pubDate>")) != NULL)
532*5e7646d2SAndroid Build Coastguard Worker       {
533*5e7646d2SAndroid Build Coastguard Worker         *end       = '\0';
534*5e7646d2SAndroid Build Coastguard Worker 	event_time = httpGetDateTime(start);
535*5e7646d2SAndroid Build Coastguard Worker       }
536*5e7646d2SAndroid Build Coastguard Worker     }
537*5e7646d2SAndroid Build Coastguard Worker     else if ((start = strstr(line, "<guid>")) != NULL)
538*5e7646d2SAndroid Build Coastguard Worker       sequence_number = atoi(start + 6);
539*5e7646d2SAndroid Build Coastguard Worker   }
540*5e7646d2SAndroid Build Coastguard Worker 
541*5e7646d2SAndroid Build Coastguard Worker   if (subject)
542*5e7646d2SAndroid Build Coastguard Worker     free(subject);
543*5e7646d2SAndroid Build Coastguard Worker 
544*5e7646d2SAndroid Build Coastguard Worker   if (text)
545*5e7646d2SAndroid Build Coastguard Worker     free(text);
546*5e7646d2SAndroid Build Coastguard Worker 
547*5e7646d2SAndroid Build Coastguard Worker   if (link_url)
548*5e7646d2SAndroid Build Coastguard Worker     free(link_url);
549*5e7646d2SAndroid Build Coastguard Worker 
550*5e7646d2SAndroid Build Coastguard Worker   fclose(fp);
551*5e7646d2SAndroid Build Coastguard Worker }
552*5e7646d2SAndroid Build Coastguard Worker 
553*5e7646d2SAndroid Build Coastguard Worker 
554*5e7646d2SAndroid Build Coastguard Worker /*
555*5e7646d2SAndroid Build Coastguard Worker  * 'new_message()' - Create a new RSS message.
556*5e7646d2SAndroid Build Coastguard Worker  */
557*5e7646d2SAndroid Build Coastguard Worker 
558*5e7646d2SAndroid Build Coastguard Worker static _cups_rss_t *			/* O - New message */
new_message(int sequence_number,char * subject,char * text,char * link_url,time_t event_time)559*5e7646d2SAndroid Build Coastguard Worker new_message(int    sequence_number,	/* I - notify-sequence-number */
560*5e7646d2SAndroid Build Coastguard Worker             char   *subject,		/* I - Subject/summary */
561*5e7646d2SAndroid Build Coastguard Worker             char   *text,		/* I - Text */
562*5e7646d2SAndroid Build Coastguard Worker 	    char   *link_url,		/* I - Link to printer */
563*5e7646d2SAndroid Build Coastguard Worker 	    time_t event_time)		/* I - Date/time of event */
564*5e7646d2SAndroid Build Coastguard Worker {
565*5e7646d2SAndroid Build Coastguard Worker   _cups_rss_t	*msg;			/* New message */
566*5e7646d2SAndroid Build Coastguard Worker 
567*5e7646d2SAndroid Build Coastguard Worker 
568*5e7646d2SAndroid Build Coastguard Worker   if ((msg = calloc(1, sizeof(_cups_rss_t))) == NULL)
569*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
570*5e7646d2SAndroid Build Coastguard Worker 
571*5e7646d2SAndroid Build Coastguard Worker   msg->sequence_number = sequence_number;
572*5e7646d2SAndroid Build Coastguard Worker   msg->subject         = subject;
573*5e7646d2SAndroid Build Coastguard Worker   msg->text            = text;
574*5e7646d2SAndroid Build Coastguard Worker   msg->link_url        = link_url;
575*5e7646d2SAndroid Build Coastguard Worker   msg->event_time      = event_time;
576*5e7646d2SAndroid Build Coastguard Worker 
577*5e7646d2SAndroid Build Coastguard Worker   return (msg);
578*5e7646d2SAndroid Build Coastguard Worker }
579*5e7646d2SAndroid Build Coastguard Worker 
580*5e7646d2SAndroid Build Coastguard Worker 
581*5e7646d2SAndroid Build Coastguard Worker /*
582*5e7646d2SAndroid Build Coastguard Worker  * 'password_cb()' - Return the cached password.
583*5e7646d2SAndroid Build Coastguard Worker  */
584*5e7646d2SAndroid Build Coastguard Worker 
585*5e7646d2SAndroid Build Coastguard Worker static const char *			/* O - Cached password */
password_cb(const char * prompt)586*5e7646d2SAndroid Build Coastguard Worker password_cb(const char *prompt)		/* I - Prompt string, unused */
587*5e7646d2SAndroid Build Coastguard Worker {
588*5e7646d2SAndroid Build Coastguard Worker   (void)prompt;
589*5e7646d2SAndroid Build Coastguard Worker 
590*5e7646d2SAndroid Build Coastguard Worker   return (rss_password);
591*5e7646d2SAndroid Build Coastguard Worker }
592*5e7646d2SAndroid Build Coastguard Worker 
593*5e7646d2SAndroid Build Coastguard Worker 
594*5e7646d2SAndroid Build Coastguard Worker /*
595*5e7646d2SAndroid Build Coastguard Worker  * 'save_rss()' - Save messages to a RSS file.
596*5e7646d2SAndroid Build Coastguard Worker  */
597*5e7646d2SAndroid Build Coastguard Worker 
598*5e7646d2SAndroid Build Coastguard Worker static int				/* O - 1 on success, 0 on failure */
save_rss(cups_array_t * rss,const char * filename,const char * baseurl)599*5e7646d2SAndroid Build Coastguard Worker save_rss(cups_array_t *rss,		/* I - RSS messages */
600*5e7646d2SAndroid Build Coastguard Worker          const char   *filename,	/* I - File to save to */
601*5e7646d2SAndroid Build Coastguard Worker 	 const char   *baseurl)		/* I - Base URL */
602*5e7646d2SAndroid Build Coastguard Worker {
603*5e7646d2SAndroid Build Coastguard Worker   FILE		*fp;			/* File pointer */
604*5e7646d2SAndroid Build Coastguard Worker   _cups_rss_t	*msg;			/* Current message */
605*5e7646d2SAndroid Build Coastguard Worker   char		date[1024];		/* Current date */
606*5e7646d2SAndroid Build Coastguard Worker   char		*href;			/* Escaped base URL */
607*5e7646d2SAndroid Build Coastguard Worker 
608*5e7646d2SAndroid Build Coastguard Worker 
609*5e7646d2SAndroid Build Coastguard Worker   if ((fp = fopen(filename, "w")) == NULL)
610*5e7646d2SAndroid Build Coastguard Worker   {
611*5e7646d2SAndroid Build Coastguard Worker     fprintf(stderr, "ERROR: Unable to create %s: %s\n", filename,
612*5e7646d2SAndroid Build Coastguard Worker             strerror(errno));
613*5e7646d2SAndroid Build Coastguard Worker     return (0);
614*5e7646d2SAndroid Build Coastguard Worker   }
615*5e7646d2SAndroid Build Coastguard Worker 
616*5e7646d2SAndroid Build Coastguard Worker   fchmod(fileno(fp), 0644);
617*5e7646d2SAndroid Build Coastguard Worker 
618*5e7646d2SAndroid Build Coastguard Worker   fputs("<?xml version=\"1.0\"?>\n", fp);
619*5e7646d2SAndroid Build Coastguard Worker   fputs("<rss version=\"2.0\">\n", fp);
620*5e7646d2SAndroid Build Coastguard Worker   fputs("  <channel>\n", fp);
621*5e7646d2SAndroid Build Coastguard Worker   fputs("    <title>CUPS RSS Feed</title>\n", fp);
622*5e7646d2SAndroid Build Coastguard Worker 
623*5e7646d2SAndroid Build Coastguard Worker   href = xml_escape(baseurl);
624*5e7646d2SAndroid Build Coastguard Worker   fprintf(fp, "    <link>%s</link>\n", href);
625*5e7646d2SAndroid Build Coastguard Worker   free(href);
626*5e7646d2SAndroid Build Coastguard Worker 
627*5e7646d2SAndroid Build Coastguard Worker   fputs("    <description>CUPS RSS Feed</description>\n", fp);
628*5e7646d2SAndroid Build Coastguard Worker   fputs("    <generator>" CUPS_SVERSION "</generator>\n", fp);
629*5e7646d2SAndroid Build Coastguard Worker   fputs("    <ttl>1</ttl>\n", fp);
630*5e7646d2SAndroid Build Coastguard Worker 
631*5e7646d2SAndroid Build Coastguard Worker   fprintf(fp, "    <pubDate>%s</pubDate>\n",
632*5e7646d2SAndroid Build Coastguard Worker           httpGetDateString2(time(NULL), date, sizeof(date)));
633*5e7646d2SAndroid Build Coastguard Worker 
634*5e7646d2SAndroid Build Coastguard Worker   for (msg = (_cups_rss_t *)cupsArrayLast(rss);
635*5e7646d2SAndroid Build Coastguard Worker        msg;
636*5e7646d2SAndroid Build Coastguard Worker        msg = (_cups_rss_t *)cupsArrayPrev(rss))
637*5e7646d2SAndroid Build Coastguard Worker   {
638*5e7646d2SAndroid Build Coastguard Worker     char *subject = xml_escape(msg->subject);
639*5e7646d2SAndroid Build Coastguard Worker     char *text = xml_escape(msg->text);
640*5e7646d2SAndroid Build Coastguard Worker 
641*5e7646d2SAndroid Build Coastguard Worker     fputs("    <item>\n", fp);
642*5e7646d2SAndroid Build Coastguard Worker     fprintf(fp, "      <title>%s</title>\n", subject);
643*5e7646d2SAndroid Build Coastguard Worker     fprintf(fp, "      <description>%s</description>\n", text);
644*5e7646d2SAndroid Build Coastguard Worker     if (msg->link_url)
645*5e7646d2SAndroid Build Coastguard Worker       fprintf(fp, "      <link>%s</link>\n", msg->link_url);
646*5e7646d2SAndroid Build Coastguard Worker     fprintf(fp, "      <pubDate>%s</pubDate>\n",
647*5e7646d2SAndroid Build Coastguard Worker             httpGetDateString2(msg->event_time, date, sizeof(date)));
648*5e7646d2SAndroid Build Coastguard Worker     fprintf(fp, "      <guid>%d</guid>\n", msg->sequence_number);
649*5e7646d2SAndroid Build Coastguard Worker     fputs("    </item>\n", fp);
650*5e7646d2SAndroid Build Coastguard Worker 
651*5e7646d2SAndroid Build Coastguard Worker     free(subject);
652*5e7646d2SAndroid Build Coastguard Worker     free(text);
653*5e7646d2SAndroid Build Coastguard Worker   }
654*5e7646d2SAndroid Build Coastguard Worker 
655*5e7646d2SAndroid Build Coastguard Worker   fputs(" </channel>\n", fp);
656*5e7646d2SAndroid Build Coastguard Worker   fputs("</rss>\n", fp);
657*5e7646d2SAndroid Build Coastguard Worker 
658*5e7646d2SAndroid Build Coastguard Worker   return (!fclose(fp));
659*5e7646d2SAndroid Build Coastguard Worker }
660*5e7646d2SAndroid Build Coastguard Worker 
661*5e7646d2SAndroid Build Coastguard Worker 
662*5e7646d2SAndroid Build Coastguard Worker /*
663*5e7646d2SAndroid Build Coastguard Worker  * 'xml_escape()' - Copy a string, escaping &, <, and > as needed.
664*5e7646d2SAndroid Build Coastguard Worker  */
665*5e7646d2SAndroid Build Coastguard Worker 
666*5e7646d2SAndroid Build Coastguard Worker static char *				/* O - Escaped string */
xml_escape(const char * s)667*5e7646d2SAndroid Build Coastguard Worker xml_escape(const char *s)		/* I - String to escape */
668*5e7646d2SAndroid Build Coastguard Worker {
669*5e7646d2SAndroid Build Coastguard Worker   char		*e,			/* Escaped string */
670*5e7646d2SAndroid Build Coastguard Worker 		*eptr;			/* Pointer into escaped string */
671*5e7646d2SAndroid Build Coastguard Worker   const char	*sptr;			/* Pointer into string */
672*5e7646d2SAndroid Build Coastguard Worker   size_t	bytes;			/* Bytes needed for string */
673*5e7646d2SAndroid Build Coastguard Worker 
674*5e7646d2SAndroid Build Coastguard Worker 
675*5e7646d2SAndroid Build Coastguard Worker  /*
676*5e7646d2SAndroid Build Coastguard Worker   * First figure out how many extra bytes we need...
677*5e7646d2SAndroid Build Coastguard Worker   */
678*5e7646d2SAndroid Build Coastguard Worker 
679*5e7646d2SAndroid Build Coastguard Worker   for (bytes = 0, sptr = s; *sptr; sptr ++)
680*5e7646d2SAndroid Build Coastguard Worker     if (*sptr == '&')
681*5e7646d2SAndroid Build Coastguard Worker       bytes += 4;			/* &amp; */
682*5e7646d2SAndroid Build Coastguard Worker     else if (*sptr == '<' || *sptr == '>')
683*5e7646d2SAndroid Build Coastguard Worker       bytes += 3;			/* &lt; and &gt; */
684*5e7646d2SAndroid Build Coastguard Worker 
685*5e7646d2SAndroid Build Coastguard Worker  /*
686*5e7646d2SAndroid Build Coastguard Worker   * If there is nothing to escape, just strdup() it...
687*5e7646d2SAndroid Build Coastguard Worker   */
688*5e7646d2SAndroid Build Coastguard Worker 
689*5e7646d2SAndroid Build Coastguard Worker   if (bytes == 0)
690*5e7646d2SAndroid Build Coastguard Worker     return (strdup(s));
691*5e7646d2SAndroid Build Coastguard Worker 
692*5e7646d2SAndroid Build Coastguard Worker  /*
693*5e7646d2SAndroid Build Coastguard Worker   * Otherwise allocate memory and copy...
694*5e7646d2SAndroid Build Coastguard Worker   */
695*5e7646d2SAndroid Build Coastguard Worker 
696*5e7646d2SAndroid Build Coastguard Worker   if ((e = malloc(bytes + 1 + strlen(s))) == NULL)
697*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
698*5e7646d2SAndroid Build Coastguard Worker 
699*5e7646d2SAndroid Build Coastguard Worker   for (eptr = e, sptr = s; *sptr; sptr ++)
700*5e7646d2SAndroid Build Coastguard Worker     if (*sptr == '&')
701*5e7646d2SAndroid Build Coastguard Worker     {
702*5e7646d2SAndroid Build Coastguard Worker       *eptr++ = '&';
703*5e7646d2SAndroid Build Coastguard Worker       *eptr++ = 'a';
704*5e7646d2SAndroid Build Coastguard Worker       *eptr++ = 'm';
705*5e7646d2SAndroid Build Coastguard Worker       *eptr++ = 'p';
706*5e7646d2SAndroid Build Coastguard Worker       *eptr++ = ';';
707*5e7646d2SAndroid Build Coastguard Worker     }
708*5e7646d2SAndroid Build Coastguard Worker     else if (*sptr == '<')
709*5e7646d2SAndroid Build Coastguard Worker     {
710*5e7646d2SAndroid Build Coastguard Worker       *eptr++ = '&';
711*5e7646d2SAndroid Build Coastguard Worker       *eptr++ = 'l';
712*5e7646d2SAndroid Build Coastguard Worker       *eptr++ = 't';
713*5e7646d2SAndroid Build Coastguard Worker       *eptr++ = ';';
714*5e7646d2SAndroid Build Coastguard Worker     }
715*5e7646d2SAndroid Build Coastguard Worker     else if (*sptr == '>')
716*5e7646d2SAndroid Build Coastguard Worker     {
717*5e7646d2SAndroid Build Coastguard Worker       *eptr++ = '&';
718*5e7646d2SAndroid Build Coastguard Worker       *eptr++ = 'g';
719*5e7646d2SAndroid Build Coastguard Worker       *eptr++ = 't';
720*5e7646d2SAndroid Build Coastguard Worker       *eptr++ = ';';
721*5e7646d2SAndroid Build Coastguard Worker     }
722*5e7646d2SAndroid Build Coastguard Worker     else
723*5e7646d2SAndroid Build Coastguard Worker       *eptr++ = *sptr;
724*5e7646d2SAndroid Build Coastguard Worker 
725*5e7646d2SAndroid Build Coastguard Worker   *eptr = '\0';
726*5e7646d2SAndroid Build Coastguard Worker 
727*5e7646d2SAndroid Build Coastguard Worker   return (e);
728*5e7646d2SAndroid Build Coastguard Worker }
729