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