]> git.ipfire.org Git - thirdparty/sarg.git/blame - grepday.c
Complex file names out of messages to translate
[thirdparty/sarg.git] / grepday.c
CommitLineData
25697a35 1/*
94ff9470 2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
e99bf0c0 3 * 1998, 2013
25697a35
GS
4 *
5 * SARG donations:
6 * please look at http://sarg.sourceforge.net/donations.php
1164c474
FM
7 * Support:
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
25697a35
GS
9 * ---------------------------------------------------------------------
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
24 *
25 */
26
27#include "include/conf.h"
5f3cfd1d 28#include "include/defs.h"
25697a35 29
a1de61fe 30#if defined(HAVE_GD)
17c89803 31
a1de61fe 32#if defined(HAVE_ICONV_H) && defined(gdFTEX_Unicode)
25697a35 33#include <iconv.h>
e43854ef
FM
34#define USE_ICONV 1
35#endif
25697a35 36
e43854ef 37struct GraphDataStruct
25697a35 38{
9bd92830
FM
39 int lavender;
40 int darkblue;
41 int dimgray;
42 int goldenrod;
43 int goldenrod2;
44 int gray;
45 int silver;
46 int black;
47 //! The color of the top side of a graph bar.
48 int color1;
49 //! The color of the right side of a graph bar.
50 int color2;
51 //! The color of the front side of a graph bar.
52 int color3;
53 //! The libgd image we are drawing on.
54 gdImage *im;
55 //! An allocated buffer to convert the string into UTF-8.
56 char *string;
57 //! The number of bytes allocated for the string buffer.
58 size_t string_size;
59 //! The bottom border of the graph.
60 int BottomGraph;
61 //! The top border of the graph.
62 int TopGraph;
63 //! The left border of the graph.
64 int LeftGraph;
65 //! The right border of the graph.
66 int RightGraph;
67 //! The height at which the bottom depth border of the graph extends.
68 int BottomDepth;
69 //! The distance between two ticks on the horizontal axis.
70 double XScale;
71 //! The distance between two ticks on the vertical axis.
72 double YScale;
73 //! The exterior length of a tick on the scales.
74 int TickLength;
75 //! The distance, in pixels, between two ticks along the Y axis.
76 int YTickSpace;
286f212b
FM
77};
78
79enum PlotType
80{
9bd92830
FM
81 PTG_LinBin,
82 PTG_LogBin,
83 PTG_Time,
286f212b
FM
84};
85
86struct PlotStruct
87{
9bd92830
FM
88 //! The data points to plot.
89 long long int *datapoints;
90 //! The number of points to plot.
91 int npoints;
92 //! The minimum data to plot along the Y axis.
93 long long int ymin;
94 //! The maximum data to plot along the Y axis.
95 long long int ymax;
96 //! The type of Y axis to draw.
97 enum PlotType ytype;
98 //! The label to write on the X axis.
99 const char *XLabel;
100 //! The label to write on the Y axis.
101 const char *YLabel;
102 //! The name of the output PNG file.
103 const char *pngfile;
e43854ef
FM
104};
105
106enum TextRefPos
107{
9bd92830
FM
108 TRP_TopLeft,
109 TRP_TopCenter,
110 TRP_TopRight,
111 TRP_BottomLeft,
112 TRP_BottomCenter,
113 TRP_BottomRight,
114 TRP_CenterLeft,
115 TRP_Center,
116 TRP_CenterRight,
e43854ef
FM
117};
118
1f482a8d
FM
119#ifdef USE_ICONV
120//! The iconv object to convert the text from the locale character set to UTF-8.
121iconv_t localtoutf=(iconv_t)-1;
122#endif
123
124static void Sarg_gdImageStringFT (struct GraphDataStruct *gdata, int fg, char *fontlist,
007905af 125 double ptsize, double angle, int x, int y, const char *string,enum TextRefPos RefPos)
e43854ef 126{
9bd92830
FM
127 char *sstring;
128 char *retval;
129 int brect[8];
130 int minx,miny,maxx,maxy;
131 int i;
e43854ef
FM
132
133#ifdef USE_ICONV
9bd92830
FM
134 if (localtoutf!=(iconv_t)-1) {
135 const char *str;
136 char *sstr;
137 size_t slen, sslen;
138
139 slen = strlen(string) + 1; // We must include string termination character
140 sslen = slen * 3; // We assume that the UTF8 string will not be bigger than 3 times the original size.
141 if (sslen>gdata->string_size) {
142 sstring = (char *)realloc(gdata->string,sslen);
143 if (!sstring) {
144 debuga(_("realloc error (%"PRIu64" bytes required)\n"),(uint64_t)sslen);
145 exit(EXIT_FAILURE);
146 }
147 gdata->string=(char *)sstring;
148 gdata->string_size=sslen;
149 } else {
150 sstring=gdata->string;
151 sslen=gdata->string_size;
152 }
153
154 str = string;
155 sstr = sstring;
156 if (iconv (localtoutf, (ICONV_CONST char **)&str, &slen, &sstr, &sslen)==-1) {
4b06d570
FM
157 /* TRANSLATORS: First %s is the string that failed to convert. Second %s is the input
158 * character encoding. Last %s is the reason for the failure.
159 */
160 debugapos("grepday",_("iconv failed to convert string \"%s\" from %s to UTF-8: %s\n"),string,CharSet,strerror(errno));
9bd92830
FM
161 sstring=(char *)string; //show something sensible on the graph
162 }
163 } else {
164 sstring=(char *)string; //show something sensible on the graph
165 }
e43854ef 166#else
9bd92830 167 sstring=(char *)string;
e43854ef
FM
168#endif
169
9bd92830
FM
170 if (RefPos!=TRP_BottomLeft) {
171 retval = gdImageStringFTEx (NULL, brect, fg, fontlist, ptsize, angle, 0, 0, sstring, gdFTEX_Unicode);
172 if (retval) {
173 debuga(_("libgd failed to calculate the bounding box of the text \"%s\": %s\n"),sstring,retval);
174 exit(EXIT_FAILURE);
175 }
176 /*
177 From libgd documentation, brect contains this without taking into account the angle:
178 0 lower left corner, X position
179 1 lower left corner, Y position
180 2 lower right corner, X position
181 3 lower right corner, Y position
182 4 upper right corner, X position
183 5 upper right corner, Y position
184 6 upper left corner, X position
185 7 upper left corner, Y position
186 */
187 minx=maxx=brect[0];
188 miny=maxy=brect[1];
189 for (i=2 ; i<7 ; i+=2) {
190 if (minx>brect[i]) minx=brect[i];
191 if (maxx<brect[i]) maxx=brect[i];
192 if (miny>brect[i+1]) miny=brect[i+1];
193 if (maxy<brect[i+1]) maxy=brect[i+1];
194 }
195 }
196
197 switch (RefPos)
198 {
199 case TRP_TopLeft:
200 y-=miny;
201 break;
202
203 case TRP_TopCenter:
204 x-=(maxx-minx)/2;
205 y-=miny;
206 break;
207
208 case TRP_TopRight:
209 x-=maxx;
210 y-=miny;
211 break;
212
213 case TRP_BottomLeft:
214 break;
215
216 case TRP_BottomCenter:
217 x-=(maxx-minx)/2;
218 break;
219
220 case TRP_BottomRight:
221 x-=maxx;
222 break;
223
224 case TRP_Center:
225 x-=(maxx-minx)/2;
226 y+=(maxy-miny)/2;
227 break;
228
229 case TRP_CenterLeft:
230 y+=(maxy-miny)/2;
231 break;
232
233 case TRP_CenterRight:
234 x-=maxx;
235 y+=(maxy-miny)/2;
236 break;
237 }
238 retval = gdImageStringFTEx (gdata->im, brect, fg, fontlist, ptsize, angle, x, y, sstring, gdFTEX_Unicode);
239 if (retval) {
240 debuga(_("libgd failed to render the text \"%s\": %s\n"),sstring,retval);
241 exit(EXIT_FAILURE);
242 }
25697a35 243}
25697a35 244
286f212b 245static void bar(struct GraphDataStruct *gdata,int x1,double y,const char *label)
1dd9dcec 246{
9bd92830
FM
247 gdPoint points[4];
248 int val=0;
249 int width2;
250
251 val=gdata->BottomGraph+5-(int)(y*gdata->YScale+0.5);
252 width2=(int)(gdata->XScale/4.);
253
254 // front side of the bar
255 if (val<gdata->BottomDepth)
256 gdImageFilledRectangle(gdata->im, x1-width2, val, x1+width2, gdata->BottomDepth, gdata->color3);
257
258 // top side of the bar
259 points[0].x = x1-width2+5;
260 points[0].y = val-5;
261 points[1].x = x1-width2;
262 points[1].y = val;
263 points[2].x = x1+width2;
264 points[2].y = val;
265 points[3].x = x1+width2+5;
266 points[3].y = val-5;
267 gdImageFilledPolygon(gdata->im, points, 4, gdata->color1);
268
269 gdImageLine(gdata->im, x1+2, val-2, x1+2, val-10, gdata->dimgray);
270 gdImageFilledRectangle(gdata->im, x1-8, val-20, x1+12, val-10, gdata->goldenrod);
271 gdImageRectangle(gdata->im, x1-8, val-20, x1+12, val-10, gdata->goldenrod2);
272
273 Sarg_gdImageStringFT(gdata,gdata->black,GraphFont,6,0.0,x1+2,val-12,label,TRP_BottomCenter);
274
275 // lateral side of the bar
276 if (val<gdata->BottomDepth) {
277 points[0].x = x1+width2+5;
278 points[0].y = val-5;
279 points[1].x = x1+width2;
280 points[1].y = val;
281 points[2].x = x1+width2;
282 points[2].y = gdata->BottomDepth;
283 points[3].x = x1+width2+5;
284 points[3].y = gdata->BottomGraph;
285 gdImageFilledPolygon(gdata->im, points, 4, gdata->color2);
286 }
287
288 return;
25697a35
GS
289}
290
286f212b
FM
291static int greport_compute_yaxis(struct PlotStruct *pdata,struct GraphDataStruct *gdata)
292{
9bd92830
FM
293 double symin,symax;
294 double range;
295 double yscale;
9bd92830
FM
296
297 if (pdata->ymin<0.) {
298 debuga(_("Minimum for Y scale of the graph is out of range: %"PRId64"\n"),(int64_t)pdata->ymin);
299 return(-1);
300 }
301 if (pdata->ymax<=0.) {
302 debuga(_("Maximum for Y scale of the graph is out of range: %"PRId64"\n"),(int64_t)pdata->ymax);
303 return(-1);
304 }
305
306 switch(pdata->ytype)
307 {
308 case PTG_LinBin:
309 symin=(double)pdata->ymin;
310 symax=(double)pdata->ymax;
9bd92830
FM
311 break;
312
313 case PTG_LogBin:
314 if (pdata->ymin>0.)
315 symin=log(pdata->ymin);
316 else
317 symin=0.;
318 symax=log(pdata->ymax);
9bd92830
FM
319 break;
320
321 case PTG_Time:
322 symin=(double)pdata->ymin;
323 symax=(double)pdata->ymax;
9bd92830
FM
324 break;
325
326 default:
327 debuga(_("Unknown type %d for Y axis scale\n"),pdata->ytype);
328 return(-1);
329 }
330 gdata->YTickSpace=10;
331
332 range=symax-symin;
333 yscale=(double)(gdata->BottomGraph-gdata->TopGraph)/range;
334 gdata->YScale=yscale;
335 return(0);
286f212b
FM
336}
337
1b81f396 338static void greport_formatbin(double yval,int maxdigits,char *string,int slen)
286f212b 339{
9bd92830
FM
340 int len;
341 char schar[]={'\0','k','M','G','T','P'};
342 int scount;
343 int i;
344 int ndigits;
345
346 for (scount=0 ; scount<sizeof(schar)/sizeof(*schar) && yval>=1000. ; scount++)
347 yval/=1000.;
348 if (yval<2.)
349 ndigits=2;
350 else if (yval<3.)
351 ndigits=1;
352 else
353 ndigits=0;
354 if (ndigits>maxdigits) ndigits=maxdigits;
355 len=snprintf(string,slen,"%.*f",ndigits,(float)yval);
356 if (UseComma)
357 for (i=0 ; i<len ; i++)
358 if (string[i]=='.') string[i]=',';
359 if (schar[scount] && len<slen) {
360 string[len++]=schar[scount];
361 string[len]='\0';
362 }
286f212b
FM
363}
364
365static void greport_draw_yaxis(struct PlotStruct *pdata,struct GraphDataStruct *gdata)
366{
9bd92830
FM
367 double yval;
368 int y0;
369 int y;
370 int yt;
371 char YLabel[50];
372 int xexterior;
373 int xinterior;
374 int xtick;
375
376 y0=gdata->BottomGraph;
377 yt=gdata->BottomDepth-gdata->BottomGraph;
378 xexterior=gdata->LeftGraph-10;
379 xinterior=gdata->LeftGraph;
380 xtick=gdata->LeftGraph-10-gdata->TickLength;
381 for(y=y0-gdata->YTickSpace ; y>=gdata->TopGraph ; y-=gdata->YTickSpace) {
382 gdImageLine(gdata->im, xtick, y+yt, xexterior, y+yt, gdata->dimgray);
383 gdImageLine(gdata->im, xexterior, y+yt, xinterior, y, gdata->dimgray);
384 gdImageLine(gdata->im, xinterior, y, gdata->RightGraph, y, gdata->dimgray);
385 switch (pdata->ytype)
386 {
387 case PTG_LinBin:
388 yval=(double)(y0-y)/gdata->YScale+(double)pdata->ymin;
389 greport_formatbin(yval,2,YLabel,sizeof(YLabel));
390 break;
391
392 case PTG_LogBin:
393 yval=exp((double)(y0-y)/gdata->YScale+log(pdata->ymin));
394 greport_formatbin(yval,2,YLabel,sizeof(YLabel));
395 break;
396
397 case PTG_Time:
398 {
399 int t;
400
401 yval=(double)(y0-y)/gdata->YScale+(double)pdata->ymin;
402 t=(int)(yval/60000.+0.5);
403 snprintf(YLabel,sizeof(YLabel),"%02d:%02d",t/60,t%60);
404 break;
405 }
406 }
407 Sarg_gdImageStringFT(gdata,gdata->dimgray,GraphFont,7,0.0,xtick,y+yt,YLabel,TRP_CenterRight);
408 }
286f212b
FM
409}
410
411static void greport_plot(const struct userinfostruct *uinfo,struct PlotStruct *pdata)
25697a35 412{
9bd92830
FM
413 FILE *pngout;
414 int x, y;
415 int day;
416 int x1;
417 char graph[MAXLEN];
418 char s[15];
419 char ftime[128];
420 time_t t;
421 struct tm *local;
422 gdPoint points[4];
423 struct GraphDataStruct gdata;
424 const int ImgXSize=720;
425 const int ImgYSize=480;
426 const int LeftMargin=60;
427 const int RightMargin=20;
428 const int TopMargin=60;
429 const int BottomMargin=60;
430 const int TickLength=3;
431 const int ZTickLength=5;
432 double yval;
433 char blabel[50];
434 double logpmin;
435
436 memset(&gdata,0,sizeof(gdata));
437
438 gdata.im = gdImageCreate(ImgXSize, ImgYSize);
439 gdata.BottomGraph=ImgYSize-BottomMargin;
440 gdata.LeftGraph=LeftMargin;
441 gdata.RightGraph=ImgXSize-RightMargin;
442 gdata.TopGraph=TopMargin;
443 gdata.BottomDepth=gdata.BottomGraph+5;
444 gdata.XScale=(double)(gdata.RightGraph-gdata.LeftGraph)/(pdata->npoints+1);
445 if (greport_compute_yaxis(pdata,&gdata)<0) return;
446 gdata.TickLength=TickLength;
447
448 // first allocated color is the background
449 gdata.lavender = gdImageColorAllocate(gdata.im, 230, 230, 250);
450 gdata.gray = gdImageColorAllocate(gdata.im, 192, 192, 192);
451 gdata.silver = gdImageColorAllocate(gdata.im, 211, 211, 211);
452 gdata.black = gdImageColorAllocate(gdata.im, 0, 0, 0);
453 gdata.dimgray = gdImageColorAllocate(gdata.im, 105, 105, 105);
454 gdata.darkblue = gdImageColorAllocate(gdata.im, 0, 0, 139);
455 gdata.goldenrod = gdImageColorAllocate(gdata.im, 234, 234, 174);
456 gdata.goldenrod2 = gdImageColorAllocate(gdata.im, 207, 181, 59);
457
458 if(strcmp(GraphDaysBytesBarColor,"orange") == 0) {
459 gdata.color1 = gdImageColorAllocate(gdata.im, 255, 233, 142);
460 gdata.color2 = gdImageColorAllocate(gdata.im, 220, 163, 72);
461 gdata.color3 = gdImageColorAllocate(gdata.im, 255, 198, 107);
462 }
463 else if(strcmp(GraphDaysBytesBarColor,"blue") == 0) {
464 gdata.color1 = gdImageColorAllocate(gdata.im, 62, 80, 167);
465 gdata.color2 = gdImageColorAllocate(gdata.im, 40, 51, 101);
466 gdata.color3 = gdImageColorAllocate(gdata.im, 57, 73, 150);
467 }
468 else if(strcmp(GraphDaysBytesBarColor,"green") == 0) {
469 gdata.color1 = gdImageColorAllocate(gdata.im,120,166,129);
470 gdata.color2 = gdImageColorAllocate(gdata.im,84,113,82);
471 gdata.color3 = gdImageColorAllocate(gdata.im,158,223,167);
472 }
473 else if(strcmp(GraphDaysBytesBarColor,"yellow") == 0) {
474 gdata.color1 = gdImageColorAllocate(gdata.im,185,185,10);
475 gdata.color2 = gdImageColorAllocate(gdata.im,111,111,10);
476 gdata.color3 = gdImageColorAllocate(gdata.im,166,166,10);
477 }
478 else if(strcmp(GraphDaysBytesBarColor,"brown") == 0) {
479 gdata.color1 = gdImageColorAllocate(gdata.im,97,45,27);
480 gdata.color2 = gdImageColorAllocate(gdata.im,60,30,20);
481 gdata.color3 = gdImageColorAllocate(gdata.im,88,41,26);
482 }
483 else if(strcmp(GraphDaysBytesBarColor,"red") == 0){
484 gdata.color1 = gdImageColorAllocate(gdata.im,185,10,10);
485 gdata.color2 = gdImageColorAllocate(gdata.im,111,10,10);
486 gdata.color3 = gdImageColorAllocate(gdata.im,166,10,10);
487 } else {
488 debuga(_("Unknown color \"%s\" requested for the graph. Using orange instead\n"),GraphDaysBytesBarColor);
489 gdata.color1 = gdImageColorAllocate(gdata.im, 255, 233, 142);
490 gdata.color2 = gdImageColorAllocate(gdata.im, 220, 163, 72);
491 gdata.color3 = gdImageColorAllocate(gdata.im, 255, 198, 107);
492 }
493
494 // rectangle around the image
495 gdImageRectangle(gdata.im, 0, 0, ImgXSize-1, ImgYSize-1, gdata.dimgray);
496 // backtround of the graph
497 gdImageFilledRectangle(gdata.im, LeftMargin, gdata.TopGraph, gdata.RightGraph, gdata.BottomGraph, gdata.silver);
498
499 // depth of the left Y axis
500 points[0].x = gdata.LeftGraph-10;
501 points[0].y = gdata.TopGraph+5;
502 points[1].x = gdata.LeftGraph-10;
503 points[1].y = gdata.BottomDepth;
504 points[2].x = gdata.LeftGraph;
505 points[2].y = gdata.BottomGraph;
506 points[3].x = gdata.LeftGraph;
507 points[3].y = gdata.TopGraph;
508 gdImageFilledPolygon(gdata.im, points, 4, gdata.gray);
509
510 // depth of the bottom X axis
511 points[0].x = gdata.LeftGraph;
512 points[0].y = gdata.BottomGraph;
513 points[1].x = gdata.LeftGraph-10;
514 points[1].y = gdata.BottomDepth;
515 points[2].x = gdata.RightGraph-10;
516 points[2].y = gdata.BottomDepth;
517 points[3].x = gdata.RightGraph;
518 points[3].y = gdata.BottomGraph;
519 gdImageFilledPolygon(gdata.im, points, 4, gdata.gray);
520
521 // vertical exterior line of the depth
522 gdImageLine(gdata.im, LeftMargin-10, TopMargin+5, LeftMargin-10, gdata.BottomDepth+ZTickLength, gdata.black);
523 // horizontal exterior line of the depth
524 gdImageLine(gdata.im, LeftMargin-10-ZTickLength, gdata.BottomDepth, gdata.RightGraph-10, gdata.BottomDepth, gdata.black);
525 // diagonal line between the two depths
526 gdImageLine(gdata.im, LeftMargin-10, gdata.BottomDepth, LeftMargin, gdata.BottomGraph, gdata.black);
527 // vertical left line of the graph
528 gdImageLine(gdata.im, LeftMargin, gdata.BottomGraph, LeftMargin, gdata.TopGraph, gdata.black);
529 // horizontal bottom line of the graph
530 gdImageLine(gdata.im, LeftMargin, gdata.BottomGraph, gdata.RightGraph, gdata.BottomGraph, gdata.black);
531 // vertical right line of the graph
532 gdImageLine(gdata.im, gdata.RightGraph, gdata.TopGraph, gdata.RightGraph, gdata.BottomGraph, gdata.black);
533 // diagonal line to close the right of the bottom depth
534 gdImageLine(gdata.im, gdata.RightGraph-10, gdata.BottomDepth, gdata.RightGraph, gdata.BottomGraph, gdata.black);
535
536 // Y axis ticks
537 greport_draw_yaxis(pdata,&gdata);
538
539 // X axis ticks and labels
540 for(y=1; y<=pdata->npoints; y++) {
541 x=gdata.LeftGraph-10+(int)((double)y*gdata.XScale+0.5);
542 gdImageLine(gdata.im, x, gdata.BottomDepth, x, gdata.BottomDepth+TickLength, gdata.dimgray);
543 sprintf(s,"%02d",y);
544 Sarg_gdImageStringFT(&gdata,gdata.dimgray,GraphFont,7,0.0,x,gdata.BottomDepth+TickLength+1,s,TRP_TopCenter);
545 }
546
547 t = time(NULL);
548 local = localtime(&t);
549 if(DateFormat[0]=='u')
550 strftime(ftime, sizeof(ftime), "%b/%d/%Y %H:%M", local);
551 if(DateFormat[0]=='e')
552 strftime(ftime, sizeof(ftime), "%d/%b/%Y-%H:%M", local);
553
554 x=ImgXSize*5/12;
555 Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,7,0.0,ImgXSize-10,ImgYSize-10,ftime,TRP_BottomRight);
556 if(ShowSargInfo) Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,10,0.0,x,15,_("SARG, "),TRP_BottomRight);
557 Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,10,0.0,x,15,Title,TRP_BottomLeft);
558 sprintf(warea,_("Period: %s"),period.text);
559 Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,9,0.0,x,27,warea,TRP_BottomLeft);
560 sprintf(warea,_("User: %s"),uinfo->label);
561 Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,9,0.0,x,38,warea,TRP_BottomLeft);
562
563 Sarg_gdImageStringFT(&gdata,gdata.black,GraphFont,10,3.141592/2,15,ImgYSize/2,pdata->YLabel,TRP_CenterLeft);
564 Sarg_gdImageStringFT(&gdata,gdata.black,GraphFont,10,0.0,ImgXSize/2,ImgYSize-20,pdata->XLabel,TRP_BottomCenter);
565
566 logpmin=(pdata->ytype==PTG_LogBin && pdata->ymin>0.) ? log(pdata->ymin) : 0.;
567 for (day=0 ; day<pdata->npoints ; day++) {
568 if (pdata->datapoints[day]>0) {
569 x1=gdata.LeftGraph-10+(int)((double)(day+1)*gdata.XScale+0.5);
570 switch (pdata->ytype)
571 {
572 case PTG_LinBin:
573 yval=(double)pdata->datapoints[day];
574 if (yval<pdata->ymin)
575 yval=0.;
576 else if (yval>pdata->ymax)
577 yval=pdata->ymax;
578 else
579 yval-=pdata->ymin;
580 greport_formatbin(pdata->datapoints[day],1,blabel,sizeof(blabel));
581 break;
582 case PTG_LogBin:
583 yval=(double)pdata->datapoints[day];
584 if (yval<=pdata->ymin)
585 yval=0.;
586 else if (yval>pdata->ymax)
587 yval=log(pdata->ymax)-logpmin;
588 else
589 yval=log(yval)-logpmin;
590 greport_formatbin(pdata->datapoints[day],1,blabel,sizeof(blabel));
591 break;
592 case PTG_Time:
593 {
594 int t;
595
596 yval=(double)pdata->datapoints[day];
597 if (yval<pdata->ymin)
598 yval=0.;
599 else if (yval>pdata->ymax)
600 yval=pdata->ymax;
601 else
602 yval-=pdata->ymin;
603 t=(int)(pdata->datapoints[day]/60000.);
604 snprintf(blabel,sizeof(blabel),"%d:%02d",t/60,t%60);
605 break;
606 }
607 default:
608 yval=-1.;
609 break;
610 }
611 if (yval>=0.) bar(&gdata,x1,yval,blabel);
612 }
613 }
614
615 if (snprintf(graph,sizeof(graph),"%s/%s/%s",outdirname,uinfo->filename,pdata->pngfile)>=sizeof(graph)) {
b0cf31a8
FM
616 /* TRANSLATORS: The message is followed by the path that is too long. */
617 debuga(_("User name too long to manufacture file name "));
618 debuga_more("%s/%s/%s\n",outdirname,uinfo->filename,pdata->pngfile);
9bd92830
FM
619 exit(EXIT_FAILURE);
620 }
621 if((pngout=fopen(graph,"wb"))==NULL) {
4b06d570 622 debugapos("grepday",_("Cannot open file \"%s\": %s\n"),graph,strerror(errno));
9bd92830
FM
623 exit(EXIT_FAILURE);
624 }
625 gdImagePng(gdata.im, pngout);
626 fclose(pngout);
627 gdImageDestroy(gdata.im);
628
629 if (gdata.string) free(gdata.string);
1f482a8d
FM
630}
631
632#endif //HAVE_GD
633
634void greport_prepare(void)
635{
636#ifdef HAVE_GD
8ddc656a 637 if (!Graphs) {
4b06d570
FM
638 if (debugz) {
639 /* TRANSLATORS: %s is the name of the configuration file providing
640 * the graph option.
641 */
642 debugaz(_("Graphs disabled as requested in \"%s\"\n"),ConfigFile);
643 }
8ddc656a
FM
644 return;
645 }
646 if (GraphFont[0]=='\0') {
4b06d570
FM
647 if (debugz) {
648 /* TRANSLATORS: %s is the name of the configuration file providing
649 * the graph option.
650 */
651 debugaz(_("Graphs disabled as no font names were provided in \"%s\"\n"),ConfigFile);
652 }
8ddc656a
FM
653 return;
654 }
655
9bd92830 656 if(access(GraphFont, R_OK) != 0) {
4b06d570 657 debugapos("grepday",_("Fontname \"%s\" not found\n"),GraphFont);
9bd92830
FM
658 exit(EXIT_FAILURE);
659 }
1f482a8d 660
e43854ef 661#ifdef USE_ICONV
9bd92830
FM
662 localtoutf = iconv_open ("UTF-8", CharSet);
663 if (localtoutf==(iconv_t)-1) {
4b06d570 664 debugapos("grepday",_("iconv cannot convert from %s to UTF-8: %s\n"),CharSet,strerror(errno));
9bd92830 665 }
e43854ef 666#endif
1dd9dcec 667
1f482a8d
FM
668#endif //HAVE_GD
669}
670
671void greport_day(const struct userinfostruct *uinfo)
672{
673#ifdef HAVE_GD
9bd92830
FM
674 FILE *fp_in, *fp_ou;
675 char wdirname[MAXLEN];
676 char buf[MAXLEN];
9bd92830
FM
677 int day;
678 long long int llday;
679 long long int bytes;
680 long long int elap;
681 long long int bytespoints[31];
682 long long int elappoints[31];
683 struct getwordstruct gwarea;
684 struct PlotStruct pdata;
685
686 if (snprintf(wdirname,sizeof(wdirname),"%s/%s.day",tmp,uinfo->filename)>=sizeof(wdirname)) {
b0cf31a8
FM
687 debuga(_("User name too long to manufacture file name "));
688 debuga_more("%s/%s.day\n",tmp,uinfo->filename);
9bd92830
FM
689 exit(EXIT_FAILURE);
690 }
691 if(access(wdirname, R_OK) != 0) {
692 return;
693 }
694 if(!Graphs || GraphFont[0]=='\0') {
11767c6a
FM
695 if (!KeepTempLog && unlink(wdirname))
696 debuga(_("Cannot delete \"%s\": %s\n"),wdirname,strerror(errno));
9bd92830
FM
697 return;
698 }
699
700 if((fp_in=fopen(wdirname,"r"))==NULL) {
4b06d570 701 debugapos("grepday",_("Cannot open file \"%s\": %s\n"),wdirname,strerror(errno));
9bd92830
FM
702 exit(EXIT_FAILURE);
703 }
704
705 memset(bytespoints,0,sizeof(bytespoints));
706 memset(elappoints,0,sizeof(elappoints));
707 while(fgets(buf,sizeof(buf),fp_in)!=NULL) {
708 fixendofline(buf);
709 getword_start(&gwarea,buf);
710 if (getword_atoll(&llday,&gwarea,'/')<0) {
b2dad7e7 711 debuga(_("Invalid date in file \"%s\"\n"),wdirname);
9bd92830
FM
712 exit(EXIT_FAILURE);
713 }
714 day=(int)llday;
715 if (day<1 || day>31) continue;
716 if (getword_skip(20,&gwarea,'\t')<0 || getword_skip(20,&gwarea,'\t')<0) {
b2dad7e7 717 debuga(_("Invalid entry in file \"%s\"\n"),wdirname);
9bd92830
FM
718 exit(EXIT_FAILURE);
719 }
720 if ((datetimeby & DATETIME_BYTE)!=0) {
9bd92830 721 if (getword_atoll(&bytes,&gwarea,'\t')<0) {
b2dad7e7 722 debuga(_("Invalid number of bytes in file \"%s\"\n"),wdirname);
9bd92830
FM
723 exit(EXIT_FAILURE);
724 }
725 bytespoints[day-1]+=bytes;
726 }
727 if ((datetimeby & DATETIME_ELAP)!=0) {
728 if (getword_atoll(&elap,&gwarea,'\0')<0) {
b2dad7e7 729 debuga(_("Invalid elapsed time in file \"%s\"\n"),wdirname);
9bd92830
FM
730 exit(EXIT_FAILURE);
731 }
732 elappoints[day-1]+=elap;
733 }
734 }
735 fclose(fp_in);
11767c6a
FM
736 if (!KeepTempLog && unlink(wdirname)) {
737 debuga(_("Cannot delete \"%s\": %s\n"),wdirname,strerror(errno));
08f9b029
FM
738 exit(EXIT_FAILURE);
739 }
9bd92830
FM
740
741 if (snprintf(wdirname,sizeof(wdirname),"%s/%s/graph.html",outdirname,uinfo->filename)>=sizeof(wdirname)) {
b0cf31a8
FM
742 debuga(_("User name too long to manufacture file name "));
743 debuga_more("%s/%s/%s\n",outdirname,uinfo->filename,"graph.html");
9bd92830
FM
744 exit(EXIT_FAILURE);
745 }
746 if ((fp_ou=fopen(wdirname,"wt"))==NULL) {
4b06d570 747 debugapos("grepday",_("Cannot open file \"%s\": %s\n"),wdirname,strerror(errno));
007905af 748 exit(EXIT_FAILURE);
9bd92830
FM
749 }
750 write_html_head(fp_ou,(IndexTree == INDEX_TREE_DATE) ? 4 : 2,_("Graph report"),HTML_JS_NONE);
751
752 fputs("<table class=\"report\" cellpadding=\"0\" cellspacing=\"2\">\n", fp_ou);
753 if((datetimeby & DATETIME_BYTE)!=0) {
754 memset(&pdata,0,sizeof(pdata));
755 pdata.datapoints=bytespoints;
756 pdata.npoints=31;
757 pdata.XLabel=_("DAYS");
758 pdata.ymin=50LL*1000LL;
759 pdata.ymax=5LL*1000LL*1000LL*1000LL;
760 pdata.ytype=PTG_LogBin;
761 pdata.YLabel=_("BYTES");
762 pdata.pngfile="graph_day_byte.png";
763 greport_plot(uinfo,&pdata);
764 fprintf(fp_ou,"<tr><td><img src=\"%s\" alt=\"B\"></td></tr>\n",pdata.pngfile);
765 }
766 if((datetimeby & DATETIME_ELAP)!=0) {
767 memset(&pdata,0,sizeof(pdata));
768 pdata.datapoints=elappoints;
769 pdata.npoints=31;
770 pdata.XLabel=_("DAYS");
771 pdata.ymin=0;
772 pdata.ymax=86400000;
773 pdata.ytype=PTG_Time;
774 pdata.YLabel=_("ELAPSED TIME");
775 pdata.pngfile="graph_day_elap.png";
776 greport_plot(uinfo,&pdata);
777 fprintf(fp_ou,"<tr><td><img src=\"%s\" alt=\"E\"></td></tr>\n",pdata.pngfile);
778 }
779 fputs("</table>\n",fp_ou);
780
781 if (write_html_trailer(fp_ou)<0)
b2dad7e7 782 debuga(_("Write error in file \"%s\"\n"),wdirname);
9bd92830 783 if (fclose(fp_ou)==EOF)
4b06d570 784 debuga(_("Failed to close file \"%s\": %s\n"),wdirname,strerror(errno));
a1de61fe 785#endif //HAVE_GD
d6e703cc 786
9bd92830 787 return;
25697a35 788}
c274f011
FM
789
790void greport_cleanup(void)
791{
792#ifdef HAVE_GD
9bd92830 793 gdFontCacheShutdown();
1f482a8d
FM
794
795#ifdef USE_ICONV
9bd92830
FM
796 if (localtoutf!=(iconv_t)-1)
797 iconv_close (localtoutf);
c274f011 798#endif
1f482a8d 799#endif //HAVE_GD
c274f011 800}