1 /*
2  *  Copyright (C) 2009-2015  Christian Heckendorf <heckendorfc@gmail.com>
3  *
4  *  This program is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "dbact.h"
19 #include "defs.h"
20 #include "util.h"
21 #include "admin.h"
22 #include "plugins/plugin.h"
23 
24 
harp_sqlite3_exec(sqlite3 * connection,const char * sql,int (* callback)(void *,int,char **,char **),void * arg,char ** errmsg)25 int harp_sqlite3_exec(sqlite3 *connection, const char *sql, int (*callback)(void*,int,char**,char**), void *arg, char **errmsg){
26 	return sqlite3_exec(connection,sql,callback,arg,errmsg);
27 }
28 
db_exec_file(char * file)29 int db_exec_file(char *file){
30 	FILE *ffd;
31 	int x=0,querysize=200,ret=0;
32 	char *query=malloc(sizeof(char)*querysize);
33 	char *err;
34 
35 	if(!query){
36 		debug(2,"Cannot malloc query");
37 		return 1;
38 	}
39 
40 	if((ffd=fopen(file,"r"))){
41 		while(fgets((query+x),querysize-x,ffd)){
42 			//fprintf(stderr,"Next batch\n%x %x ",*ptr, query[x]);
43 			for(;x<querysize-1 && query[x]!='\n' && query[x];x++);
44 			if(x<querysize-1){
45 				query[x]=' ';
46 				query[++x]=0;
47 			}
48 			if(!sqlite3_complete(query)){
49 				if(x>=querysize-100){
50 					querysize+=100;
51 					if(querysize<2000)
52 						query=realloc(query,querysize);
53 					else{
54 						debug(2,"Limit reached");
55 						ret=1;break;
56 					}
57 					if(!query){
58 						debug(2,"Not enough memory");
59 						ret=1;break;
60 					}
61 				}
62 				continue;
63 			}
64 
65 			if(harp_sqlite3_exec(conn,query,NULL,NULL,&err)!=SQLITE_OK){
66 				if(err){
67 					fprintf(stderr,"SQL Error: %s\n",err);
68 					sqlite3_free(err);
69 				}
70 				debug(2,"harp_sqlite3_exec error.");
71 				ret=1;break;
72 			}
73 			x=0;
74 		}
75 		fclose(ffd);
76 	}
77 	else{
78 		fprintf(stderr,"Cannot open file\n");
79 		ret=1;
80 	}
81 	free(query);
82 	return ret;
83 }
84 
upgrade_0()85 static void upgrade_0(){
86 	int i;
87 	int type;
88 	char query[200];
89 	char *newview="CREATE VIEW SongPubInfo AS \
90 SELECT Song.Title AS SongTitle, Song.Location AS Location, \
91 Album.Title AS AlbumTitle, Artist.Name AS ArtistName, \
92 Song.TypeID AS PluginID, Song.Length AS Length, \
93 Song.Rating AS Rating, \
94 Song.SongID AS SongID, Song.Track AS SongTrack \
95 FROM Song \
96 INNER JOIN Album ON Song.AlbumID=Album.AlbumID \
97 NATURAL JOIN AlbumArtist \
98 INNER JOIN Artist ON AlbumArtist.ArtistID=Artist.ArtistID";
99 
100 	for(i=0;i<PLUGIN_NULL;i++){
101 		if(plugin_head[i]==NULL)
102 			type=-1;
103 		else
104 			type=i;
105 
106 		sprintf(query,"UPDATE Song SET TypeID=%d WHERE TypeID=(SELECT TypeID FROM FileType WHERE Name='%s' LIMIT 1)",i,plugin_head[i]->name);
107 		harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
108 	}
109 
110 	harp_sqlite3_exec(conn,"DROP VIEW SongPubInfo",NULL,NULL,NULL);
111 	harp_sqlite3_exec(conn,newview,NULL,NULL,NULL);
112 }
113 
114 typedef void (*db_up)();
115 static db_up upgrade_db_from[]={
116 	upgrade_0,
117 };
118 
dbInit()119 unsigned int dbInit(){
120 	char temp[255];
121 	//strcpy(temp,DB);
122 	sprintf(temp,"%s%s",DB_PATH,DB);
123 	expand(temp);
124 	if(sqlite3_open_v2(temp,&conn,SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE,NULL)!=SQLITE_OK){
125 		printf("Database not found. Attempting to create\n");
126 		// Try creating
127 		strcpy(temp,DB_PATH);
128 		expand(temp);
129 		mkdir(temp,0700);
130 		sprintf(temp,"%s%s",DB_PATH,DB);
131 		expand(temp);
132 		if(sqlite3_open(temp,&conn)!=SQLITE_OK){
133 			printf("Database connection error: %s\n",sqlite3_errmsg(conn));
134 			return 0;
135 		}
136 		sprintf(temp,"%s/harp/create.sql",SHARE_PATH);
137 		if(db_exec_file(temp)){
138 			printf("Error creating database from file:\n\t%s\n",temp);
139 			sqlite3_close(conn);
140 			return 0;
141 		}
142 		/*
143 		if(autoAddPlugins()!=HARP_RET_OK){
144 			fprintf(stderr,"Automatic plugin loading failed.\nPlease add any installed plugins to the database with harp -a\n");
145 		}
146 		*/
147 	}
148 	else{
149 		/* Upgrade DB */
150 		int vnum=0;
151 		harp_sqlite3_exec(conn,"SELECT Version FROM DBInfo",uint_return_cb,&vnum,NULL);
152 		if(vnum!=DB_VERSION){
153 			sprintf(temp,"Upgrading database from %d to %d\n",vnum,DB_VERSION);
154 			debug(1,temp);
155 			while(vnum<DB_VERSION){
156 				upgrade_db_from[vnum++]();
157 			}
158 			harp_sqlite3_exec(conn,"CREATE TABLE IF NOT EXISTS DBInfo(Version integer primary key)",uint_return_cb,&vnum,NULL);
159 			harp_sqlite3_exec(conn,"DELETE FROM DBInfo",NULL,NULL,NULL);
160 			harp_sqlite3_exec(conn,"INSERT INTO DBInfo(Version) VALUES(" varstr(DB_VERSION) ")",NULL,NULL,NULL);
161 		}
162 	}
163 	return 1;
164 }
165 
dbiInit(struct dbitem * dbi)166 void dbiInit(struct dbitem *dbi){
167 	dbi->result=NULL;
168 	dbi->row=NULL;
169 	dbi->err=NULL;
170 }
171 
dbiClean(struct dbitem * dbi)172 void dbiClean(struct dbitem *dbi){
173 	if(dbi->row!=NULL){
174 		free(dbi->row);
175 		dbi->row=NULL;
176 	}
177 	if(dbi->result!=NULL){
178 		sqlite3_free_table(dbi->result);
179 		dbi->result=NULL;
180 	}
181 }
182 
fetch_row(struct dbitem * dbi)183 int fetch_row(struct dbitem *dbi){
184 	if(dbi->row_count==0)return 0;
185 
186 	int x;
187 	for(x=0;x<dbi->column_count;x++)
188 		dbi->row[x]=dbi->result[dbi->current_row+x];
189 
190 	x=dbi->current_row<(dbi->row_count+1)*dbi->column_count?1:0;
191 	dbi->current_row+=dbi->column_count;
192 	return x;
193 }
194 
fetch_row_at(struct dbitem * dbi,int index)195 int fetch_row_at(struct dbitem *dbi,int index){
196 	int x;
197 	if(index>=dbi->row_count || index<0)return 0;
198 	for(x=0;x<dbi->column_count;x++)
199 		dbi->row[x]=dbi->result[index+x];
200 	return 1;
201 }
202 
fetch_column_at(struct dbitem * dbi,int index)203 char ** fetch_column_at(struct dbitem *dbi, int index){
204 	int x;
205 	char **col;
206 	if(!(col=malloc(sizeof(char*)*dbi->row_count)))return NULL;
207 	index+=dbi->column_count;
208 	for(x=0;x<dbi->row_count;x++)
209 		col[x]=dbi->result[index+(x*dbi->column_count)];
210 	return col;
211 }
212 
doQuery(const char * querystr,struct dbitem * dbi)213 int doQuery(const char *querystr,struct dbitem *dbi){
214 	dbiClean(dbi);
215 	sqlite3_get_table(conn,querystr,&dbi->result,&dbi->row_count,&dbi->column_count,&dbi->err);
216 	if(dbi->err!=NULL){
217 		fprintf(stderr,"Database query error: %s\n",dbi->err);
218 		sqlite3_free(dbi->err);
219 		dbi->err=NULL;
220 		return -1;
221 	}
222 	if(!dbi->column_count)
223 		return sqlite3_changes(conn);
224 
225 	dbi->current_row=0;
226 	if(!(dbi->row=malloc(sizeof(char*)*dbi->column_count))){
227 		debug(2,"Malloc failed (dbi->row).");
228 		return -1;
229 	}
230 	fetch_row(dbi);
231 	return dbi->row_count;
232 }
233 
uint_return_cb(void * arg,int col_count,char ** row,char ** titles)234 int uint_return_cb(void *arg, int col_count, char **row, char **titles){
235 	*(unsigned int*)arg=(unsigned int)strtol(*row,NULL,10);
236 	return 0;
237 }
238 
str_return_cb(void * arg,int col_count,char ** row,char ** titles)239 int str_return_cb(void *arg, int col_count, char **row, char **titles){
240 	arg=strdup(*row);
241 	return 0;
242 }
243 
titlequery_titles_cb(void * data,int col_count,char ** row,char ** titles)244 static int titlequery_titles_cb(void *data, int col_count, char **row, char **titles){
245 	struct titlequery_data *arg=(struct titlequery_data*) data;
246 	int x,templen,len=arg->maxwidth+3;
247 	col_count--;
248 	for(x=0;x<col_count;x++){
249 		if(!arg->exception[x]){
250 			len=printf("[%.*s]",arg->maxwidth,titles[x]);
251 			printf("%*c",(arg->maxwidth+3)-len,' ');
252 		}
253 		else{
254 			templen=printf("[%s]",titles[x]);
255 			if(templen>arg->exlen[x])arg->exlen[x]=templen;
256 			printf("%*c",(arg->exlen[x]-templen)+1,' ');
257 		}
258 	}
259 	if(!arg->exception[x]){ // Ignore end spacing on final field
260 		printf("[%.*s]",arg->maxwidth,titles[x]);
261 	}
262 	else
263 		printf("[%s] ",titles[x]);
264 	printf("\n");
265 	return 1;
266 }
267 
titlequery_columns_cb(void * data,int col_count,char ** row,char ** titles)268 static int titlequery_columns_cb(void *data, int col_count, char **row, char **titles){
269 	struct titlequery_data *arg=(struct titlequery_data*) data;
270 	int x,templen;
271 	char *ptr;
272 	col_count--;
273 	for(x=0;x<col_count;x++){
274 		if(arg->exception[x]){
275 			for(ptr=row[x];*ptr;++ptr);
276 			templen=(ptr-row[x])+2;
277 			if(templen>arg->exlen[x])arg->exlen[x]=templen;
278 		}
279 	}
280 	return 0;
281 }
282 
titlequery_cb(void * data,int col_count,char ** row,char ** titles)283 static int titlequery_cb(void *data, int col_count, char **row, char **titles){
284 	struct titlequery_data *arg=(struct titlequery_data*) data;
285 	int x,templen,len=arg->maxwidth+3;
286 	col_count--;
287 	for(x=0;x<col_count;x++){
288 		if(!arg->exception[x]){
289 			len=printf("[%.*s]",arg->maxwidth,row[x]);
290 			printf("%*c",(arg->maxwidth+3)-len,' ');
291 		}
292 		else{
293 			templen=printf("[%s]",row[x]);
294 			printf("%*c",(arg->exlen[x]-templen)+1,' ');
295 		}
296 	}
297 	if(!arg->exception[x]){ // Ignore end spacing on final field
298 		printf("[%.*s]",arg->maxwidth,row[x]);
299 	}
300 	else
301 		printf("[%s] ",row[x]);
302 	printf("\n");
303 	arg->count++;
304 	return 0;
305 }
306 
doTitleQuery(const char * querystr,int * exception,int maxwidth)307 int doTitleQuery(const char *querystr,int *exception, int maxwidth){
308 	struct titlequery_data tqd;
309 
310 	int defexception[10];
311 	if(!exception){
312 		int x;
313 		for(x=1;x<10;x++)defexception[x]=listconf.exception;
314 		exception=defexception;
315 	}
316 
317 	tqd.count=0;
318 	tqd.exception=exception;
319 	tqd.maxwidth=maxwidth;
320 	tqd.exlen=calloc(10,sizeof(int));
321 
322 	harp_sqlite3_exec(conn,querystr,titlequery_columns_cb,&tqd,NULL);
323 	harp_sqlite3_exec(conn,querystr,titlequery_titles_cb,&tqd,NULL);
324 	harp_sqlite3_exec(conn,querystr,titlequery_cb,&tqd,NULL);
325 
326 	free(tqd.exlen);
327 	return tqd.count;
328 }
329 
batch_tempplaylistsong_insert_cb(void * arg,int col_count,char ** row,char ** titles)330 int batch_tempplaylistsong_insert_cb(void *arg, int col_count, char **row, char **titles){
331 	struct insert_tps_arg *data=(struct insert_tps_arg*)arg;
332 
333 	sprintf(data->query,"INSERT INTO TempPlaylistSong(SongID,\"Order\") VALUES(%s,%d)",*row,data->order);
334 	harp_sqlite3_exec(conn,data->query,NULL,NULL,NULL);
335 
336 	data->order++;
337 	return 0;
338 }
339 
createTempPlaylistSong()340 void createTempPlaylistSong(){
341 	harp_sqlite3_exec(conn,"CREATE TEMP TABLE IF NOT EXISTS TempPlaylistSong( PlaylistSongID integer primary key, SongID integer not null, \"Order\" integer NOT NULL)",NULL,NULL,NULL);
342 }
343