distromatic/src/distroquery.c

457 lines
18 KiB
C

/*
* distroquery - tool for querying data generated by distromatic
*
* Copyright (C) 2013 by Silvan Calarco <silvan.calarco@mambasoft.it>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of version 2 of the GNU General Public License as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY, to the extent permitted by law; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <getopt.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <dirent.h>
#include <sys/stat.h>
#if HAVE_STRING_H
# if !STDC_HEADERS && HAVE_MEMORY_H
# include <memory.h>
# endif
/* Tell glibc's <string.h> to provide a prototype for strndup() */
# ifndef __USE_GNU
# define __USE_GNU
# endif
# include <string.h>
#endif
#if HAVE_STRINGS_H
# include <strings.h>
#endif
/* Tell glibc's <time.h> to provide a prototype for strptime() */
#ifndef __USE_XOPEN
# define __USE_XOPEN
#endif
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#if !HAVE_STRCHR
# define strchr index
#endif
#include <sqlite3.h>
#include "distromatic.h"
#include "functions.h"
static struct configTag *firstconfigtag = NULL, *configtag = NULL;
char *query;
char *query_package;
char *query_repository;
char *query_arch;
struct configTag *query_repositories[100];
int search_milestone1 = 0, search_milestone2 = 1, search_devel = 1;
int search_arm = 0, search_x86_64 = 0, search_i586 = 1, search_sources = 0;
/* Converts a hex character to its integer value */
char from_hex(char ch) {
return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
}
/* Converts an integer value to its hex character*/
char to_hex(char code) {
static char hex[] = "0123456789abcdef";
return hex[code & 15];
}
/* Returns a url-encoded version of str */
/* IMPORTANT: be sure to free() the returned string after use */
char *url_encode(char *str) {
char *pstr = str, *buf = malloc(strlen(str) * 3 + 1), *pbuf = buf;
while (*pstr) {
if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
*pbuf++ = *pstr;
else if (*pstr == ' ')
*pbuf++ = '+';
else
*pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
pstr++;
}
*pbuf = '\0';
return buf;
}
/* Returns a url-decoded version of str */
/* IMPORTANT: be sure to free() the returned string after use */
char *url_decode(char *str) {
char *pstr = str, *buf = malloc(strlen(str) + 1), *pbuf = buf;
while (*pstr) {
if (*pstr == '%') {
if (pstr[1] && pstr[2]) {
*pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
pstr += 2;
}
} else if (*pstr == '+') {
*pbuf++ = ' ';
} else {
*pbuf++ = *pstr;
}
pstr++;
}
*pbuf = '\0';
return buf;
}
void printInputForm() {
struct configTag *ct = firstconfigtag;
const char ajax_call[] = "distroquery_request("
// "'repository='+getElementById('repository').value"
"'query='+getElementById('query').value+"
"'&search_devel='+getElementById('search_devel').checked+"
"'&search_milestone2='+getElementById('search_milestone2').checked+"
"'&search_milestone1='+getElementById('search_milestone1').checked+"
"'&search_i586='+getElementById('search_i586').checked+"
"'&search_x86_64='+getElementById('search_x86_64').checked+"
"'&search_arm='+getElementById('search_arm').checked+"
"'&search_sources='+getElementById('search_sources').checked"
")";
printf("<queryform><![CDATA[");
printf("<input id=query onkeyup=if(checkMinLength(this.value,3))%s>", ajax_call);
printf("<button onclick=%s>Cerca</button>", ajax_call);
/* printf("&nbsp;Repository: <select id=repository>");
while (ct) {
printf("<option>%s</option>",ct->tag);
ct = ct->next;
}
printf("</select>");*/
printf("<input type=checkbox id=\"search_devel\" checked=checked onclick=%s>devel&nbsp;", ajax_call);
printf("<input type=checkbox id=\"search_milestone2\" checked=checked onclick=%s>milestone2&nbsp;", ajax_call);
printf("<input type=checkbox id=\"search_milestone1\" onclick=%s>milestone1&nbsp;", ajax_call);
printf("&nbsp;<input type=checkbox id=\"search_i586\" checked=checked onclick=%s>i586&nbsp;", ajax_call);
printf("<input type=checkbox id=\"search_x86_64\" onclick=%s>x86_64&nbsp;", ajax_call);
printf("<input type=checkbox id=\"search_arm\" onclick=%s>arm&nbsp;", ajax_call);
printf("<input type=checkbox id=\"search_sources\" onclick=%s>sources&nbsp;", ajax_call);
printf("<br>");
/* ct = firstconfigtag;
while (ct) {
printf("<div width=150px style=\"display:inline\"><input name=\"%s\" type=checkbox value=\"%s\">%s</div>",ct->tag, ct->tag, ct->tag);
ct = ct->next;
}*/
printf("]]></queryform>");
}
void printQueryData() {
int a, i, j, k, numresults = 0;
char dbname[PATH_MAX];
sqlite3_stmt *statement;
char sql[PATH_MAX];
printf("<queryreply><![CDATA[");
for (i = 0; i < strlen(query); i++) {
if (query[i] == ' ') query[i] = '%';
}
for (i = 0; query_repositories[i] != NULL; i++) {
snprintf(dbname, PATH_MAX, "%sdistromatic.db", query_repositories[i]->repository_dir);
if (sqlite3_open_v2(dbname, (sqlite3**)&query_repositories[i]->db, SQLITE_OPEN_READONLY, NULL)) {
if (query_repositories[i]->db) sqlite3_close(query_repositories[i]->db);
query_repositories[i]->db = NULL;
fprintf(stderr, "ERROR: unable to open sqlite3 db %s; aborting.\n", dbname);
}
}
for (i = 0; query_repositories[i] != NULL; i++) {
for (a = 0; a < ARCHS_MAX && query_repositories[i]->arch[a]; a++) {
if ((search_i586 && !strcmp(query_repositories[i]->arch[a],"i586")) ||
(search_arm && !strcmp(query_repositories[i]->arch[a],"arm")) ||
(search_x86_64 && !strcmp(query_repositories[i]->arch[a],"x86_64"))) {
snprintf(sql, PATH_MAX,
"SELECT * FROM packages_%s WHERE name LIKE '%%%s%%' OR summary LIKE '%%%s%%' OR description LIKE '%%%s%%' OR version LIKE '%%%s%%' "
"ORDER BY name = '%s' DESC, name LIKE '%s%%' DESC, name LIKE '%%%s%%' DESC, "
"groupdescr LIKE 'Graphical Desktop/%%' DESC, groupdescr LIKE 'Applications/%%' DESC, "
"groupdescr LIKE 'Development/%%' ASC, groupdescr LIKE 'Documentation%%' ASC, groupdescr LIKE 'System/Libraries%%' ASC, "
"name LIKE '%%-devel' ASC, name LIKE '%%-debug' ASC "
"LIMIT 100",
query_repositories[i]->arch[a], query, query, query, query, query, query);
if (query_repositories[i]->db &&
(sqlite3_prepare_v2((sqlite3*)query_repositories[i]->db, sql, strlen(sql), &statement, NULL) == SQLITE_OK)) {
while (sqlite3_step(statement) == SQLITE_ROW) {
numresults++;
printf("<div style='position:relative'><hr><br><div style='display:inline;color:white;background-color:green'>&nbsp;%s&nbsp;</div>&nbsp;"
"<div style='display:inline;color:black;background-color:yellow'>&nbsp;%s&nbsp;</div>&nbsp;"
"<div style='display:inline;color:black;background-color:lightblue'>&nbsp;%s&nbsp;</div><br>"
"<b>%s</b> %s-%s<br>%s",
query_repositories[i]->arch[a],
query_repositories[i]->tag,
sqlite3_column_text(statement,7),
sqlite3_column_text(statement,1),
sqlite3_column_text(statement,4),
sqlite3_column_text(statement,5),
sqlite3_column_text(statement,6));
printf("<br><br><div style='text-align:justify;text-justify:inter-word;font-style:italic'>%s</div>",
sqlite3_column_text(statement,8));
/* install */
/* printf("<div align=right style='position:absolute;top:5px;right:0;padding:5px;'>"
"<div><object type=\"application/x-packagekit-plugin\" width=\"400\" height=\"50\">"
"<param name=\"displayname\" value=\"%s - %s\" />"
"<param name=\"packagenames\" value=\"%s\" /></object></div>",
sqlite3_column_text(statement,1),
sqlite3_column_text(statement,6),
sqlite3_column_text(statement,1));*/
/* download */
printf("<div style='display:inline;background-color:green'>"
"<a href=\"%s%s/SRPMS.base/%s-%s-%s.src.rpm\" style=\"color:white\">&nbsp;Download&nbsp;</a></div>",
query_repositories[i]->download_prefix,
query_repositories[i]->download_dir,
sqlite3_column_text(statement,1),
sqlite3_column_text(statement,4),
sqlite3_column_text(statement,5));
/* details */
printf("&nbsp;<div style='display:inline;background-color:lightblue;font-weight:strong'>"
"<a href='javascript:distroquery_request("
"\"repository=%s&package=%s&arch=%s\")' style=\"color:black\">&nbsp;Details&nbsp;</a></div>",
query_repositories[i]->tag,
sqlite3_column_text(statement,1),
query_repositories[i]->arch[a]);
printf("</div></div><br>");
}
}
}
printf("\n");
}
}
if (search_sources) {
snprintf(sql, PATH_MAX,
"SELECT * FROM sources WHERE name LIKE '%%%s%%' OR summary LIKE '%%%s%%' OR description LIKE '%%%s%%' OR version LIKE '%%%s%%'"
"ORDER BY name = '%s' DESC, name LIKE '%s%%' DESC, name LIKE '%%%s%%' DESC LIMIT 100",
query, query, query, query, query, query);
for (i = 0; query_repositories[i] != NULL; i++) {
if (query_repositories[i]->db &&
(sqlite3_prepare_v2((sqlite3*)query_repositories[i]->db, sql, strlen(sql), &statement, NULL) == SQLITE_OK)) {
while (sqlite3_step(statement) == SQLITE_ROW) {
numresults++;
printf("<hr><br><div style='display:inline;color:black;background-color:red'>&nbsp;Source&nbsp;</div>&nbsp;"
"<div style='display:inline;color:black;background-color:yellow'>&nbsp;%s&nbsp;</div>&nbsp;"
"<div style='display:inline;color:black;background-color:lightblue'>&nbsp%s&nbsp;</div><br>"
"<b>%s</b> %s-%s<br>%s<br>License: %s</br>URL: %s<br><br>"
"<div style='text-align:justify;text-justify:inter-word;font-style:italic'>%s</div><br>",
query_repositories[i]->tag,
sqlite3_column_text(statement,8),
sqlite3_column_text(statement,1),
sqlite3_column_text(statement,4),
sqlite3_column_text(statement,5),
sqlite3_column_text(statement,6),
sqlite3_column_text(statement,11),
sqlite3_column_text(statement,10),
sqlite3_column_text(statement,9));
}
}
printf("\n");
}
}
printf("<hr>");
printf("]]></queryreply>");
printf("<querystatus><![CDATA[%d result(s) shown.]]></querystatus>", numresults);
for (i = 0; query_repositories[i] != NULL; i++) {
sqlite3_close((sqlite3*)query_repositories[i]->db);
query_repositories[i]->db = NULL;
}
}
void printPackageData() {
int a, i, j, k, numresults = 0;
char dbname[PATH_MAX];
sqlite3_stmt *statement;
char sql[PATH_MAX];
struct configTag* ct = findRepositoryByTag(query_repository);
printf("<queryreply><![CDATA[");
snprintf(dbname, PATH_MAX, "%sdistromatic.db", ct->repository_dir);
if (sqlite3_open_v2(dbname, (sqlite3**)&ct->db, SQLITE_OPEN_READONLY, NULL)) {
if (ct->db) sqlite3_close(ct->db);
ct->db = NULL;
fprintf(stderr, "ERROR: unable to open sqlite3 db %s; aborting.\n", dbname);
return;
}
snprintf(sql, PATH_MAX, "SELECT * FROM packages_%s WHERE name = '%s'", query_arch, query_package);
if (ct->db &&
(sqlite3_prepare_v2((sqlite3*)ct->db, sql, strlen(sql), &statement, NULL) == SQLITE_OK)) {
while (sqlite3_step(statement) == SQLITE_ROW) {
numresults++;
printf("<hr><br><div style='display:inline;color:white;background-color:green'> %s </div>&nbsp;"
"<div style='display:inline;color:black;background-color:yellow'> %s </div><br>"
"<b>%s</b> %s-%s<br>%s<br>Group: %s"
"<br><br><div style='text-align:justify;text-justify:inter-word;font-style:italic'>%s</div><br>",
query_repositories[i]->arch[a],
query_repositories[i]->tag,
sqlite3_column_text(statement,1),
sqlite3_column_text(statement,4),
sqlite3_column_text(statement,5),
sqlite3_column_text(statement,6),
sqlite3_column_text(statement,7),
sqlite3_column_text(statement,8));
}
}
printf("\n");
/* if (search_sources) {
snprintf(sql, PATH_MAX, "SELECT * FROM sources WHERE name LIKE '%%%s%%' OR summary LIKE '%%%s%%' OR description LIKE '%%%s%%'", query, query, query);
for (i = 0; query_repositories[i] != NULL; i++) {
if (query_repositories[i]->db &&
(sqlite3_prepare_v2((sqlite3*)query_repositories[i]->db, sql, strlen(sql), &statement, NULL) == SQLITE_OK)) {
while (sqlite3_step(statement) == SQLITE_ROW) {
numresults++;
printf("<hr><br><div style='display:inline;color:black;background-color:red'> Source </div>&nbsp;"
"<div style='display:inline;color:black;background-color:yellow'> %s </div><br>"
"<b>%s</b> %s-%s<br>%s<br>Group: %s<br>License: %s</br>URL: %s<br><br>"
"<div style='text-align:justify;text-justify:inter-word;font-style:italic'>%s</div><br>",
query_repositories[i]->tag,
sqlite3_column_text(statement,1),
sqlite3_column_text(statement,4),
sqlite3_column_text(statement,5),
sqlite3_column_text(statement,6),
sqlite3_column_text(statement,8),
sqlite3_column_text(statement,11),
sqlite3_column_text(statement,10),
sqlite3_column_text(statement,9));
}
}
printf("\n");
}
}
printf("<hr><br>%d result(s) found.", numresults);*/
printf("]]></queryreply>");
sqlite3_close(ct->db);
ct->db = NULL;
}
void parse_request_variables(char *data) {
char *vartok, *valuetok;
struct configTag *ct = firstconfigtag;
int i;
while (1) {
vartok = (char *) strtok(data, "=");
if (data) data = NULL;
if (!vartok || (vartok[0] == '\0') ) break;
valuetok = (char *) strtok(NULL, "&");
if (!strcmp(vartok, "repository")) {
query_repository = valuetok;
} else if (!strcmp(vartok, "package")) {
query_package = valuetok;
} else if (!strcmp(vartok, "arch")) {
query_arch = valuetok;
} else if (!strcmp(vartok, "query")) {
query = url_decode(valuetok);
} else if (!strcmp(vartok, "search_milestone2")) {
search_milestone2 = (strstr(valuetok, "false") != valuetok);
} else if (!strcmp(vartok, "search_milestone1")) {
search_milestone1 = (strstr(valuetok, "false") != valuetok);
} else if (!strcmp(vartok, "search_devel")) {
search_devel = (strstr(valuetok, "false") != valuetok);
} else if (!strcmp(vartok, "search_i586")) {
search_i586 = (strstr(valuetok, "false") != valuetok);
} else if (!strcmp(vartok, "search_x86_64")) {
search_x86_64 = (strstr(valuetok, "false") != valuetok);
} else if (!strcmp(vartok, "search_arm")) {
search_arm = (strstr(valuetok, "false") != valuetok);
} else if (!strcmp(vartok, "search_sources")) {
search_sources = (strstr(valuetok, "false") != valuetok);
}
}
ct = firstconfigtag;
i = 0;
while (ct) {
if ((strstr(ct->tag, "devel") == ct->tag) && search_devel) query_repositories[i++] = ct;
ct = ct->next;
}
ct = firstconfigtag;
while (ct) {
if ((strstr(ct->tag, "milestone2") == ct->tag) && search_milestone2) query_repositories[i++] = ct;
ct = ct->next;
}
ct = firstconfigtag;
while (ct) {
if ((strstr(ct->tag, "milestone1") == ct->tag) && search_milestone1) query_repositories[i++] = ct;
ct = ct->next;
}
query_repositories[i++] = NULL;
}
int
main(int argc, char *argv[])
{
char *repository_dir = NULL;
// char *configfile = NULL;
char *data;
printf("Content-Type: text/xml;charset=utf-8\n\n<distroquery>");
firstconfigtag = read_configuration(DEFAULT_CONFIGFILE);
if (!firstconfigtag) {
fprintf(stderr, "Fatal error while parsing config file " DEFAULT_CONFIGFILE "; aborting.\n");
exit(1);
}
data = getenv("QUERY_STRING");
if (data && strlen(data)) {
parse_request_variables(data);
}
if (query_package && strlen(query_package)) {
printPackageData();
} else if (query && strlen(query)) {
printQueryData();
} else {
printInputForm();
}
printf("</distroquery>\n");
exit(0);
}