1 /*
2  *  Copyright (C) 2014-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 "edit_shell.h"
19 #include "dbact.h"
20 #include "insert.h"
21 
22 int yyparse();
23 TokenList *tlist;
24 extern commandline_t *fullcmd;
25 typedef int(*seltypefun)(commandline_t*);
26 typedef int(*acttypefun)(command_t*,command_t*);
27 
28 static char *seltypes[]={
29 	"song",
30 	"album",
31 	"artist",
32 	"playlist",
33 	"tag",
34 	NULL
35 };
printEditSelect(int id,int type)36 void printEditSelect(int id, int type){
37 	char query[100];
38 	fprintf(stderr,"type: %d %s\n",type,seltypes[type]);
39 	sprintf(query,"select SelectID from TempSelect where TempID=%d",id);
40 	doTitleQuery(query,NULL,20);
41 }
42 
43 struct selgroup{
44 	acttypefun func;
45 	char *name;
46 };
47 
runGenericEditAction(commandline_t * cmd,struct selgroup * selactlist)48 static int runGenericEditAction(commandline_t *cmd,struct selgroup *selactlist){
49 	int i;
50 	command_t *act;
51 
52 	for(act=cmd->actions;act;act=act->next){
53 		for(i=0;selactlist[i].name;i++){
54 			if(strcmp(selactlist[i].name,act->cmd->word)==0){
55 				selactlist[i].func(cmd->selector,act);
56 				break;
57 			}
58 		}
59 	}
60 
61 	return HARP_RET_ERR;
62 }
63 
listSongs(command_t * sel,command_t * act)64 static int listSongs(command_t *sel, command_t *act){
65 	char query[300];
66 	int exception[10];
67 	int i;
68 
69 	for(i=0;i<10;i++)exception[i]=i<5?1:listconf.exception;
70 	sprintf(query,"SELECT SongID, SongTitle, SongTrack, Location, AlbumTitle AS Album, ArtistName AS Artist FROM SongPubInfo WHERE SongID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",sel->tlid);
71 	doTitleQuery(query,exception,listconf.maxwidth);
72 
73 	return HARP_RET_OK;
74 }
75 
editSongTitle(command_t * sel,command_t * act)76 static int editSongTitle(command_t *sel, command_t *act){
77 	char query[300];
78 
79 	sprintf(query,"UPDATE Song SET Title='%s' WHERE SongID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",act->args->words->word,sel->tlid);
80 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
81 
82 	return HARP_RET_OK;
83 }
84 
deleteSong(command_t * sel,command_t * act)85 static int deleteSong(command_t *sel, command_t *act){
86 	char query[300];
87 
88 	sprintf(query,"DELETE FROM Song WHERE SongID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",sel->tlid);
89 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
90 
91 	return HARP_RET_OK;
92 }
93 
editSongAlbumArtist(command_t * sel,command_t * act)94 static int editSongAlbumArtist(command_t *sel, command_t *act){
95 	char query[300];
96 	int artistid,albumid;
97 	struct dbitem dbi;
98 	dbiInit(&dbi);
99 
100 	if(act->args->next==NULL){
101 		fprintf(stderr,"albumartist: Two arguments required for this action.\n");
102 		return HARP_RET_ERR;
103 	}
104 
105 	if(act->args->next->words->flag==WORD_DEFAULT)
106 		artistid=strtol(act->args->next->words->word,NULL,10);
107 	else
108 		artistid=getArtist(act->args->next->words->word);
109 
110 	if(act->args->words->flag==WORD_DEFAULT)
111 		albumid=strtol(act->args->words->word,NULL,10);
112 	else
113 		albumid=getAlbum(act->args->words->word,artistid);
114 
115 	sprintf(query,"UPDATE Song SET AlbumID=%d WHERE SongID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",albumid,sel->tlid);
116 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
117 
118 	return HARP_RET_OK;
119 }
120 
songActivation(command_t * sel,command_t * act)121 static int songActivation(command_t *sel, command_t *act){
122 	char query[300];
123 
124 	/*TODO: test argument to disable toggle */
125 	sprintf(query,"UPDATE Song SET Active=NOT(Active) WHERE SongID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",sel->tlid);
126 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
127 
128 	return HARP_RET_OK;
129 }
130 
editSongLocation(command_t * sel,command_t * act)131 static int editSongLocation(command_t *sel, command_t *act){
132 	char query[300];
133 
134 	sprintf(query,"UPDATE Song SET Location='%s' WHERE SongID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",act->args->words->word,sel->tlid);
135 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
136 
137 	return HARP_RET_OK;
138 }
139 
editSongTrack(command_t * sel,command_t * act)140 static int editSongTrack(command_t *sel, command_t *act){
141 	char query[300];
142 
143 	sprintf(query,"UPDATE Song SET Track=%s WHERE SongID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",act->args->words->word,sel->tlid);
144 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
145 
146 	return HARP_RET_OK;
147 }
148 
149 static struct selgroup selsongacts[]={
150 	{listSongs,"list"},
151 	{editSongTitle,"title"},
152 	{editSongTrack,"track"},
153 	{editSongLocation,"location"},
154 	{editSongAlbumArtist,"albumArtist"},
155 	{deleteSong,"delete"},
156 	{songActivation,"activate"},
157 	{NULL,NULL}
158 };
runSongEditAction(commandline_t * cmd)159 static int runSongEditAction(commandline_t *cmd){
160 	return runGenericEditAction(cmd,selsongacts);
161 }
162 
listAlbums(command_t * sel,command_t * act)163 static int listAlbums(command_t *sel, command_t *act){
164 	char query[300];
165 	int exception[10];
166 	int i;
167 
168 	for(i=0;i<10;i++)exception[i]=i<5?1:listconf.exception;
169 	sprintf(query,"SELECT AlbumID, Title, \"Date\" FROM Album WHERE AlbumID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",sel->tlid);
170 	doTitleQuery(query,exception,listconf.maxwidth);
171 
172 	return HARP_RET_OK;
173 }
editAlbumDate(command_t * sel,command_t * act)174 static int editAlbumDate(command_t *sel, command_t *act){
175 	char query[300];
176 
177 	sprintf(query,"UPDATE Album SET Date=%s WHERE AlbumID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",act->args->words->word,sel->tlid);
178 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
179 
180 	return HARP_RET_OK;
181 }
182 
editAlbumTitle(command_t * sel,command_t * act)183 static int editAlbumTitle(command_t *sel, command_t *act){
184 	char query[300];
185 
186 	sprintf(query,"UPDATE Album SET Title='%s' WHERE AlbumID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",act->args->words->word,sel->tlid);
187 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
188 
189 	return HARP_RET_OK;
190 }
191 
editAlbumArtist(command_t * sel,command_t * act)192 static int editAlbumArtist(command_t *sel, command_t *act){
193 	char query[300];
194 	int artistid;
195 
196 	if(act->args->words->flag==WORD_DEFAULT)
197 		artistid=strtol(act->args->words->word,NULL,10);
198 	else
199 		artistid=getArtist(act->args->words->word);
200 
201 	sprintf(query,"UPDATE AlbumArtist SET ArtistID=%d WHERE AlbumID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",artistid,sel->tlid);
202 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
203 
204 	return HARP_RET_OK;
205 }
206 
207 static struct selgroup selalbumacts[]={
208 	{listAlbums,"list"},
209 	{editAlbumTitle,"title"},
210 	{editAlbumArtist,"artist"},
211 	{editAlbumDate,"date"},
212 	{NULL,NULL}
213 };
runAlbumEditAction(commandline_t * cmd)214 static int runAlbumEditAction(commandline_t *cmd){
215 	return runGenericEditAction(cmd,selalbumacts);
216 }
217 
listArtists(command_t * sel,command_t * act)218 static int listArtists(command_t *sel, command_t *act){
219 	char query[300];
220 	int exception[10];
221 	int i;
222 
223 	for(i=0;i<10;i++)exception[i]=i<5?1:listconf.exception;
224 	sprintf(query,"SELECT ArtistID, Name FROM Artist WHERE ArtistID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",sel->tlid);
225 	doTitleQuery(query,exception,listconf.maxwidth);
226 
227 	return HARP_RET_OK;
228 }
229 
editArtistName(command_t * sel,command_t * act)230 static int editArtistName(command_t *sel, command_t *act){
231 	char query[300];
232 
233 	sprintf(query,"UPDATE Artist SET Name='%s' WHERE ArtistID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",act->args->words->word,sel->tlid);
234 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
235 
236 	return HARP_RET_OK;
237 }
238 
239 static struct selgroup selartistacts[]={
240 	{listArtists,"list"},
241 	{editArtistName,"name"},
242 	{NULL,NULL}
243 };
runArtistEditAction(commandline_t * cmd)244 static int runArtistEditAction(commandline_t *cmd){
245 	return runGenericEditAction(cmd,selartistacts);
246 }
247 
listPlaylists(command_t * sel,command_t * act)248 static int listPlaylists(command_t *sel, command_t *act){
249 	char query[300];
250 	int exception[10];
251 	int i;
252 
253 	for(i=0;i<10;i++)exception[i]=i<5?1:listconf.exception;
254 	sprintf(query,"SELECT PlaylistID, Title FROM Playlist WHERE PlaylistID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",sel->tlid);
255 	doTitleQuery(query,exception,listconf.maxwidth);
256 
257 	return HARP_RET_OK;
258 }
259 
listPlaylistContents(command_t * sel,command_t * act)260 static int listPlaylistContents(command_t *sel, command_t *act){
261 	char query[300];
262 	int exception[10];
263 	int i;
264 
265 	for(i=0;i<10;i++)exception[i]=i<5?1:listconf.exception;
266 	sprintf(query,"SELECT PlaylistID, \"Order\" AS \"#\", SongID,SongTitle,AlbumTitle,ArtistName FROM PlaylistSong NATURAL JOIN SongPubInfo WHERE PlaylistID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d) ORDER BY PlaylistID,\"Order\"",sel->tlid);
267 	doTitleQuery(query,exception,listconf.maxwidth);
268 
269 	return HARP_RET_OK;
270 }
271 
editPlaylistName(command_t * sel,command_t * act)272 static int editPlaylistName(command_t *sel, command_t *act){
273 	char query[300];
274 
275 	sprintf(query,"UPDATE Playlist SET Name='%s' WHERE PlaylistID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",act->args->words->word,sel->tlid);
276 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
277 
278 	return HARP_RET_OK;
279 }
280 
deletePlaylist(command_t * sel,command_t * act)281 static int deletePlaylist(command_t *sel, command_t *act){
282 	char query[300];
283 
284 	sprintf(query,"DELETE FROM PlaylistSong WHERE PlaylistID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",sel->tlid);
285 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
286 	sprintf(query,"DELETE FROM Playlist WHERE PlaylistID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",sel->tlid);
287 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
288 
289 	return HARP_RET_OK;
290 }
291 
editPlaylistOrder(command_t * sel,command_t * act)292 static int editPlaylistOrder(command_t *sel, command_t *act){
293 	char query[300];
294 	int oldO,newO;
295 
296 	if(act->args->next==NULL){
297 		fprintf(stderr,"order: Two arguments required for this action.\n");
298 		return HARP_RET_ERR;
299 	}
300 
301 	oldO=strtol(act->args->words->word,NULL,10);
302 	newO=strtol(act->args->next->words->word,NULL,10);
303 
304 	if(oldO<newO)
305 		harp_sqlite3_exec(conn,"CREATE TEMPORARY TRIGGER PLIMv AFTER UPDATE ON PlaylistSong BEGIN "
306 			"UPDATE PlaylistSong SET \"Order\"=\"Order\"-1 WHERE PlaylistID=OLD.PlaylistID AND \"Order\" BETWEEN OLD.\"Order\" AND NEW.\"Order\" AND PlaylistSongID!=OLD.PlaylistSongID;"
307 			"END",NULL,NULL,NULL);
308 	else
309 		harp_sqlite3_exec(conn,"CREATE TEMPORARY TRIGGER PLIMv AFTER UPDATE ON PlaylistSong BEGIN "
310 			"UPDATE PlaylistSong SET \"Order\"=\"Order\"+1 WHERE PlaylistID=OLD.PlaylistID AND \"Order\" BETWEEN NEW.\"Order\" AND OLD.\"Order\" AND PlaylistSongID!=OLD.PlaylistSongID;"
311 			"END",NULL,NULL,NULL);
312 
313 	sprintf(query,"UPDATE PlaylistSong SET \"Order\"=%d WHERE \"Order\"=%d AND PlaylistID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",newO,oldO,sel->tlid);
314 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
315 
316 	harp_sqlite3_exec(conn,"DROP TRIGGER PLIMv",NULL,NULL,NULL);
317 
318 	return HARP_RET_OK;
319 }
320 
editPlaylistAdd(command_t * sel,command_t * act)321 static int editPlaylistAdd(command_t *sel, command_t *act){
322 	char query[300];
323 	char *songs_start,*songs_end;
324 
325 	if(act->args->next==NULL){
326 		fprintf(stderr,"add: Two arguments required for this action.\n");
327 		return HARP_RET_ERR;
328 	}
329 
330 	if(act->args->words->flag==WORD_DEFAULT){
331 		songs_start="SongID=";
332 		songs_end="";
333 	}
334 	else{
335 		songs_start="Song.Title LIKE '%%";
336 		songs_end="%%'";
337 	}
338 
339 	sprintf(query,"UPDATE PlaylistSong SET \"Order\"=\"Order\"+1 WHERE \"Order\">=%s AND PlaylistID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d AND SelectID IN (SELECT PlaylistID FROM PlaylistSong WHERE \"Order\"=%s))",act->args->next->words->word,sel->tlid,act->args->next->words->word);
340 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
341 
342 	sprintf(query,"INSERT INTO PlaylistSong (SongID,PlaylistID,\"Order\") SELECT SongID,PlaylistID,%s FROM Song,Playlist WHERE %s%s%s AND PlaylistID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",act->args->next->words->word,songs_start,act->args->words->word,songs_end,sel->tlid);
343 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
344 
345 	return HARP_RET_OK;
346 }
347 
editPlaylistRemove(command_t * sel,command_t * act)348 static int editPlaylistRemove(command_t *sel, command_t *act){
349 	char query[300];
350 	char *songs_start,*songs_end;
351 
352 	if(strcmp(act->cmd->word,"removeOrder")==0){
353 		songs_start="\"Order\"=";
354 		songs_end="";
355 	}
356 	else{
357 		if(act->args->words->flag==WORD_DEFAULT){
358 			songs_start="SongID=";
359 			songs_end="";
360 		}
361 		else{
362 			songs_start="Song.Title LIKE '%%";
363 			songs_end="%%'";
364 		}
365 	}
366 
367 	harp_sqlite3_exec(conn,"CREATE TEMPORARY TRIGGER PLIDel AFTER DELETE ON PlaylistSong BEGIN "
368 			"UPDATE PlaylistSong SET \"Order\"=\"Order\"-1 WHERE PlaylistID=OLD.PlaylistID AND \"Order\">OLD.\"Order\";"
369 			"END",NULL,NULL,NULL);
370 
371 	//sprintf(query,"DELETE FROM PlaylistSong (SongID,PlaylistID,\"Order\") SELECT SongID,PlaylistID,%s FROM Song,Playlist WHERE %s%s%s AND PlaylistID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",act->args->next->words->word,songs_start,act->args->words->word,songs_end,sel->tlid);
372 	sprintf(query,"DELETE FROM PlaylistSong WHERE PlaylistSongID IN (SELECT PlaylistSongID FROM PlaylistSong NATURAL JOIN Song WHERE %s%s%s AND PlaylistID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d))",songs_start,act->args->words->word,songs_end,sel->tlid);
373 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
374 
375 	harp_sqlite3_exec(conn,"DROP TRIGGER PLIDel",NULL,NULL,NULL);
376 
377 	return HARP_RET_OK;
378 }
379 
380 static struct selgroup selplaylistacts[]={
381 	{listPlaylists,"list"},
382 	{listPlaylistContents,"contents"},
383 	{editPlaylistName,"name"},
384 	{deletePlaylist,"delete"},
385 	{editPlaylistOrder,"order"},
386 	{editPlaylistAdd,"add"},
387 	{editPlaylistRemove,"removeOrder"},
388 	{editPlaylistRemove,"removeSong"},
389 	{NULL,NULL}
390 };
runPlaylistEditAction(commandline_t * cmd)391 static int runPlaylistEditAction(commandline_t *cmd){
392 	char query[200];
393 	sprintf(query,"DELETE FROM TempSelect WHERE SelectID=1 AND TempID=%d",cmd->selector->tlid);
394 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL); // Failsafe, disable editing of library directly
395 	return runGenericEditAction(cmd,selplaylistacts);
396 }
397 
listTags(command_t * sel,command_t * act)398 static int listTags(command_t *sel, command_t *act){
399 	char query[300];
400 	int exception[10];
401 	int i;
402 
403 	for(i=0;i<10;i++)exception[i]=i<5?1:listconf.exception;
404 	sprintf(query,"SELECT TagID, Name FROM Tag WHERE TagID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",sel->tlid);
405 	doTitleQuery(query,exception,listconf.maxwidth);
406 
407 	return HARP_RET_OK;
408 }
409 
listTagContents(command_t * sel,command_t * act)410 static int listTagContents(command_t *sel, command_t *act){
411 	char query[300];
412 	int exception[10];
413 	int i;
414 
415 	for(i=0;i<10;i++)exception[i]=i<5?1:listconf.exception;
416 	sprintf(query,"SELECT TagID,SongID,SongTitle,AlbumTitle,ArtistName FROM SongTag NATURAL JOIN SongPubInfo WHERE TagID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d) ORDER BY TagID",sel->tlid);
417 	doTitleQuery(query,exception,listconf.maxwidth);
418 
419 	return HARP_RET_OK;
420 }
421 
editTagName(command_t * sel,command_t * act)422 static int editTagName(command_t *sel, command_t *act){
423 	char query[300];
424 
425 	sprintf(query,"UPDATE Tag SET Name='%s' WHERE TagID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",act->args->words->word,sel->tlid);
426 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
427 
428 	return HARP_RET_OK;
429 }
430 
deleteTag(command_t * sel,command_t * act)431 static int deleteTag(command_t *sel, command_t *act){
432 	char query[300];
433 
434 	sprintf(query,"DELETE FROM SongTag WHERE TagID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",sel->tlid);
435 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
436 	sprintf(query,"DELETE FROM Tag WHERE TagID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",sel->tlid);
437 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
438 
439 	return HARP_RET_OK;
440 }
441 
editTagAdd(command_t * sel,command_t * act)442 static int editTagAdd(command_t *sel, command_t *act){
443 	char query[300];
444 	char *songs_start,*songs_end;
445 
446 	if(act->tlid>=0){
447 		sprintf(query,"INSERT INTO SongTag (SongID,TagID) SELECT SongID,TagID FROM Song,Tag WHERE Song.SongID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d) AND TagID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",act->tlid,sel->tlid);
448 		harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
449 		return HARP_RET_OK;
450 	}
451 	if(act->args->words->flag==WORD_DEFAULT){
452 		songs_start="SongID=";
453 		songs_end="";
454 	}
455 	else{
456 		songs_start="Song.Title LIKE '%%";
457 		songs_end="%%'";
458 	}
459 
460 	sprintf(query,"INSERT INTO SongTag (SongID,TagID) SELECT SongID,TagID FROM Song,Tag WHERE %s%s%s AND TagID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",songs_start,act->args->words->word,songs_end,sel->tlid);
461 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
462 
463 	return HARP_RET_OK;
464 }
465 
editTagRemove(command_t * sel,command_t * act)466 static int editTagRemove(command_t *sel, command_t *act){
467 	char query[300];
468 	char *songs_start,*songs_end;
469 
470 	if(act->args->words->flag==WORD_DEFAULT){
471 		songs_start="SongID=";
472 		songs_end="";
473 	}
474 	else{
475 		songs_start="Song.Title LIKE '%%";
476 		songs_end="%%'";
477 	}
478 
479 	sprintf(query,"DELETE FROM SongTag WHERE %s%s%s AND TagID IN (SELECT SelectID FROM TempSelect WHERE TempID=%d)",songs_start,act->args->words->word,songs_end,sel->tlid);
480 	harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
481 
482 	return HARP_RET_OK;
483 }
484 
485 static struct selgroup seltagacts[]={
486 	{listTags,"list"},
487 	{listTagContents,"contents"},
488 	{editTagName,"name"},
489 	{deleteTag,"delete"},
490 	{editTagAdd,"add"},
491 	{editTagRemove,"remove"},
492 	{NULL,NULL}
493 };
runTagEditAction(commandline_t * cmd)494 static int runTagEditAction(commandline_t *cmd){
495 	return runGenericEditAction(cmd,seltagacts);
496 }
497 
498 static seltypefun selacts[]={
499 	runSongEditAction,
500 	runAlbumEditAction,
501 	runArtistEditAction,
502 	runPlaylistEditAction,
503 	runTagEditAction,
504 	NULL
505 };
runEditAction(commandline_t * cmd)506 static int runEditAction(commandline_t *cmd){
507 	if(cmd->selector->tltype>=0 && cmd->selector->tltype<SEL_NULL){
508 		return selacts[cmd->selector->tltype](cmd);
509 	}
510 	return HARP_RET_ERR;
511 }
512 
cleanOrphans()513 static void cleanOrphans(){
514 	// Clean orphaned albums
515 	harp_sqlite3_exec(conn,"DELETE FROM Album WHERE AlbumID NOT IN (SELECT AlbumID FROM Song)",NULL,NULL,NULL);
516 	// Clean orphaned albumartists
517 	harp_sqlite3_exec(conn,"DELETE FROM AlbumArtist WHERE AlbumID NOT IN (SELECT AlbumID FROM Song)",NULL,NULL,NULL);
518 	// Clean orphaned artists
519 	harp_sqlite3_exec(conn,"DELETE FROM Artist WHERE ArtistID NOT IN (SELECT ArtistID FROM AlbumArtist)",NULL,NULL,NULL);
520 }
521 
editShell()522 int editShell(){
523 	char src[512];
524 	int ret;
525 
526 	if(!arglist[AEDIT].subarg){
527 		printf("Edit> ");
528 		while(fgets(src,512,stdin)){
529 			tlist = lex(src);
530 			fullcmd=NULL;
531 			ret=yyparse();
532 
533 			if(!ret)
534 				ret=runEditAction(fullcmd);
535 			else
536 				ret=HARP_RET_ERR;
537 
538 			printf("Edit> ");
539 		}
540 	}
541 	else{
542 		tlist = lex(arglist[AEDIT].subarg);
543 		fullcmd=NULL;
544 		ret=yyparse();
545 
546 		if(!ret)
547 			ret=runEditAction(fullcmd);
548 		else
549 			ret=HARP_RET_ERR;
550 	}
551 
552 	cleanOrphans();
553 
554 	return ret;
555 }
556