vnstat  2.9
About: vnStat is a console-based network traffic monitor (using the /proc filesystem).
  Fossies Dox: vnstat-2.9.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

image.c
Go to the documentation of this file.
1#include "common.h"
2#include "dbsql.h"
3#include "misc.h"
4#include "image.h"
5#include "image_support.h"
6#include "vnstati.h"
7
9{
10 ic->im = NULL;
11 ic->font = gdFontGetSmall();
12 ic->lineheight = 12;
13 ic->large = 0;
14 ic->showheader = 1;
15 ic->showedge = 1;
16 ic->showlegend = 1;
17 ic->altdate = 0;
18 ic->headertext[0] = '\0';
19 ic->databegin[0] = '\0';
20 ic->dataend[0] = '\0';
21 ic->interface.name[0] = '\0';
22 ic->interface.alias[0] = '\0';
23}
24
26{
27 switch (cfg.qmode) {
28 case 1:
29 drawlist(ic, "day");
30 break;
31 case 2:
32 drawlist(ic, "month");
33 break;
34 case 3:
35 drawlist(ic, "top");
36 break;
37 case 4:
38 drawlist(ic, "year");
39 break;
40 case 5:
41 drawsummary(ic, 0, 0);
42 break;
43 case 51:
44 drawsummary(ic, 1, cfg.hourlyrate); // horizontal
45 break;
46 case 52:
47 drawsummary(ic, 2, cfg.hourlyrate); // vertical
48 break;
49 case 7:
51 break;
52 case 8:
53 drawlist(ic, "hour");
54 break;
55 case 9:
56 drawlist(ic, "fiveminute");
57 break;
58 case 10:
60 break;
61 default:
62 printf("Error: No such query mode: %d\n", cfg.qmode);
63 exit(EXIT_FAILURE);
64 }
65
66 /* enable background transparency if needed */
67 if (cfg.transbg) {
68 gdImageColorTransparent(ic->im, ic->cbackground);
69 }
70}
71
72#if HAVE_DECL_GD_NEAREST_NEIGHBOUR
73void scaleimage(IMAGECONTENT *ic)
74{
75 gdImagePtr im_scaled;
76 unsigned int width = 0, height = 0;
77
78 if (cfg.imagescale == 100 || ic->im == NULL) {
79 return;
80 }
81
82 width = (unsigned int)((float)gdImageSX(ic->im) * ((float)cfg.imagescale / (float)100));
83 height = (unsigned int)((float)gdImageSY(ic->im) * ((float)cfg.imagescale / (float)100));
84
85 if (width < 100 || height < 100) {
86 return;
87 }
88
89 if (width > 5000 || height > 5000) {
90 return;
91 }
92
93 /* keep output sharp when percent is an exact multiplier */
94 if (cfg.imagescale % 100 == 0) {
95 gdImageSetInterpolationMethod(ic->im, GD_NEAREST_NEIGHBOUR);
96 }
97
98 im_scaled = gdImageScale(ic->im, width, height);
99 if (im_scaled == NULL) {
100 return;
101 }
102
103 gdImageDestroy(ic->im);
104 ic->im = im_scaled;
105}
106#endif
107
108int drawhours(IMAGECONTENT *ic, const int xpos, const int ypos, const int rate)
109{
110 int i, tmax = 0, s = 0, step, prev = 0, diff = 0, chour;
111 int x = xpos, y = ypos, extrax = 0, extray = 0, xt = 0;
112 double ratediv;
113 uint64_t max = 1, scaleunit = 0;
114 char buffer[32];
115 struct tm *d;
116 dbdatalist *datalist = NULL, *datalist_i = NULL;
117 dbdatalistinfo datainfo;
118 HOURDATA hourdata[24];
119 gdFontPtr font;
120
121 if (ic->large) {
122 font = gdFontGetSmall();
123 } else {
124 font = gdFontGetTiny();
125 }
126
127 for (i = 0; i < 24; i++) {
128 hourdata[i].rx = hourdata[i].tx = 0;
129 hourdata[i].date = 0;
130 }
131
132 if (cfg.hourlygmode == 0) {
133 buffer[0] = '\0';
134 } else {
135 snprintf(buffer, 32, "today");
136 }
137
138 if (!db_getdata_range(&datalist, &datainfo, ic->interface.name, "hour", 24, buffer, "") || datainfo.count == 0) {
139 gdImageString(ic->im, ic->font, x + (32 * ic->font->w), y + 54, (unsigned char *)"no data available", ic->ctext);
140 return 0;
141 }
142
143 datalist_i = datalist;
144
145 while (datalist_i != NULL) {
146 d = localtime(&datalist_i->timestamp);
147 if (hourdata[d->tm_hour].date != 0 || ic->interface.updated - datalist_i->timestamp > 86400) {
148 datalist_i = datalist_i->next;
149 continue;
150 }
151 hourdata[d->tm_hour].rx = datalist_i->rx;
152 hourdata[d->tm_hour].tx = datalist_i->tx;
153 hourdata[d->tm_hour].date = datalist_i->timestamp;
154 datalist_i = datalist_i->next;
155 }
156 dbdatalistfree(&datalist);
157
158 ic->current = ic->interface.updated;
159 chour = localtime(&ic->current)->tm_hour;
160
161 if (cfg.rateunit) {
162 ratediv = 450; /* x * 8 / 3600 */
163 } else {
164 ratediv = 3600;
165 }
166
167 /* tmax (time max) = current hour */
168 /* max = transfer max */
169
170 for (i = 0; i < 24; i++) {
171 /* convert hourly transfer to hourly rate if needed */
172 if (rate) {
173 if ((ic->current - hourdata[i].date) > 3600) {
174 hourdata[i].rx = (uint64_t)((double)hourdata[i].rx / ratediv);
175 hourdata[i].tx = (uint64_t)((double)hourdata[i].tx / ratediv);
176 } else {
177 /* scale ongoing hour properly */
178 if (chour != i) {
179 hourdata[i].rx = (uint64_t)((double)hourdata[i].rx / ratediv);
180 hourdata[i].tx = (uint64_t)((double)hourdata[i].tx / ratediv);
181 } else {
182 d = localtime(&ic->current);
183 diff = d->tm_min * 60;
184 if (!diff) {
185 diff = 60;
186 }
187 if (cfg.rateunit == 1) {
188 hourdata[i].rx *= 8;
189 hourdata[i].tx *= 8;
190 }
191 hourdata[i].rx = (uint64_t)((double)hourdata[i].rx / (double)diff);
192 hourdata[i].tx = (uint64_t)((double)hourdata[i].tx / (double)diff);
193 }
194 }
195 }
196
197 if (hourdata[i].date >= hourdata[tmax].date) {
198 tmax = i;
199 }
200 if (hourdata[i].rx >= max) {
201 max = hourdata[i].rx;
202 }
203 if (hourdata[i].tx >= max) {
204 max = hourdata[i].tx;
205 }
206 }
207
208 if (ic->large) {
209 x += 14;
210 extrax = 145;
211 extray = 35;
212 }
213
214 /* scale values */
215 scaleunit = getscale(max, rate);
216
217 s = (int)lrint(((double)scaleunit / (double)max) * (124 + extray));
218 if (s < SCALEMINPIXELS) {
219 step = 2;
220 } else {
221 step = 1;
222 }
223
224 xt = x + 36;
225
226 for (i = step; i * s <= (124 + extray + 4); i = i + step) {
227 gdImageDashedLine(ic->im, xt, y + 124 - (i * s), xt + 424 + extrax, y + 124 - (i * s), ic->cline);
228 gdImageDashedLine(ic->im, xt, y + 124 - prev - (step * s) / 2, xt + 424 + extrax, y + 124 - prev - (step * s) / 2, ic->clinel);
229 gdImageString(ic->im, font, x + 16 - (ic->large * 3), y + 121 - (i * s) - (ic->large * 3), (unsigned char *)getimagevalue(scaleunit * (unsigned int)i, 3, rate), ic->ctext);
230 prev = i * s;
231 }
232 if ((prev + (step * s) / 2) <= (124 + extray + 4)) {
233 gdImageDashedLine(ic->im, xt, y + 124 - prev - (step * s) / 2, xt + 424 + extrax, y + 124 - prev - (step * s) / 2, ic->clinel);
234 }
235
236 /* scale text */
237 gdImageStringUp(ic->im, font, x - 2 - (ic->large * 14), y + 58 + (rate * 10) - (extray / 2), (unsigned char *)getimagescale(scaleunit * (unsigned int)step, rate), ic->ctext);
238
239 /* axis */
240 gdImageLine(ic->im, xt - 4, y + 124, xt + 430 + extrax, y + 124, ic->ctext);
241 gdImageLine(ic->im, xt, y - 10 - extray, xt, y + 124 + 4, ic->ctext);
242
243 /* arrows */
244 drawarrowup(ic, xt, y - 9 - extray);
245 drawarrowright(ic, xt + 429 + extrax, y + 124);
246
247 xt = x + 440 + extrax;
248
249 /* keep alignment when midnight line isn't shown s*/
250 if (cfg.hourlygmode || tmax - 23 == 0) {
251 xt--;
252 }
253
254 /* x-axis values and poles */
255 for (i = 0; i < 24; i++) {
256 if (cfg.hourlygmode == 0) {
257 s = tmax - i;
258 if (s < 0) {
259 s += 24;
260 }
261 } else {
262 s = 23 - i;
263 }
264 snprintf(buffer, 32, "%02d ", s);
265 if (hourdata[s].date == 0) {
266 chour = ic->cline;
267 } else {
268 chour = ic->ctext;
269 }
270 gdImageString(ic->im, font, xt, y + 128, (unsigned char *)buffer, chour);
271 drawpoles(ic, xt - 2, y - extray, 124 + extray, hourdata[s].rx, hourdata[s].tx, max);
272 gdImageLine(ic->im, xt - 4 - (ic->large * 3), y + 124, xt + 12 + (ic->large * 3), y + 124, chour);
273 if (s == 0 && i != 23) {
274 /* midnight line */
275 gdImageLine(ic->im, xt - 5 - (ic->large * 3), y - 5 - extray, xt - 5 - (ic->large * 3), y + 124 - 1, ic->clinel);
276 xt--;
277 }
278 xt = xt - (17 + ic->large * 6);
279 }
280
281 return 1;
282}
283
284void drawhourly(IMAGECONTENT *ic, const int rate)
285{
286 int width, height, headermod = 0;
287
288 width = 500 + (ic->large * 168);
289 height = 200 + (ic->large * 48);
290
291 if (!ic->showheader) {
292 headermod = 26;
293 height -= 22;
294 }
295
296 imageinit(ic, width, height);
297 layoutinit(ic, " / hourly", width, height);
298
299 if (drawhours(ic, 12, 46 - headermod + (ic->large * 40), rate)) {
300 drawlegend(ic, width / 2 - (ic->large * 10), 183 - headermod + (ic->large * 46), 0);
301 }
302}
303
304void drawlist(IMAGECONTENT *ic, const char *listname)
305{
306 ListType listtype = LT_None;
307 int textx, texty, offsetx = 0;
308 int width, height, headermod, i = 1, rowcount = 0;
309 int estimateavailable = 0, estimatevisible = 0;
310 int32_t limit;
311 uint64_t e_rx = 0, e_tx = 0, e_secs = 0;
312 char buffer[512], datebuff[16], daybuff[16];
313 char stampformat[64], titlename[16], colname[8];
314 struct tm *d;
315 time_t current;
316 dbdatalist *datalist = NULL, *datalist_i = NULL;
317 dbdatalistinfo datainfo;
318
319 if (strcmp(listname, "day") == 0) {
320 listtype = LT_Day;
321 strncpy_nt(colname, listname, 8);
322 snprintf(titlename, 16, "daily");
323 strncpy_nt(stampformat, cfg.dformat, 64);
324 limit = cfg.listdays;
325 } else if (strcmp(listname, "month") == 0) {
326 listtype = LT_Month;
327 strncpy_nt(colname, listname, 8);
328 snprintf(titlename, 16, "monthly");
329 strncpy_nt(stampformat, cfg.mformat, 64);
330 limit = cfg.listmonths;
331 } else if (strcmp(listname, "year") == 0) {
332 listtype = LT_Year;
333 strncpy_nt(colname, listname, 8);
334 snprintf(titlename, 16, "yearly");
335 strncpy_nt(stampformat, "%Y", 64);
336 limit = cfg.listyears;
337 } else if (strcmp(listname, "top") == 0) {
338 listtype = LT_Top;
339 snprintf(colname, 8, "day");
340 strncpy_nt(stampformat, cfg.tformat, 64);
341 limit = cfg.listtop;
342 offsetx = 5 * ic->font->w;
343 } else if (strcmp(listname, "hour") == 0) {
344 listtype = LT_Hour;
345 strncpy_nt(colname, listname, 8);
346 snprintf(titlename, 16, "hourly");
347 strncpy_nt(stampformat, "%H:%M", 64);
348 limit = cfg.listhours;
349 } else if (strcmp(listname, "fiveminute") == 0) {
350 listtype = LT_5min;
351 strncpy_nt(colname, "time", 8);
352 snprintf(titlename, 16, "5 minute");
353 strncpy_nt(stampformat, "%H:%M", 64);
354 limit = cfg.listfivemins;
355 } else {
356 return;
357 }
358
359 if (limit < 0) {
360 limit = 0;
361 }
362
363 daybuff[0] = '\0';
364
365 db_getdata_range(&datalist, &datainfo, ic->interface.name, listname, (uint32_t)limit, ic->databegin, ic->dataend);
366
367 datalist_i = datalist;
368
369 if (strlen(ic->dataend) == 0 && datainfo.count > 0 && listtype != LT_Top) {
370 getestimates(&e_rx, &e_tx, listtype, ic->interface.updated, &datalist);
371 if ((cfg.estimatestyle > 0 || cfg.barshowsrate > 0) && e_rx + e_tx > datainfo.max) {
372 datainfo.max = e_rx + e_tx;
373 }
374 estimateavailable = 1;
375 if (listtype == LT_Day || listtype == LT_Month || listtype == LT_Year) {
376 estimatevisible = 1;
377 }
378 }
379
380 if (listtype == LT_Top) {
381 if (limit > 0 && datainfo.count < (uint32_t)limit) {
382 limit = (int32_t)datainfo.count;
383 }
384 if (limit <= 0 || datainfo.count > 999) {
385 snprintf(titlename, 16, "top");
386 } else {
387 snprintf(titlename, 16, "top %d", limit);
388 }
389 }
390
391 if (listtype == LT_Hour || listtype == LT_5min) {
392 while (datalist_i != NULL) {
393 d = localtime(&datalist_i->timestamp);
394 strftime(datebuff, 16, cfg.dformat, d);
395 if (strcmp(daybuff, datebuff) != 0) {
396 rowcount += 1;
397 strcpy(daybuff, datebuff);
398 }
399 datalist_i = datalist_i->next;
400 }
401 datalist_i = datalist;
402 daybuff[0] = '\0';
403 }
404 rowcount += datainfo.count;
405
406 width = 83 * ic->font->w + 2 + (ic->large * 2);
407 height = 62 + 3 * ic->lineheight;
408
409 // less space needed when no estimate or sum is shown (Top, 5min and Hour never have estimate)
410 if ((!estimatevisible && datainfo.count < 2) || (listtype == LT_Top || listtype == LT_Hour || listtype == LT_5min)) {
411 height = 62 + 2 * ic->lineheight;
412 }
413
414 // exception for 5min and Hour when having sum shown
415 if ((listtype == LT_5min || listtype == LT_Hour) && datainfo.count > 1 && strlen(ic->dataend) > 0) {
416 height = 62 + 3 * ic->lineheight;
417 }
418
419 height += (ic->lineheight + cfg.linespaceadjust) * rowcount - cfg.linespaceadjust;
420
421 // "no data available"
422 if (!datainfo.count) {
423 height = 98 + (ic->large * 12);
424 }
425
426 if (!ic->showheader) {
427 headermod = 26;
428 height -= 22;
429 } else {
430 headermod = 0;
431 }
432
433 snprintf(buffer, 512, " / %s", titlename);
434
435 imageinit(ic, width, height);
436 layoutinit(ic, buffer, width, height);
437
438 if (datainfo.count) {
439 if (listtype == LT_Top) {
440 if (cfg.ostyle <= 2) {
441 drawlegend(ic, 66 * ic->font->w + 2, 40 - headermod, 0);
442 }
443 current = time(NULL);
444 d = localtime(&current);
445 strftime(daybuff, 16, stampformat, d);
446 } else { // everything else
447 if (cfg.ostyle > 2) {
448 if (estimateavailable && cfg.barshowsrate) {
449 drawlegend(ic, 72 * ic->font->w, 40 - headermod, 1);
450 } else {
451 drawlegend(ic, 72 * ic->font->w, 40 - headermod, 0);
452 }
453 } else {
454 drawlegend(ic, 64 * ic->font->w + 1, 40 - headermod, 0);
455 }
456 }
457 }
458
459 textx = 10;
460 texty = 40 - headermod;
461
462 if (listtype == LT_Top) { // top
463 snprintf(buffer, 512, " # day rx tx total");
464 } else { // everything else
465 snprintf(buffer, 512, " %8s rx tx total", colname);
466 }
467 if (cfg.ostyle > 2) {
468 strcat(buffer, " avg. rate");
469 gdImageString(ic->im, ic->font, textx, texty, (unsigned char *)buffer, ic->ctext);
470 gdImageLine(ic->im, textx + 2, texty + ic->lineheight + 4, textx + (65 * ic->font->w) + offsetx + 2, texty + ic->lineheight + 4, ic->cline);
471 } else {
472 gdImageString(ic->im, ic->font, textx, texty, (unsigned char *)buffer, ic->ctext);
473 gdImageLine(ic->im, textx + 2, texty + ic->lineheight + 4, textx + (50 * ic->font->w) + offsetx - 4, texty + ic->lineheight + 4, ic->cline);
474 }
475
476 texty += ic->lineheight + 8;
477
478 if (datainfo.count) {
479 gdImageLine(ic->im, textx + (24 * ic->font->w) + offsetx, texty - 6 - ic->lineheight, textx + (24 * ic->font->w) + offsetx, texty + ((ic->lineheight + cfg.linespaceadjust) * rowcount) - cfg.linespaceadjust + 5 - (ic->large * 2), ic->cline);
480 gdImageLine(ic->im, textx + (37 * ic->font->w) + offsetx, texty - 6 - ic->lineheight, textx + (37 * ic->font->w) + offsetx, texty + ((ic->lineheight + cfg.linespaceadjust) * rowcount) - cfg.linespaceadjust + 5 - (ic->large * 2), ic->cline);
481 if (cfg.ostyle > 2) {
482 gdImageLine(ic->im, textx + (50 * ic->font->w) + offsetx, texty - 6 - ic->lineheight, textx + (50 * ic->font->w) + offsetx, texty + ((ic->lineheight + cfg.linespaceadjust) * rowcount) - cfg.linespaceadjust + 5 - (ic->large * 2), ic->cline);
483 }
484 } else {
485 gdImageLine(ic->im, textx + (24 * ic->font->w) + offsetx, texty - 6 - ic->lineheight, textx + (24 * ic->font->w) + offsetx, texty - 4, ic->cline);
486 gdImageLine(ic->im, textx + (37 * ic->font->w) + offsetx, texty - 6 - ic->lineheight, textx + (37 * ic->font->w) + offsetx, texty - 4, ic->cline);
487 if (cfg.ostyle > 2) {
488 gdImageLine(ic->im, textx + (50 * ic->font->w) + offsetx, texty - 6 - ic->lineheight, textx + (50 * ic->font->w) + offsetx, texty - 4, ic->cline);
489 }
490 }
491
492 while (datalist_i != NULL) {
493 d = localtime(&datalist_i->timestamp);
494
495 if (listtype == LT_5min || listtype == LT_Hour) {
496 strftime(datebuff, 16, cfg.dformat, d);
497 if (strcmp(daybuff, datebuff) != 0) {
498 snprintf(buffer, 32, " %s", datebuff);
499 gdImageString(ic->im, ic->font, textx, texty, (unsigned char *)buffer, ic->ctext);
500 texty += ic->lineheight + cfg.linespaceadjust;
501 strcpy(daybuff, datebuff);
502 }
503 }
504
505 if (listtype == LT_Top) {
506 if (strftime(datebuff, 16, stampformat, d) <= 8) {
507 snprintf(buffer, 32, " %2d %*s", i, getpadding(8, datebuff), datebuff);
508 strcat(buffer, " ");
509 } else {
510 snprintf(buffer, 32, " %2d %-*s ", i, getpadding(11, datebuff), datebuff);
511 }
512 if (strcmp(datebuff, daybuff) == 0) {
513 if (cfg.ostyle > 2) {
514 gdImageFilledRectangle(ic->im, textx + 2, texty + 2 - (ic->large * 1), textx + (65 * ic->font->w) + offsetx + 2, texty + 11 + (ic->large * 3), ic->cbgoffset);
515 } else {
516 gdImageFilledRectangle(ic->im, textx + 2, texty + 2 - (ic->large * 1), textx + (50 * ic->font->w) + offsetx - 4, texty + 11 + (ic->large * 3), ic->cbgoffset);
517 }
518 }
519 } else {
520 if (strftime(datebuff, 16, stampformat, d) <= 8) {
521 snprintf(buffer, 32, " %*s", getpadding(8, datebuff), datebuff);
522 strcat(buffer, " ");
523 } else {
524 snprintf(buffer, 32, " %-*s ", getpadding(11, datebuff), datebuff);
525 }
526 }
527 strncat(buffer, getvalue(datalist_i->rx, 10, RT_Normal), 32);
528 strcat(buffer, " ");
529 strncat(buffer, getvalue(datalist_i->tx, 10, RT_Normal), 32);
530 strcat(buffer, " ");
531 strncat(buffer, getvalue(datalist_i->rx + datalist_i->tx, 10, RT_Normal), 32);
532 if (cfg.ostyle > 2) {
533 strcat(buffer, " ");
534 if (datalist_i->next == NULL && issametimeslot(listtype, datalist_i->timestamp, ic->interface.updated)) {
535 e_secs = getperiodseconds(listtype, datalist_i->timestamp, ic->interface.updated, 1);
536 } else {
537 e_secs = getperiodseconds(listtype, datalist_i->timestamp, ic->interface.updated, 0);
538 }
539 strncat(buffer, gettrafficrate(datalist_i->rx + datalist_i->tx, (time_t)e_secs, 14), 32);
540 }
541 gdImageString(ic->im, ic->font, textx, texty, (unsigned char *)buffer, ic->ctext);
542 if (listtype == LT_Top) {
543 if (cfg.ostyle > 2) {
544 drawbar(ic, textx + (71 * ic->font->w) + 2, texty + 4, 9 * ic->font->w - 1, datalist_i->rx, datalist_i->tx, datainfo.max, 0);
545 } else {
546 drawbar(ic, textx + (56 * ic->font->w), texty + 4, 23 * ic->font->w + 3, datalist_i->rx, datalist_i->tx, datainfo.max, 0);
547 }
548 } else { // everything else
549 if (cfg.ostyle > 2) {
550 if (datalist_i->next == NULL && estimateavailable && cfg.barshowsrate) {
551 drawbar(ic, textx + (67 * ic->font->w) - 2, texty + 4, 13 * ic->font->w + 1, e_rx, e_tx, datainfo.max, 0);
552 } else {
553 drawbar(ic, textx + (67 * ic->font->w) - 2, texty + 4, 13 * ic->font->w + 1, datalist_i->rx, datalist_i->tx, datainfo.max, 0);
554 }
555 } else {
556 drawbar(ic, textx + (51 * ic->font->w) - 2, texty + 4, 28 * ic->font->w + 3, datalist_i->rx, datalist_i->tx, datainfo.max, 0);
557 }
558 }
559 texty += ic->lineheight + cfg.linespaceadjust;
560 if (datalist_i->next == NULL) {
561 texty -= cfg.linespaceadjust;
562 break;
563 }
564 datalist_i = datalist_i->next;
565 i++;
566 }
567
568 if (!datainfo.count) {
569 i = 17 * ic->font->w;
570 if (cfg.ostyle > 2) {
571 i += 8 * ic->font->w;
572 }
573 gdImageString(ic->im, ic->font, textx + i, texty, (unsigned char *)"no data available", ic->ctext);
574 texty += ic->lineheight;
575 }
576
577 if (cfg.ostyle > 2) {
578 gdImageLine(ic->im, textx + 2, texty + 5 - (ic->large * 2), textx + (65 * ic->font->w) + offsetx + 2, texty + 5 - (ic->large * 2), ic->cline);
579 } else {
580 gdImageLine(ic->im, textx + 2, texty + 5 - (ic->large * 2), textx + (50 * ic->font->w) + offsetx - 4, texty + 5 - (ic->large * 2), ic->cline);
581 }
582
583 buffer[0] = '\0';
584
585 /* estimate visible */
586 if (estimatevisible) {
587 snprintf(buffer, 32, " estimated ");
588 strncat(buffer, getvalue(e_rx, 10, RT_Estimate), 32);
589 strcat(buffer, " ");
590 strncat(buffer, getvalue(e_tx, 10, RT_Estimate), 32);
591 strcat(buffer, " ");
592 strncat(buffer, getvalue(e_rx + e_tx, 10, RT_Estimate), 32);
593
594 if (cfg.estimatestyle) {
595 if (cfg.ostyle > 2) {
596 drawbar(ic, textx + (67 * ic->font->w) - 2, texty - ic->lineheight + 4, 13 * ic->font->w + 1, e_rx, e_tx, datainfo.max, 1);
597 drawbar(ic, textx + (67 * ic->font->w) - 2, texty - ic->lineheight + 4, 13 * ic->font->w + 1, datalist_i->rx, datalist_i->tx, datainfo.max, 0);
598 } else {
599 drawbar(ic, textx + (51 * ic->font->w) - 2, texty - ic->lineheight + 4, 28 * ic->font->w + 3, e_rx, e_tx, datainfo.max, 1);
600 drawbar(ic, textx + (51 * ic->font->w) - 2, texty - ic->lineheight + 4, 28 * ic->font->w + 3, datalist_i->rx, datalist_i->tx, datainfo.max, 0);
601 }
602 }
603
604 /* sum visible */
605 } else if (strlen(ic->dataend) > 0 && datainfo.count > 1 && listtype != LT_Top) {
606 if (datainfo.count < 100) {
607 snprintf(datebuff, 16, "sum of %" PRIu32 "", datainfo.count);
608 } else {
609 snprintf(datebuff, 16, "sum");
610 }
611 snprintf(buffer, 32, " %9s ", datebuff);
612 strncat(buffer, getvalue(datainfo.sumrx, 10, RT_Normal), 32);
613 strcat(buffer, " ");
614 strncat(buffer, getvalue(datainfo.sumtx, 10, RT_Normal), 32);
615 strcat(buffer, " ");
616 strncat(buffer, getvalue(datainfo.sumrx + datainfo.sumtx, 10, RT_Normal), 32);
617 }
618
619 if (strlen(buffer) > 0) {
620 texty += 8;
621 gdImageString(ic->im, ic->font, textx, texty, (unsigned char *)buffer, ic->ctext);
622
623 gdImageLine(ic->im, textx + (24 * ic->font->w) + offsetx, texty - 6, textx + (24 * ic->font->w) + offsetx, texty + ic->lineheight - (ic->large * 2), ic->cline);
624 gdImageLine(ic->im, textx + (37 * ic->font->w) + offsetx, texty - 6, textx + (37 * ic->font->w) + offsetx, texty + ic->lineheight - (ic->large * 2), ic->cline);
625 if (cfg.ostyle > 2) {
626 gdImageLine(ic->im, textx + (50 * ic->font->w) + offsetx, texty - 6, textx + (50 * ic->font->w) + offsetx, texty + ic->lineheight - (ic->large * 2), ic->cline);
627 }
628 }
629
630 dbdatalistfree(&datalist);
631}
632
633void drawsummary(IMAGECONTENT *ic, const int layout, const int rate)
634{
635 int width, height, headermod;
636
637 switch (layout) {
638 // horizontal
639 case 1:
640 width = 163 * ic->font->w + 2 + (ic->large * 2);
641 height = 56 + 12 * ic->lineheight;
642 break;
643 // vertical
644 case 2:
645 width = 83 * ic->font->w + 2 + (ic->large * 2);
646 height = 370 + (ic->large * 90);
647 break;
648 // no hours
649 default:
650 width = 83 * ic->font->w + 2 + (ic->large * 2);
651 height = 56 + 12 * ic->lineheight;
652 break;
653 }
654
655 if (!ic->showheader) {
656 headermod = 26;
657 height -= 22;
658 } else {
659 headermod = 0;
660 }
661
662 imageinit(ic, width, height);
663 layoutinit(ic, "", width, height);
664
665 if (ic->interface.rxtotal == 0 && ic->interface.txtotal == 0) {
666 gdImageString(ic->im, ic->font, 33 * ic->font->w, 100, (unsigned char *)"no data available", ic->ctext);
667 return;
668 }
669
670 drawsummary_alltime(ic, 385 + (ic->large * 125), 57 - headermod + (ic->large * 10));
671 drawlegend(ic, 410 + (ic->large * 132), 155 - headermod + (ic->large * 40), 0);
672
673 drawsummary_digest(ic, 100, 30 - headermod, "day");
674 drawsummary_digest(ic, 100, 29 + 7 * ic->lineheight - headermod, "month");
675
676 switch (layout) {
677 // horizontal
678 case 1:
679 if (cfg.summarygraph == 1) {
680 drawfiveminutes(ic, 496 + (ic->large * 174), height - 30 - (ic->large * 8), rate, 422 + (ic->large * 154), height - 68 + headermod - (ic->large * 8));
681 } else {
682 drawhours(ic, 500 + (ic->large * 160), 46 + (ic->large * 40) - headermod, rate);
683 }
684 break;
685 // vertical
686 case 2:
687 if (cfg.summarygraph == 1) {
688 drawfiveminutes(ic, 8 + (ic->large * 14), height - 31 - (ic->large * 6), rate, 422 + (ic->large * 154), 132 + (ic->large * 35));
689 } else {
690 drawhours(ic, 12, 215 + (ic->large * 84) - headermod, rate);
691 }
692 break;
693 default:
694 break;
695 }
696}
697
698void drawsummary_alltime(IMAGECONTENT *ic, const int x, const int y)
699{
700 struct tm *d;
701 char buffer[512], datebuff[16], daytemp[32];
702 gdFontPtr titlefont;
703
704 if (ic->large) {
705 titlefont = gdFontGetGiant();
706 } else {
707 titlefont = gdFontGetLarge();
708 }
709
710 gdImageString(ic->im, titlefont, x + 12 + (ic->large * 10), y, (unsigned char *)"all time", ic->ctext);
711 snprintf(buffer, 4, "rx ");
712 strncat(buffer, getvalue(ic->interface.rxtotal, 12, RT_Normal), 32);
713 gdImageString(ic->im, ic->font, x, y + (2 * ic->lineheight), (unsigned char *)buffer, ic->ctext);
714 snprintf(buffer, 4, "tx ");
715 strncat(buffer, getvalue(ic->interface.txtotal, 12, RT_Normal), 32);
716 gdImageString(ic->im, ic->font, x, y + (3 * ic->lineheight), (unsigned char *)buffer, ic->ctext);
717 snprintf(buffer, 4, " = ");
718 strncat(buffer, getvalue(ic->interface.rxtotal + ic->interface.txtotal, 12, RT_Normal), 32);
719 gdImageString(ic->im, ic->font, x, y + (4 * ic->lineheight) + 2 + (ic->large * 4), (unsigned char *)buffer, ic->ctext);
720 d = localtime(&ic->interface.created);
721 strftime(datebuff, 16, cfg.tformat, d);
722 snprintf(daytemp, 24, "since %s", datebuff);
723 snprintf(buffer, 32, "%23s", daytemp);
724 gdImageString(ic->im, ic->font, x - 8 * ic->font->w, y + (5 * ic->lineheight) + 10 + (ic->large * 4), (unsigned char *)buffer, ic->ctext);
725}
726
727void drawsummary_digest(IMAGECONTENT *ic, const int x, const int y, const char *mode)
728{
729 int textx, texty, offset = 0;
730 double rxp, txp, mod;
731 char buffer[512], datebuff[16], daytemp[32];
732 time_t yesterday;
733 struct tm *d = NULL;
734 dbdatalist *datalist = NULL;
735 dbdatalist *data_current = NULL, *data_previous = NULL;
736 dbdatalistinfo datainfo;
737 gdFontPtr titlefont;
738
739 if (ic->large) {
740 titlefont = gdFontGetGiant();
741 } else {
742 titlefont = gdFontGetLarge();
743 }
744
745 yesterday = ic->current - 86400;
746
747 switch(mode[0]) {
748 case 'd':
749 break;
750 case 'm':
751 break;
752 default:
753 printf("Error: Unsupported mode %s for summary digest\n", mode);
754 return;
755 }
756
757 if (!db_getdata(&datalist, &datainfo, ic->interface.name, mode, 2) || datalist == NULL) {
758 gdImageString(ic->im, ic->font, 25 * ic->font->w, y + 30, (unsigned char *)"no data available", ic->ctext);
759 return;
760 } else if (datalist->next == NULL) {
761 data_current = datalist;
762 } else {
763 data_previous = datalist;
764 data_current = datalist->next;
765 }
766
767 /* latest entry */
768 if (data_current->rx + data_current->tx == 0) {
769 rxp = txp = 0;
770 } else {
771 rxp = (double)data_current->rx / (double)(data_current->rx + data_current->tx) * 100;
772 txp = (double)100 - rxp;
773 }
774
775 /* do scaling if needed */
776 if (data_previous != NULL && (data_current->rx + data_current->tx) < (data_previous->rx + data_previous->tx)) {
777 mod = (double)(data_current->rx + data_current->tx) / (double)(data_previous->rx + data_previous->tx);
778 rxp = rxp * mod;
779 txp = txp * mod;
780 }
781
782 /* move graph to center if there's only one to draw for this line */
783 if (data_previous == NULL) {
784 offset = 85 + (ic->large * 25);
785 }
786
787 textx = x + offset;
788 texty = y;
789
790 drawdonut(ic, textx + 50 + (ic->large * 40), texty + 45 + (ic->large * 10), (float)rxp, (float)txp, 49 + (ic->large * 10), 15 + (ic->large * 3));
791
792 if (mode[0] == 'd') {
793 /* get formatted date for today */
794 d = localtime(&ic->current);
795 strftime(datebuff, 16, cfg.dformat, d);
796
797 /* get formatted date for current day in database */
798 d = localtime(&data_current->timestamp);
799 strftime(daytemp, 16, cfg.dformat, d);
800
801 /* change daytemp to today if formatted days match */
802 if (strcmp(datebuff, daytemp) == 0) {
803 strncpy_nt(daytemp, "today", 32);
804 }
805 } else if (mode[0] == 'm') {
806 d = localtime(&data_current->timestamp);
807 strftime(daytemp, 16, cfg.mformat, d);
808 }
809
810 snprintf(buffer, 32, "%*s", getpadding(12, daytemp), daytemp);
811 gdImageString(ic->im, titlefont, textx - 54 + (ic->large * (ic->font->w * 3 - 4)), texty - 1, (unsigned char *)buffer, ic->ctext);
812
813 if (cfg.summaryrate) {
814 d = localtime(&ic->interface.updated);
815 if (mode[0] == 'd') {
816 snprintf(buffer, 16, "%15s", gettrafficrate(data_current->rx + data_current->tx, d->tm_sec + (d->tm_min * 60) + (d->tm_hour * 3600), 15));
817 } else if (mode[0] == 'm') {
818 snprintf(buffer, 16, "%15s", gettrafficrate(data_current->rx + data_current->tx, mosecs(data_current->timestamp, ic->interface.updated), 15));
819 }
820 gdImageString(ic->im, ic->font, textx - 74, texty + 4 * ic->lineheight + 10, (unsigned char *)buffer, ic->ctext);
821 } else {
822 texty += 7;
823 }
824
825 snprintf(buffer, 4, "rx ");
826 strncat(buffer, getvalue(data_current->rx, 12, RT_Normal), 32);
827 gdImageString(ic->im, ic->font, textx - 74, texty + ic->lineheight + 6, (unsigned char *)buffer, ic->ctext);
828 snprintf(buffer, 4, "tx ");
829 strncat(buffer, getvalue(data_current->tx, 12, RT_Normal), 32);
830 gdImageString(ic->im, ic->font, textx - 74, texty + 2 * ic->lineheight + 6, (unsigned char *)buffer, ic->ctext);
831 snprintf(buffer, 4, " = ");
832 strncat(buffer, getvalue(data_current->rx + data_current->tx, 12, RT_Normal), 32);
833 gdImageString(ic->im, ic->font, textx - 74, texty + 3 * ic->lineheight + 8, (unsigned char *)buffer, ic->ctext);
834
835 /* previous entry */
836 if (data_previous != NULL) {
837 if (data_previous->rx + data_previous->tx == 0) {
838 rxp = txp = 0;
839 } else {
840 rxp = (double)data_previous->rx / (double)(data_previous->rx + data_previous->tx) * 100;
841 txp = (double)100 - rxp;
842 }
843
844 /* do scaling if needed */
845 if ((data_previous->rx + data_previous->tx) < (data_current->rx + data_current->tx)) {
846 mod = (double)(data_previous->rx + data_previous->tx) / (double)(data_current->rx + data_current->tx);
847 rxp = rxp * mod;
848 txp = txp * mod;
849 }
850
851 textx += 180 + (ic->large * 60);
852
853 drawdonut(ic, textx + 50 + (ic->large * 40), texty + 45 + (ic->large * 10), (float)rxp, (float)txp, 49 + (ic->large * 10), 15 + (ic->large * 3));
854
855 if (mode[0] == 'd') {
856 /* get formatted date for yesterday */
857 d = localtime(&yesterday);
858 strftime(datebuff, 16, cfg.dformat, d);
859
860 /* get formatted date for previous day in database */
861 d = localtime(&data_previous->timestamp);
862 strftime(daytemp, 16, cfg.dformat, d);
863
864 /* change daytemp to yesterday if formatted days match */
865 if (strcmp(datebuff, daytemp) == 0) {
866 strncpy_nt(daytemp, "yesterday", 32);
867 }
868 } else if (mode[0] == 'm') {
869 d = localtime(&data_previous->timestamp);
870 strftime(daytemp, 16, cfg.mformat, d);
871 }
872
873 snprintf(buffer, 32, "%*s", getpadding(12, daytemp), daytemp);
874 gdImageString(ic->im, titlefont, textx - 54 + (ic->large * (ic->font->w * 3 - 4)), texty - 1, (unsigned char *)buffer, ic->ctext);
875
876 if (cfg.summaryrate) {
877 if (mode[0] == 'd') {
878 snprintf(buffer, 16, "%15s", gettrafficrate(data_previous->rx + data_previous->tx, 86400, 15));
879 } else if (mode[0] == 'm') {
880 snprintf(buffer, 16, "%15s", gettrafficrate(data_previous->rx + data_previous->tx, dmonth(d->tm_mon) * 86400, 15));
881 }
882 gdImageString(ic->im, ic->font, textx - 74, texty + 4 * ic->lineheight + 10, (unsigned char *)buffer, ic->ctext);
883 } else {
884 texty += 7;
885 }
886
887 snprintf(buffer, 4, "rx ");
888 strncat(buffer, getvalue(data_previous->rx, 12, RT_Normal), 32);
889 gdImageString(ic->im, ic->font, textx - 74, texty + ic->lineheight + 6, (unsigned char *)buffer, ic->ctext);
890 snprintf(buffer, 4, "tx ");
891 strncat(buffer, getvalue(data_previous->tx, 12, RT_Normal), 32);
892 gdImageString(ic->im, ic->font, textx - 74, texty + 2 * ic->lineheight + 6, (unsigned char *)buffer, ic->ctext);
893 snprintf(buffer, 4, " = ");
894 strncat(buffer, getvalue(data_previous->rx + data_previous->tx, 12, RT_Normal), 32);
895 gdImageString(ic->im, ic->font, textx - 74, texty + 3 * ic->lineheight + 8, (unsigned char *)buffer, ic->ctext);
896 }
897
898 data_current = NULL;
899 data_previous = NULL;
900 dbdatalistfree(&datalist);
901}
902
903void drawfivegraph(IMAGECONTENT *ic, const int rate, const int resultcount, const int height)
904{
905 int imagewidth, imageheight = height, headermod = 0;
906
907 imagewidth = resultcount + FIVEMINEXTRASPACE + (ic->large * 14);
908
909 if (!ic->showheader) {
910 headermod = 22;
911 }
912
913 imageinit(ic, imagewidth, imageheight);
914 layoutinit(ic, " / 5 minute", imagewidth, imageheight);
915
916 if (drawfiveminutes(ic, 8 + (ic->large * 14), imageheight - 30 - (ic->large * 8), rate, resultcount, imageheight - 68 + headermod - (ic->large * 8))) {
917 drawlegend(ic, imagewidth / 2 - (ic->large * 10), imageheight - 17 - (ic->large * 2), 0);
918 }
919}
920
921int drawfiveminutes(IMAGECONTENT *ic, const int xpos, const int ypos, const int rate, const int resultcount, const int height)
922{
923 int x = xpos, y = ypos, i = 0, t = 0, rxh = 0, txh = 0, step = 0, s = 0, prev = 0;
924 uint64_t scaleunit, max;
925 time_t timestamp;
926 double ratediv, e;
927 char buffer[32];
928 struct tm *d;
929 dbdatalist *datalist = NULL, *datalist_i = NULL;
930 dbdatalistinfo datainfo;
931 gdFontPtr font;
932
933 if (ic->large) {
934 font = gdFontGetSmall();
935 } else {
936 font = gdFontGetTiny();
937 }
938
939 if (!db_getdata(&datalist, &datainfo, ic->interface.name, "fiveminute", (uint32_t)resultcount) || datainfo.count == 0) {
940 x = (resultcount + FIVEMINEXTRASPACE + (ic->large * 14)) / 2 - (8 * ic->font->w + ic->font->w / 2);
941 gdImageString(ic->im, ic->font, x, y - (height / 2) - ic->font->h, (unsigned char *)"no data available", ic->ctext);
942 return 0;
943 }
944
945 datalist_i = datalist;
946
947 if (cfg.rateunit) {
948 ratediv = 37.5; /* x * 8 / 300 */
949 } else {
950 ratediv = 300;
951 }
952
953 /* axis */
954 x += 36;
955 gdImageLine(ic->im, x, y, x + (resultcount + FIVEMINWIDTHFULLPADDING), y, ic->ctext);
956 gdImageLine(ic->im, x + 4, y + 4, x + 4, y - height, ic->ctext);
957
958 /* arrows */
959 drawarrowup(ic, x + 4, y - 1 - height);
960 drawarrowright(ic, x + 1 + (resultcount + FIVEMINWIDTHFULLPADDING), y);
961
962 max = datainfo.maxrx + datainfo.maxtx;
963
964 if (datainfo.maxrx == datainfo.maxtx) {
965 txh = (int)((height - FIVEMINHEIGHTOFFSET * 2) / 2);
966 rxh = height - FIVEMINHEIGHTOFFSET * 2 - txh;
967 max = (uint64_t)((double)datainfo.maxrx / ratediv);
968 t = rxh;
969 } else if (datainfo.maxrx > datainfo.maxtx) {
970 txh = (int)lrint(((double)datainfo.maxtx / (double)max) * (height - FIVEMINHEIGHTOFFSET * 2));
971 rxh = height - FIVEMINHEIGHTOFFSET * 2 - txh;
972 max = (uint64_t)((double)datainfo.maxrx / ratediv);
973 t = rxh;
974 } else {
975 rxh = (int)lrint(((double)datainfo.maxrx / (double)max) * (height - FIVEMINHEIGHTOFFSET * 2));
976 txh = height - FIVEMINHEIGHTOFFSET * 2 - rxh;
977 max = (uint64_t)((double)datainfo.maxtx / ratediv);
978 t = txh;
979 }
980
981 /* center line */
982 x += 5;
983 y -= txh + FIVEMINHEIGHTOFFSET;
984 gdImageLine(ic->im, x, y, x + (resultcount + FIVEMINWIDTHPADDING), y, ic->ctext);
985 gdImageString(ic->im, font, x - 21 - (ic->large * 3), y - 4 - (ic->large * 3), (unsigned char *)" 0", ic->ctext);
986
987 /* scale values */
988 scaleunit = getscale(max, rate);
989
990 s = (int)lrint(((double)scaleunit / (double)max) * t);
991 if (s == 0) {
992 s = 1; // force to show something when there's not much or any traffic, scale is likely to be wrong in this case
993 }
994 while (s * step < SCALEMINPIXELS) {
995 step++;
996 }
997
998 if (debug) {
999 printf("maxrx: %" PRIu64 "\n", datainfo.maxrx);
1000 printf("maxtx: %" PRIu64 "\n", datainfo.maxtx);
1001 printf("rxh: %d txh: %d\n", rxh, txh);
1002 printf("max divided: %" PRIu64 "\n", max);
1003 printf("scaleunit: %" PRIu64 "\nstep: %d\n", scaleunit, step);
1004 printf("pixels per step: %d\n", s);
1005 printf("mintime: %" PRIu64 "\nmaxtime: %" PRIu64 "\n", (uint64_t)datainfo.mintime, (uint64_t)datainfo.maxtime);
1006 printf("count: %u\n", datainfo.count);
1007 }
1008
1009 /* upper part scale values */
1010 y--; // adjust to start above center line
1011 for (i = step; i * s <= rxh; i = i + step) {
1012 gdImageDashedLine(ic->im, x, y - (i * s), x + (resultcount + FIVEMINWIDTHPADDING), y - (i * s), ic->cline);
1013 gdImageDashedLine(ic->im, x, y - prev - (step * s) / 2, x + (resultcount + FIVEMINWIDTHPADDING), y - prev - (step * s) / 2, ic->clinel);
1014 gdImageString(ic->im, font, x - 21 - (ic->large * 3), y - 3 - (i * s) - (ic->large * 3), (unsigned char *)getimagevalue(scaleunit * (unsigned int)i, 3, rate), ic->ctext);
1015 prev = i * s;
1016 }
1017 if ((prev + (step * s) / 2) <= rxh) {
1018 gdImageDashedLine(ic->im, x, y - prev - (step * s) / 2, x + (resultcount + FIVEMINWIDTHPADDING), y - prev - (step * s) / 2, ic->clinel);
1019 }
1020
1021 y += 2; // adjust to start below center line
1022 prev = 0;
1023
1024 /* lower part scale values */
1025 for (i = step; i * s <= txh; i = i + step) {
1026 gdImageDashedLine(ic->im, x, y + (i * s), x + (resultcount + FIVEMINWIDTHPADDING), y + (i * s), ic->cline);
1027 gdImageDashedLine(ic->im, x, y + prev + (step * s) / 2, x + (resultcount + FIVEMINWIDTHPADDING), y + prev + (step * s) / 2, ic->clinel);
1028 gdImageString(ic->im, font, x - 21 - (ic->large * 3), y - 3 + (i * s) - (ic->large * 3), (unsigned char *)getimagevalue(scaleunit * (unsigned int)i, 3, rate), ic->ctext);
1029 prev = i * s;
1030 }
1031 if ((prev + (step * s) / 2) <= txh) {
1032 gdImageDashedLine(ic->im, x, y + prev + (step * s) / 2, x + (resultcount + FIVEMINWIDTHPADDING), y + prev + (step * s) / 2, ic->clinel);
1033 }
1034
1035 y--; // y is now back on center line
1036
1037 /* scale text */
1038 gdImageStringUp(ic->im, font, x - 39 - (ic->large * 14), ypos - height / 2 + (rate * 10), (unsigned char *)getimagescale(scaleunit * (unsigned int)step, rate), ic->ctext);
1039
1040 timestamp = datainfo.maxtime - (resultcount * 300);
1041
1042 while (datalist_i != NULL && datalist_i->timestamp < timestamp + 300) {
1043 if (debug) {
1044 printf("Skip data, %" PRIu64 " < %" PRIu64 "\n", (uint64_t)datalist_i->timestamp, (uint64_t)timestamp + 300);
1045 }
1046 datalist_i = datalist_i->next;
1047 }
1048
1049 for (i = 0; i < resultcount; i++) {
1050
1051 if (datalist_i == NULL) {
1052 break;
1053 }
1054
1055 timestamp += 300;
1056 d = localtime(&timestamp);
1057
1058 if (d->tm_min == 0 && i > 2) {
1059 if (d->tm_hour % 2 == 0) {
1060 if (d->tm_hour == 0) {
1061 gdImageLine(ic->im, x + i, y + txh - 1 + FIVEMINHEIGHTOFFSET, x + i, y - rxh - 1, ic->cline);
1062 } else {
1063 gdImageLine(ic->im, x + i, y + txh - 1 + FIVEMINHEIGHTOFFSET, x + i, y - rxh - 1, ic->cbgoffset);
1064 }
1065
1066 if (i > font->w) {
1067 snprintf(buffer, 32, "%02d", d->tm_hour);
1068 if (datalist_i->timestamp > timestamp) {
1069 gdImageString(ic->im, font, x + i - font->w + 1, y + txh + font->h - (ic->large * 5), (unsigned char *)buffer, ic->cline);
1070 } else {
1071 gdImageString(ic->im, font, x + i - font->w + 1, y + txh + font->h - (ic->large * 5), (unsigned char *)buffer, ic->ctext);
1072 }
1073 }
1074 } else {
1075 gdImageLine(ic->im, x + i, y + txh - 1 + FIVEMINHEIGHTOFFSET, x + i, y - rxh - 1, ic->cbgoffset);
1076 }
1077 gdImageSetPixel(ic->im, x + i, y, ic->ctext);
1078 }
1079
1080 if (datalist_i->timestamp > timestamp) {
1081 gdImageSetPixel(ic->im, x + i, y, ic->cline);
1082 gdImageSetPixel(ic->im, x + i, y + txh + FIVEMINHEIGHTOFFSET, ic->cline);
1083 continue;
1084 }
1085
1086 /* only the last entry can be the currently ongoing period that may need scaling */
1087 if (datalist_i->next == NULL && issametimeslot(LT_5min, datalist_i->timestamp, ic->interface.updated)) {
1088 e = (double)(ic->interface.updated - datalist_i->timestamp) / (double)300;
1089 if (e < 0.01) {
1090 e = 1;
1091 }
1092 } else {
1093 e = 1;
1094 }
1095
1096 t = (int)lrint(((double)datalist_i->rx / e / (double)datainfo.maxrx) * rxh);
1097 if (t > rxh) {
1098 t = rxh;
1099 }
1100 drawpole(ic, x + i, y - 1, t, 1, ic->crx);
1101
1102 t = (int)lrint(((double)datalist_i->tx / e / (double)datainfo.maxtx) * txh);
1103 if (t > txh) {
1104 t = txh;
1105 }
1106 drawpole(ic, x + i, y + 1, t, 2, ic->ctx);
1107
1108 datalist_i = datalist_i->next;
1109 }
1110
1111 dbdatalistfree(&datalist);
1112
1113 return 1;
1114}
time_t mosecs(time_t month, time_t updated)
Definition: common.c:209
int dmonth(const int month)
Definition: common.c:177
int debug
Definition: common.c:8
CFG cfg
Definition: common.c:4
char * strncpy_nt(char *dest, const char *src, size_t n)
Definition: common.c:253
int db_getdata(dbdatalist **dbdata, dbdatalistinfo *listinfo, const char *iface, const char *table, const uint32_t resultlimit)
Definition: dbsql.c:1212
int db_getdata_range(dbdatalist **dbdata, dbdatalistinfo *listinfo, const char *iface, const char *table, const uint32_t resultlimit, const char *databegin, const char *dataend)
Definition: dbsql.c:1217
void dbdatalistfree(dbdatalist **dbdata)
Definition: dbsql.c:1393
void initimagecontent(IMAGECONTENT *ic)
Definition: image.c:8
void drawsummary(IMAGECONTENT *ic, const int layout, const int rate)
Definition: image.c:633
void drawimage(IMAGECONTENT *ic)
Definition: image.c:25
void drawsummary_digest(IMAGECONTENT *ic, const int x, const int y, const char *mode)
Definition: image.c:727
void drawsummary_alltime(IMAGECONTENT *ic, const int x, const int y)
Definition: image.c:698
void drawfivegraph(IMAGECONTENT *ic, const int rate, const int resultcount, const int height)
Definition: image.c:903
void drawhourly(IMAGECONTENT *ic, const int rate)
Definition: image.c:284
void drawlist(IMAGECONTENT *ic, const char *listname)
Definition: image.c:304
int drawhours(IMAGECONTENT *ic, const int xpos, const int ypos, const int rate)
Definition: image.c:108
int drawfiveminutes(IMAGECONTENT *ic, const int xpos, const int ypos, const int rate, const int resultcount, const int height)
Definition: image.c:921
#define FIVEMINHEIGHTOFFSET
Definition: image.h:14
#define SCALEMINPIXELS
Definition: image.h:19
#define FIVEMINWIDTHFULLPADDING
Definition: image.h:15
#define FIVEMINEXTRASPACE
Definition: image.h:17
#define FIVEMINWIDTHPADDING
Definition: image.h:16
char * getimagevalue(const uint64_t b, const int len, const int rate)
void layoutinit(IMAGECONTENT *ic, const char *title, const int width, const int height)
Definition: image_support.c:93
void drawdonut(IMAGECONTENT *ic, const int x, const int y, const float rxp, const float txp, const int size, const int holesize)
void imageinit(IMAGECONTENT *ic, const int width, const int height)
Definition: image_support.c:8
void drawpoles(IMAGECONTENT *ic, const int x, const int y, const int len, const uint64_t rx, const uint64_t tx, const uint64_t max)
void drawpole(IMAGECONTENT *ic, const int x, const int y, const int length, const int direction, const int color)
void drawarrowup(IMAGECONTENT *ic, const int x, const int y)
void drawarrowright(IMAGECONTENT *ic, const int x, const int y)
void drawlegend(IMAGECONTENT *ic, const int x, const int y, const short israte)
uint64_t getscale(const uint64_t input, const int rate)
void drawbar(IMAGECONTENT *ic, const int x, const int y, const int len, const uint64_t rx, const uint64_t tx, const uint64_t max, const short isestimate)
char * getimagescale(const uint64_t b, const int rate)
uint64_t getperiodseconds(const ListType listtype, const time_t entry, const time_t updated, const short isongoing)
Definition: misc.c:453
void getestimates(uint64_t *rx, uint64_t *tx, const ListType listtype, const time_t updated, dbdatalist **dbdata)
Definition: misc.c:493
int issametimeslot(const ListType listtype, const time_t entry, const time_t updated)
Definition: misc.c:403
char * getvalue(const uint64_t bytes, const int len, const RequestType type)
Definition: misc.c:148
int getpadding(const int len, const char *str)
Definition: misc.c:320
char * gettrafficrate(const uint64_t bytes, const time_t interval, const int len)
Definition: misc.c:203
ListType
Definition: misc.h:14
@ LT_5min
Definition: misc.h:16
@ LT_Hour
Definition: misc.h:17
@ LT_Year
Definition: misc.h:20
@ LT_Day
Definition: misc.h:18
@ LT_None
Definition: misc.h:15
@ LT_Top
Definition: misc.h:21
@ LT_Month
Definition: misc.h:19
@ RT_Estimate
Definition: misc.h:10
@ RT_Normal
Definition: misc.h:9
int32_t summarygraph
Definition: common.h:318
int32_t listfivemins
Definition: common.h:324
int32_t listtop
Definition: common.h:324
int32_t estimatestyle
Definition: common.h:317
char tformat[64]
Definition: common.h:307
char mformat[64]
Definition: common.h:307
char dformat[64]
Definition: common.h:307
int32_t imagescale
Definition: common.h:316
int32_t transbg
Definition: common.h:315
int32_t listmonths
Definition: common.h:324
int32_t linespaceadjust
Definition: common.h:317
int32_t fivegheight
Definition: common.h:318
int32_t summaryrate
Definition: common.h:314
int32_t qmode
Definition: common.h:314
int32_t ostyle
Definition: common.h:315
int32_t hourlyrate
Definition: common.h:314
int32_t listdays
Definition: common.h:324
int32_t listyears
Definition: common.h:324
int32_t fivegresultcount
Definition: common.h:317
int32_t hourlygmode
Definition: common.h:318
int32_t barshowsrate
Definition: common.h:317
int32_t listhours
Definition: common.h:324
int32_t rateunit
Definition: common.h:314
Definition: dbshow.h:8
uint64_t tx
Definition: dbshow.h:10
uint64_t rx
Definition: dbshow.h:10
time_t date
Definition: dbshow.h:9
int ctext
Definition: image.h:25
int showedge
Definition: image.h:26
gdFontPtr font
Definition: image.h:23
int ctx
Definition: image.h:26
int crx
Definition: image.h:26
int large
Definition: image.h:27
time_t current
Definition: image.h:29
int clinel
Definition: image.h:25
interfaceinfo interface
Definition: image.h:24
gdImagePtr im
Definition: image.h:22
char dataend[18]
Definition: image.h:28
int altdate
Definition: image.h:26
int cline
Definition: image.h:25
char databegin[18]
Definition: image.h:28
int cbgoffset
Definition: image.h:26
char headertext[65]
Definition: image.h:28
int cbackground
Definition: image.h:25
int showlegend
Definition: image.h:26
int showheader
Definition: image.h:26
int lineheight
Definition: image.h:27
time_t timestamp
Definition: dbsql.h:8
struct dbdatalist * next
Definition: dbsql.h:11
uint64_t rx
Definition: dbsql.h:10
uint64_t tx
Definition: dbsql.h:10
time_t mintime
Definition: dbsql.h:16
time_t maxtime
Definition: dbsql.h:16
uint64_t maxrx
Definition: dbsql.h:18
uint64_t sumrx
Definition: dbsql.h:20
uint64_t sumtx
Definition: dbsql.h:20
uint32_t count
Definition: dbsql.h:15
uint64_t max
Definition: dbsql.h:19
uint64_t maxtx
Definition: dbsql.h:18
char alias[32]
Definition: dbsql.h:24
time_t created
Definition: dbsql.h:26
time_t updated
Definition: dbsql.h:26
uint64_t txtotal
Definition: dbsql.h:28
char name[32]
Definition: dbsql.h:24
uint64_t rxtotal
Definition: dbsql.h:28