[mw-devel] MW3 r1110 - in trunk: src talkhelp

psycodom at sucs.org psycodom at sucs.org
Thu Nov 26 13:03:40 GMT 2009


Author: psycodom
Date: 2009-11-26 13:03:39 +0000 (Thu, 26 Nov 2009)
New Revision: 1110

Added:
   trunk/src/uri.c
   trunk/src/uri.h
   trunk/talkhelp/uri
Modified:
   trunk/src/Makefile
   trunk/src/chattable.c
   trunk/src/completion.c
   trunk/src/js.c
   trunk/src/log.c
   trunk/src/sqlite.c
   trunk/src/talker.c
   trunk/src/talker.h
   trunk/src/talker_privs.c
Log:
Adds a .uri command to allow editing/listing of the mwuri db
Also fixes a couple of bugs encountered along the way (notably a strdup(NULL) in sqlite.c



Modified: trunk/src/Makefile
===================================================================
--- trunk/src/Makefile	2009-11-22 16:36:02 UTC (rev 1109)
+++ trunk/src/Makefile	2009-11-26 13:03:39 UTC (rev 1110)
@@ -99,7 +99,7 @@
 topten.o sort.o tidyup.o gags.o script_inst.o script.o\
 incoming.o command.o chattable.o alias.o frl.o hash.o vars.o expand.o\
 mud.o mudtable.o files.o completion.o sentinel.o iconv.o gagtable.o \
-js.o sqlite.o ipc.o log.o
+js.o sqlite.o ipc.o log.o uri.o
 	$(CC) $(LDFLAGS) $(LDLIBS) -o $@ $^
 
 del_user: del_user.o perms.o strings.o

Modified: trunk/src/chattable.c
===================================================================
--- trunk/src/chattable.c	2009-11-22 16:36:02 UTC (rev 1109)
+++ trunk/src/chattable.c	2009-11-26 13:03:39 UTC (rev 1110)
@@ -74,6 +74,7 @@
 {"ungag"	,0x0002	,1, "Usage: ungag <user>", "Remove the Gag on the user", t_ungag, 1},
 {"unignore"	,0x0000	,1, "Usage: unignore <user>", "Stop filtering user out so you can hear them", t_unignore, 1},
 {"unprotect"	,0x0020	,1, "Usage: unprotect <user>", "Remove protection from user", t_unprotect, 1},
+{"uri"		,0x0000	,0, "Usage: uri [list [all|username] [n] | delete <id> | nsfw <id> | membersonly <id> | anonymous <id> | displaymode <full|short>]", "View/Edit the uris in the mwuri database", t_uri, 1},
 {"variables"	,0x0200	,0, "Usage: variables [mask]", "List script variables + contents [or starting with mask]", t_showvars, 1},
 {"what"		,0x0000	,0, "Usage: what", "See peoples status", t_what, 1},
 {"whisper"	,0x0000	,2, "Usage: whisper <user> <message>", "Send a message to a single user", t_whisper, 1},

Modified: trunk/src/completion.c
===================================================================
--- trunk/src/completion.c	2009-11-22 16:36:02 UTC (rev 1109)
+++ trunk/src/completion.c	2009-11-26 13:03:39 UTC (rev 1110)
@@ -2,6 +2,7 @@
 #include "bb.h"
 #include "proto.h"
 #include "script.h"
+#include "uri.h"
 
 /*
   modes:	0 - commands
@@ -58,6 +59,8 @@
 {"ungag"	,1	,1	,1	,part_who_talk},
 {"unignore"	,1	,1	,-1	,part_who},
 {"unprotect"	,1	,1	,1	,part_who_talk},
+{"uri"		,1	,2	,2	,uri_arg_tc},
+{"uri"		,1	,1	,1	,uri_action_tc},
 {"whisper"	,1	,1	,1	,part_who_talk},
 {"zod"		,1	,1	,1	,part_who_talk},
 

Modified: trunk/src/js.c
===================================================================
--- trunk/src/js.c	2009-11-22 16:36:02 UTC (rev 1109)
+++ trunk/src/js.c	2009-11-26 13:03:39 UTC (rev 1110)
@@ -758,9 +758,14 @@
 //		printf("dbdata_to_jsarray: data @ %p -", (void *)data->field[i]);
 //		printf("%s", data->field[i]);
 //		printf(" -> JSString @ %p\n", (void *)jsstr);
-		jsstr = JS_NewStringCopyZ(cx, data->field[i]);
-		jv = STRING_TO_JSVAL(jsstr);
+		if(data->field[i] != NULL) {
+			jsstr = JS_NewStringCopyZ(cx, data->field[i]);
+			jv = STRING_TO_JSVAL(jsstr);
+		} else {
+			jv = JSVAL_NULL;
+		}
 		JS_SetElement(cx, jsdata, i, &jv);
+
 	}
 	JS_RemoveRoot(cx, jsdata);
 

Modified: trunk/src/log.c
===================================================================
--- trunk/src/log.c	2009-11-22 16:36:02 UTC (rev 1109)
+++ trunk/src/log.c	2009-11-26 13:03:39 UTC (rev 1110)
@@ -26,7 +26,7 @@
 #include "js.h"
 #include "files.h"
 #include "log.h"
-
+#include "uri.h"
 #include "rooms.h"
 #include "ipc.h"
 #include "sqlite.h"
@@ -65,9 +65,6 @@
 	uint32_t flags;
 };
 
-#define URLFLAG_NSFW	0x0001
-#define URLFLAG_ANON	0x0002
-#define URLFLAG_SUCS	0x0004
 
 struct uripatt urilist[] = {
 	{"^http://$", 		REG_ICASE, NULL, IGNORE, 0},
@@ -313,29 +310,16 @@
 	block_free(body);
 
 	/* fishing mission complete, store the results */
-
-	flags[0]=0;
-	if (uri->flags & URLFLAG_NSFW) {
-		int n = strlen(flags);
-		snprintf(&flags[n], sizeof(flags)-n, "%snsfw", flags[0]==0?"":" ");
-	}
-	if (uri->flags & URLFLAG_ANON) {
-		int n = strlen(flags);
-		snprintf(&flags[n], sizeof(flags)-n, "%sanon", flags[0]==0?"":" ");
-	}
-	if (uri->flags & URLFLAG_SUCS) {
-		int n = strlen(flags);
-		snprintf(&flags[n], sizeof(flags)-n, "%ssucs", flags[0]==0?"":" ");
-	}
-
-	snprintf(path,sizeof(path),"%s/mwuri.db", STATEDIR);
-	char *query = sqlite3_mprintf("INSERT INTO mwuri (user, url, added, flags, title, tags) values (%Q,%Q,datetime('now'),%Q,%Q,%Q)", user->name, url, (uri->flags&URLFLAG_NSFW)?"nsfw":NULL, title, deli==NULL?NULL:deli->p_buffer);
-	res = db_query(path, query, 1);
+	
+	uri_make_flags_str(uri->flags, flags, sizeof(flags));
+	
+	char *query = sqlite3_mprintf("INSERT INTO mwuri (user, url, added, flags, title, tags) values (%Q,%Q,datetime('now'),%Q,%Q,%Q)", user->name, url, flags, title, deli==NULL?NULL:deli->p_buffer);
+	res = db_query(MWURI_DB, query, 1);
 	if (res == NULL) {
-		res = db_query(path, "CREATE TABLE mwuri (id INTEGER PRIMARY KEY AUTOINCREMENT, user text, url text, added text, flags text, title text, tags text )", 0);
+		res = db_query(MWURI_DB, "CREATE TABLE mwuri (id INTEGER PRIMARY KEY AUTOINCREMENT, user text, url text, added text, flags text, title text, tags text )", 0);
 		if (res != NULL) {
 			db_free(res);
-			res = db_query(path, query, 0);
+			res = db_query(MWURI_DB, query, 0);
 		}
 	}
 	db_free(res);
@@ -352,17 +336,15 @@
 static void *file_tag(void * data) 
 {
 	struct taghit *tag = data;
-	char path[1024];
 	struct db_result *res;
 
-	snprintf(path,sizeof(path),"%s/mwuri.db", STATEDIR);
 	char *query = sqlite3_mprintf("INSERT INTO mwtag (user, tag, added, line) values (%Q,%Q,datetime('now'),%Q)", user->name, tag->tag, tag->line);
-	res = db_query(path, query, 1);
+	res = db_query(MWURI_DB, query, 1);
 	if (res == NULL) {
-		res = db_query(path, "CREATE TABLE mwtag (id INTEGER PRIMARY KEY AUTOINCREMENT, user text, tag text, added text, line text )", 0);
+		res = db_query(MWURI_DB, "CREATE TABLE mwtag (id INTEGER PRIMARY KEY AUTOINCREMENT, user text, tag text, added text, line text )", 0);
 		if (res != NULL) {
 			db_free(res);
-			res = db_query(path, query, 0);
+			res = db_query(MWURI_DB, query, 0);
 		}
 	}
 	db_free(res);
@@ -376,17 +358,15 @@
 /* store the doing/status string in the db */
 void catchdoing(const char *what)
 {
-	char path[1024];
 	struct db_result *res;
 
-	snprintf(path,sizeof(path),"%s/mwuri.db", STATEDIR);
 	char *query = sqlite3_mprintf("INSERT INTO mwdoing (user, added, doing) values (%Q,datetime('now'),%Q)", user->name, what);
-	res = db_query(path, query, 1);
+	res = db_query(MWURI_DB, query, 1);
 	if (res == NULL) {
-		res = db_query(path, "CREATE TABLE mwdoing (id INTEGER PRIMARY KEY AUTOINCREMENT, user text, added text, doing text )", 0);
+		res = db_query(MWURI_DB, "CREATE TABLE mwdoing (id INTEGER PRIMARY KEY AUTOINCREMENT, user text, added text, doing text )", 0);
 		if (res != NULL) {
 			db_free(res);
-			res = db_query(path, query, 0);
+			res = db_query(MWURI_DB, query, 0);
 		}
 	}
 	db_free(res);

Modified: trunk/src/sqlite.c
===================================================================
--- trunk/src/sqlite.c	2009-11-22 16:36:02 UTC (rev 1109)
+++ trunk/src/sqlite.c	2009-11-26 13:03:39 UTC (rev 1110)
@@ -60,7 +60,13 @@
 	/* Copy the data in and attach it */
 	ndata = malloc(sizeof(*ndata));
 	ndata->field = calloc(ncols+1, sizeof(char *));
-	for (i=0;i<ncols;i++) ndata->field[i] = strdup(row[i]);
+	for (i=0;i<ncols;i++) {
+		if(row[i] != NULL) {
+			ndata->field[i] = strdup(row[i]);
+		} else {
+			ndata->field[i] = NULL;
+		}
+	}
 	ndata->row = query->rows - 1;
 	ndata->next = query->data;
 	query->data = ndata;
@@ -249,8 +255,11 @@
 	/* throw away the returned rows */
 	ndata = result->data;
 	while (ndata != NULL) {
-		for (i=0;i<result->cols;i++)
-			free(ndata->field[i]);
+		for (i=0;i<result->cols;i++) {
+			if(ndata->field[i]) {
+				free(ndata->field[i]);
+			}
+		}
 		free(ndata->field);
 		nnext = ndata->next;
 		free(ndata);

Modified: trunk/src/talker.c
===================================================================
--- trunk/src/talker.c	2009-11-22 16:36:02 UTC (rev 1109)
+++ trunk/src/talker.c	2009-11-26 13:03:39 UTC (rev 1110)
@@ -27,6 +27,8 @@
 #include "rooms.h"
 #include "ipc.h"
 #include "log.h"
+#include "user.h"
+#include "uri.h"
 
 #include "alias.h"
 extern Alias bind_list;
@@ -1386,6 +1388,48 @@
 	update_user(user,userposn);
 }
 
+void t_uri(CommandList *cm, int argc, char **argv, char *args)
+{
+	uriActionList *al = uritable;
+	int wiz=0, num;
+	char c;
+	
+	if(argc == 1) {
+		// default action - list last 10 uris
+		uri_list_display(10, NULL);
+		return;
+	}
+	
+	if (u_god(user->status))  {
+		wiz=1;
+	}
+		
+	while(al->action)
+	{
+		if( strcasecmp(al->action, argv[1]) == 0 // we have a valid action
+		&& argc-1 >= al->min_argc // it has enough args
+		&& argc-1 <= al->max_argc // and doesn't have too many args
+		&& ( !al->needs_wiz || (al->needs_wiz && wiz)) ) // and it either doesn't need wiz or we are wiz
+		{
+			al->function(argc -1, &argv[1], al->needs_wiz && wiz);
+			return;
+		}
+		al++;
+	}
+	
+	if(argc == 2) // check for the posibility we have ".uri n" (same as .uri list * n)
+	{
+		if(sscanf(argv[1], "%d%c", &num, &c) == 1) { // check the arg is an int
+			if(num > 0) { 
+				uri_list_display(num, NULL);
+				return;
+			}
+		}
+	}
+		
+	printf("%s\n", cm->ArgError);
+}
+
 void t_chaton(void)
 {
 	char text[MAXTEXTLENGTH];

Modified: trunk/src/talker.h
===================================================================
--- trunk/src/talker.h	2009-11-22 16:36:02 UTC (rev 1109)
+++ trunk/src/talker.h	2009-11-26 13:03:39 UTC (rev 1110)
@@ -54,6 +54,7 @@
 void t_showvars(CommandList *cm, int argc, char **argv, char *args);
 void t_linewrap(CommandList *cm, int argc, char **argv, char *args);
 void t_mwrc(CommandList *cm, int argc, char **argv, char *args);
+void t_uri(CommandList *cm, int argc, char **argv, char *args);
 void t_chaton(void);
 
 void chat_say(char *text);

Modified: trunk/src/talker_privs.c
===================================================================
--- trunk/src/talker_privs.c	2009-11-22 16:36:02 UTC (rev 1109)
+++ trunk/src/talker_privs.c	2009-11-26 13:03:39 UTC (rev 1110)
@@ -604,7 +604,7 @@
 	 	ptr=0;
 	 	len=strlen(text);
 	}
-
+	
 	while (gaglist[ptr].name!=NULL)
 	{
 	 	if ((len==0 || !strncasecmp(gaglist[ptr].name, text, len)) && strcmp(gaglist[ptr].name, ""))

Added: trunk/src/uri.c
===================================================================
--- trunk/src/uri.c	                        (rev 0)
+++ trunk/src/uri.c	2009-11-26 13:03:39 UTC (rev 1110)
@@ -0,0 +1,702 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sqlite3.h>
+#include <readline/readline.h>
+
+#include "bb.h"
+#include "user.h"
+#include "uri.h"
+#include "sqlite.h"
+
+extern struct person *user;
+
+// uri action table
+// action, minargc, maxargc, tcmode, needs su, function
+// tcmode: 0: no tabcomplete 1: always tc 2: tc only after first char matched (su edit functions)
+uriActionList uritable[]={
+	{ "list"			, 1, 3, 1, 0, uri_list },
+	{ "-log"			, 2, 2, 0, 0, uri_delete },
+	{ "delete"			, 2, 2, 1, 0, uri_delete },
+	{ "del"				, 2, 2, 0, 0, uri_delete },
+	{ "!delete"			, 2, 2, 2, 1, uri_delete },
+	{ "!del"			, 2, 2, 0, 1, uri_delete },
+	{ "nsfw"			, 2, 2, 1, 0, uri_nsfw },
+	{ "!nsfw"			, 2, 2, 2, 1, uri_nsfw },
+	{ "membersonly"		, 2, 2, 1, 0, uri_members_only },
+	{ "!membersonly"	, 2, 2, 2, 1, uri_members_only },
+	{ "sucs"			, 2, 2, 0, 0, uri_members_only },
+	{ "anonymous"		, 2, 2, 1, 0, uri_anon },
+	{ "!anonymous"		, 2, 2, 2, 1, uri_anon },
+	{ "anon"			, 2, 2, 0, 0, uri_anon },
+	{ "displaymode"		, 1, 2, 1, 0, uri_display_mode },
+	{ NULL, 0, 0, 1, 1, NULL }
+};
+
+// uri flags
+// integer flag, db string, description used (un)setting flag, description used in list
+uriFlagList uriflagtable[] = {
+	{ URLFLAG_NSFW, "nsfw", "NSFW", "\033R-NSFW\033--" },
+	{ URLFLAG_ANON, "anon", "anonymous on web", "[Anon on web]" },
+	{ URLFLAG_SUCS, "sucs", "members-only", "(Members Only)" },
+	{ 0, NULL, NULL, NULL }
+};
+	
+// turns the db flag string into a bitwise flag field
+int uri_parse_flags(const char *flagstr)
+{
+	int flags = 0;
+	uriFlagList *fl = uriflagtable;
+	if(!flagstr) {
+		return 0;
+	}
+	while(fl->flag)
+	{
+		if(strcasestr(flagstr, fl->flagstr)) {
+			flags |= fl->flag;
+		}
+		fl++;
+	}
+	return flags;
+}
+
+// creates a string of database flags for the bitwise flags
+void uri_make_flags_str(int flags, char *flagstr, int len)
+{
+	int n=0;
+	uriFlagList *fl = uriflagtable;
+
+	flagstr[0] = '\0';
+	while(fl->flag)
+	{
+		if(flags & fl->flag)
+		{
+			n += snprintf(&flagstr[n], len-n, "%s%s", n==0?"":" ", fl->flagstr);
+		}
+		fl++;
+	}
+}
+
+// creates a the flag descriptions show in uri list from the database flags string
+void uri_make_flags_description(char *shortflags, char *flagstr, int len)
+{
+	int n=0;
+	uriFlagList *fl = uriflagtable;
+
+	flagstr[0] = '\0';
+	while(fl->flag)
+	{
+		if(strcasestr(shortflags,  fl->flagstr))
+		{
+			n += snprintf(&flagstr[n], len-n, " %s", fl->list_desc);
+		}
+		fl++;
+	}
+}
+
+// returns the long description for flag
+// should be duplicated if you want to edit it
+char *uri_get_flag_description(int flag)
+{
+	uriFlagList *fl = uriflagtable;
+	
+	while(fl->flag)
+	{
+		if(flag == fl->flag)
+		{
+			return fl->long_desc;
+		}
+		fl++;
+	}
+	return NULL;
+}
+
+// display <number> uris posted by <username> (or all users if username is NULL)
+void uri_list_display(int number, const char * username)
+{
+	char *query;	
+	struct db_result *res;
+	struct db_data *node;
+	int width, i, len;
+	char url_line[MAXTEXTLENGTH];
+	char *mode;
+	int disp_mode=0;
+	char flagstr[1024]="";
+	
+	if(username == NULL) {
+		query = sqlite3_mprintf("SELECT id,added,user,url,title,flags FROM mwuri ORDER BY id DESC LIMIT %d", number);
+	} else {
+		query = sqlite3_mprintf("SELECT id,added,user,url,title,flags FROM mwuri WHERE user=%Q ORDER BY id DESC LIMIT %d", username, number);
+	}
+	res = db_query(MWURI_DB, query, 1);	
+	fflush(stdout);
+	if(res == NULL) {
+		printf(".uri database lookup failed\n");
+	} else {
+		if(res->rows < 1)
+		{
+			if(username)
+			{
+				printf("%s has not posted any uris\n", username);
+			}
+			else
+			{
+				printf("There are not currently any uris in mwuri\n");
+			}
+		}
+		else if(res->rows < number)
+		{
+			printf("Displaying all uris posted to milliways%s%s:\n", username ? " by user " : "", username ? username : ""); 
+		}
+		else
+		{
+			printf("Displaying the last %d uri%s posted to milliways%s%s:\n", res->rows, res->rows==1? "s":"", username ? " by user " : "", username ? username : ""); 
+		}
+		// pick up the display mode from the private db
+		// we default to short if we don't get anything from the db
+		mode = userdb_get(USERDB_PRIVATE, user->name, "mwuri_display_mode");
+		if(mode)
+		{
+			if(strcmp(mode, "full")==0)
+			{
+				disp_mode = 1;
+			}
+		}
+		node = res->data;
+		width = screen_w();
+		if(width > MAXTEXTLENGTH - 1) {
+			width = MAXTEXTLENGTH - 1;
+		}
+		url_line[width]='\0';
+		while(node) {
+			char *id = node->field[0];
+			char *added = node->field[1];
+			char *username = node->field[2];
+			char *url = node->field[3];
+			char *title = node->field[4];
+			uri_make_flags_description(node->field[5], flagstr, sizeof(flagstr)); // flags = node->field[5]
+			
+			snprintf(url_line, width, "#\033G-%s\033-- [%s] <%s>%s\n", id, added, username, flagstr );
+			display_message(url_line, 0, 1);
+			
+			if(title != NULL) {
+				len = strlen(title);
+				for(i = 0; i<len; i++) {
+					if(title[i]=='\n') title[i]=' ';
+				}
+			}
+			if(disp_mode)
+			{
+				// in full display mode we just show the whole url + title
+				snprintf(url_line, MAXTEXTLENGTH-1, " %s%s%s", url, title ? " | ":"", title ? title:"");
+			
+			}
+			else
+			{
+				// in short display mode we try to fit url+title onto one line and shorten if it doesn't fit
+				// the whole url is always shown
+				if(strlen(url)+6 > width)
+				{
+					snprintf(url_line, width+1, " %s", url); // ' '.uri." | " is wider than the screen so just show the who url
+				}
+				else
+				{
+					if(snprintf(url_line, width+1, " %s%s%s", url, title ? " | ":"", title ? title:"") > width)
+					{
+						// line + title is wider than the screen so put ... at the end
+						url_line[width - 1] = '.';
+						url_line[width - 2] = '.';
+						url_line[width - 3] = '.';
+					}
+				}
+			}
+			display_message(url_line, 0, 1);
+			node = node->next;
+		}
+		db_free(res);
+	}
+	sqlite3_free(query);
+}
+
+/* parse the .uri list command and display uris if appropriate */
+void uri_list(int argc, char **argv, int wiz)
+{
+	char *username = NULL; // default is to display everyone's uris
+	int number = 10; // default is to display 10 uris
+	struct person *list_user = NULL;
+	char c; 
+	
+	if(argc == 1) // just '.uri list'
+	{
+		username = user->name;
+	}
+	else if(strcasecmp(argv[1], "*") == 0) // wants all uris
+	{
+		// username is already NULL and will thus select everyone
+		if(argc==3) 
+		{
+			if(sscanf(argv[2], "%d%c", &number, &c) == 1) 
+			{			
+				if(number < 1)
+				{
+					printf(".uri list * - can't list <1 uris\n");
+					return;
+				}
+			}
+			else
+			{
+				printf(".uri list * - last parameter was not a positive integer\n");
+				return;
+			}
+				
+		}	
+		if(argc>3)
+		{
+			printf(".uri list * - too many parameters\n");
+			return;
+		}
+		
+	}
+	else if( (list_user = user_get(argv[1])) != NULL) // is a real user
+	{
+		username = list_user->name;
+		if(argc==3) 
+		{
+			if(sscanf(argv[2], "%d%c", &number, &c) == 1) 
+			{			
+				if(number < 1)
+				{
+					free(list_user);
+					printf(".uri list %s - can't list <1 uris\n", argv[1]);
+					return;
+				}
+			}
+			else
+			{
+				free(list_user);
+				printf(".uri list %s - last parameter was not a positive integer\n", argv[1]);
+				return;
+			}
+		}
+		if(argc>3)
+		{
+			free(list_user);
+			printf(".uri list %s - too many parameters\n", argv[1]);
+			return;
+		}
+	} 
+	else // possibly we have '.uri list n' or we might have garbage
+	{
+		if(argc==2) 
+		{
+			if(sscanf(argv[1], "%d%c", &number, &c) == 1) 
+			{			
+				if(number < 1)
+				{
+					printf(".uri list - can't list <1 uris\n");
+					return;
+				}
+				// we have a .uri list n
+				username = user->name;
+			}
+			else
+			{
+				printf(".uri list - last parameter was not *, a username or a positive integer\n");
+				return;
+			}
+		}
+		if(argc>2)
+		{
+			printf(".uri list - invalid parameters\n");
+			return;
+		}
+		
+	}
+	
+	uri_list_display(number, username);
+	
+	if(list_user) {
+		free(list_user);
+	}
+}
+
+// checks an id supplied to uri_delete/nsfw etc. is valid or creates an id if the user specified 'last'
+// if wiz is true "last" will return the the last uri in mwuri otherwise it is the current users last uri
+// returns 0 if the id is not valid.
+unsigned int uri_get_id(char *idstr, int wiz)
+{
+	unsigned int id;
+	char c;
+	char *query;	
+	struct db_result *res;
+	
+	if( strcasecmp( "last", idstr ) == 0)
+	{
+		id=0;
+		if(wiz)
+		{
+			query = sqlite3_mprintf("SELECT id FROM mwuri ORDER BY id DESC LIMIT 1");
+		}
+		else
+		{
+			query = sqlite3_mprintf("SELECT id FROM mwuri WHERE user=%Q ORDER BY id DESC LIMIT 1", user->name );
+		}
+		res = db_query(MWURI_DB, query, 0);	
+		sqlite3_free(query);
+		if(res)
+		{
+			if(res->rows > 0)
+			{
+				sscanf(res->data->field[0], "%u", &id);
+			}
+			db_free(res);
+		}
+		return id;
+	}
+	else if( sscanf(idstr, "%u%c", &id, &c) == 1 )
+	{
+		return id;
+	}
+	else if( sscanf(idstr, "#%u%c", &id, &c) == 1)
+	{
+		return id;
+	}
+	return 0;
+}
+
+// deletes uri argv[1] if argv[1] is the id of a valid uri or "last"
+// if wiz is true any uri can be deleted otherwise only the current user's
+void uri_delete(int argc, char **argv, int wiz)
+{
+	unsigned int id;
+	char *query;	
+	struct db_result *res;
+	char mesg[MAXTEXTLENGTH];
+	char *del_query;
+	struct db_result *del_res;
+	int owner;
+	char answer[10];
+	char *username, *uri, *added;
+	
+	if((id = uri_get_id(argv[1], wiz)) > 0 )
+	{
+		query = sqlite3_mprintf("SELECT user,url,added FROM mwuri WHERE id=%d", id);
+		res = db_query(MWURI_DB, query, 1);	
+		if(res)
+		{
+			if(res->rows > 0)
+			{
+				username = res->data->field[0];
+				uri = res->data->field[1];
+				added = res->data->field[2];
+				owner = (strcmp(user->name, username)==0);
+				
+				if(owner || wiz)
+				{
+					snprintf(mesg, MAXTEXTLENGTH-1, "Are you sure you want to delete %s%s uri %s from mwuri?", owner? "your":username, owner? "":"'s", uri);
+					display_message(mesg, 0, 1);
+					get_str(answer, 5);
+					if (answer[0]=='y' || answer[0]=='Y')
+					{
+						del_query = sqlite3_mprintf("DELETE FROM mwuri WHERE id=%d", id);
+						del_res = db_query(MWURI_DB, del_query, 1);	
+						
+						if(del_res)
+						{
+							free(del_res);
+							snprintf(mesg, MAXTEXTLENGTH-1, "\03304%s has just deleted %s's uri %s [%s] from mwuri", user->name, username, uri, added);
+							broadcast(1, "%s", mesg);
+							snprintf(mesg, MAXTEXTLENGTH-1, "MWURI %s deleted uri: %s <%s> [%s]",  user->name, username, uri, added);
+							mwlog("%s", mesg);
+						}
+						else
+						{
+							printf("A db error occured trying to delete uri #%d\n", id);
+						}
+						sqlite3_free(del_query);
+					}
+				}
+				else
+				{
+					snprintf(mesg, MAXTEXTLENGTH-1, "uri #%d %s was not posted by you. You cannot delete it", id, uri);
+					display_message(mesg, 0, 1);
+				}
+			}
+			else
+			{
+				printf("uri %s: couldn't find uri #%d to delete\n", argv[0], id);
+			}
+			db_free(res);
+			sqlite3_free(query);
+		}
+		else
+		{
+			printf("uri %s: A db error occured while trying to find uri %s\n", argv[0], argv[1]);
+		}
+	}
+	else
+	{
+		snprintf(mesg, MAXTEXTLENGTH-1, "uri %s: %s is not a valid uri id", argv[0], argv[1]);
+		display_message(mesg, 0, 1);
+	}
+}
+
+// toggles flag uri argv[1] if argv[1] is the id of a valid uri or "last"
+// if wiz then any uri can be modified otherwise only the current user's
+void uri_set_flag(int argc, char **argv, int wiz, int flag)
+{
+	unsigned int id;
+	char mesg[MAXTEXTLENGTH];	
+	char *query, *update_query;	
+	struct db_result *res, *update_res;
+	int owner;
+	char answer[10];
+	char *username, *uri, *added;
+	int flags;
+	char flagstr[1024];
+	char *desc_str = uri_get_flag_description(flag);
+	
+	if(desc_str == NULL) {
+		printf("uri: whoops, someone needs to debug\n");
+		return;
+	}
+	
+	if((id = uri_get_id(argv[1], wiz)) > 0 )
+	{
+		query = sqlite3_mprintf("SELECT user,url,flags,added FROM mwuri WHERE id=%d", id);
+		res = db_query(MWURI_DB, query, 1);	
+		if(res)
+		{
+			if(res->rows > 0)
+			{
+				username = res->data->field[0];
+				uri = res->data->field[1];
+				flags = uri_parse_flags(res->data->field[2]);
+				added = res->data->field[3];
+				owner = (strcmp(user->name, username)==0);
+				
+				if(owner || wiz)
+				{
+					if(flags & flag)
+					{
+						snprintf(mesg, MAXTEXTLENGTH-1, "%s%s uri %s is already flaged as %s, do you want to unflag it?", owner? "your":username, owner? "":"'s", uri, desc_str);
+					}
+					else
+					{
+						snprintf(mesg, MAXTEXTLENGTH-1, "Are you sure you want to flag %s%s uri %s as %s?", owner? "your":username, owner? "":"'s", uri, desc_str);
+					}
+					display_message(mesg, 0, 1);
+					get_str(answer, 5);
+					if (answer[0]=='y' || answer[0]=='Y')
+					{
+						flags ^= flag; // toggle flag
+						
+						uri_make_flags_str(flags, flagstr, sizeof(flagstr));
+						
+						update_query = sqlite3_mprintf("UPDATE mwuri SET flags=%Q WHERE id=%d", flagstr, id);
+						update_res = db_query(MWURI_DB, update_query, 1);	
+						
+						if(update_res)
+						{
+							free(update_res);
+							snprintf(mesg, MAXTEXTLENGTH-1, "\03304%s has just %sset the %s flag on %s's uri %s [%s] in mwuri", user->name, flag&flags?"":"un", desc_str, username, uri, added);
+							broadcast(1, "%s", mesg);
+							snprintf(mesg, MAXTEXTLENGTH-1, "MWURI %s %sset %s flag on uri: %s <%s> [%s]",  user->name, flag&flags?"":"un", desc_str, username, uri, added);
+							mwlog("%s", mesg);
+						}
+						else
+						{
+							printf("A db error occured trying to change flags on uri #%d\n", id);
+						}
+						sqlite3_free(update_query);
+					}
+				}
+				else
+				{
+					snprintf(mesg, MAXTEXTLENGTH-1, "uri #%d %s was not posted by you. You cannot modify it", id, uri);
+					display_message(mesg, 0, 1);
+				}
+			}
+			else
+			{
+				printf("uri %s: couldn't find uri #%d to modify\n", argv[0], id);
+			}
+			db_free(res);
+			sqlite3_free(query);
+		}
+	}
+	else
+	{
+		snprintf(mesg, MAXTEXTLENGTH-1, "uri %s: %s is not a valid uri id", argv[0], argv[1]);
+		display_message(mesg, 0, 1);
+	}
+	
+}
+
+// these 3 flag functions call the man set_flag with the right flag
+void uri_nsfw(int argc, char **argv, int wiz)
+{
+	uri_set_flag(argc, argv, wiz, URLFLAG_NSFW);
+}
+
+void uri_members_only(int argc, char **argv, int wiz)
+{
+	uri_set_flag(argc, argv, wiz, URLFLAG_SUCS);
+}
+
+void uri_anon(int argc, char **argv, int wiz)
+{
+	uri_set_flag(argc, argv, wiz, URLFLAG_ANON);
+}
+
+// sets full or short display mode for uri list
+void uri_display_mode(int argc, char **argv, int wiz)
+{
+	char *mode = userdb_get(USERDB_PRIVATE, user->name, "mwuri_display_mode");
+	char default_mode[] = "short";
+	if(!mode)
+	{
+		mode = default_mode;
+	}
+	
+	if(argc == 1)
+	{
+		printf("Current uri list mode is: %s\n", mode ? mode:"short");
+	}
+	else
+	{
+		if(strcasecmp(argv[1],"full")==0)
+		{
+			userdb_set(USERDB_PRIVATE, user->name, "mwuri_display_mode", "full");
+			if(strcasecmp(mode, "full")==0)
+			{
+				printf("You are already using full uri list display mode\n");
+			}
+			else
+			{
+				printf("uri list display mode set to full\n");
+			}
+		}
+		else if(strcasecmp(argv[1],"short")==0)
+		{
+			userdb_set(USERDB_PRIVATE, user->name, "mwuri_display_mode", "short");
+			if(strcasecmp(mode, "short")==0)
+			{
+				printf("You are already using short uri list display mode\n");
+			}
+			else
+			{
+				printf("uri list display mode set to short\n");
+			}
+		}
+		else
+		{
+			printf("Usage: uri displaymode [full|short]\n");
+		}
+	}
+	
+	if(mode != default_mode)
+	{
+		free(mode);
+	}
+}
+
+// sorts tab commpletion for the uri command
+char *uri_action_tc(const char *text, int state)
+{
+ 	static int i=0;
+ 	static int len=0;
+ 	static int wiz=0;
+ 	int do_tc=0;
+ 	char *c;
+
+	if (state==0)
+	{
+	 	i=0;
+	 	len=strlen(text);
+		wiz = u_god(user->status);		
+	}
+	
+	while (uritable[i].action!=NULL)
+	{
+	 	if(len==0 && uritable[i].tc_mode==1)
+	 	{
+	 		// if len is 0 we tc all actions with a tc_mode 1 - tc_mode 2 are the su !edit functions for altering others uris
+	 		do_tc = 1;
+	 	}
+	 	if(len > 0 && (!strncasecmp(uritable[i].action, text, len)) && uritable[i].tc_mode )
+	 	{
+	 		// if we have the first char(s) then all non hidden actions can be shown
+	 		do_tc = 1;
+	 	}
+	 	if(!strcmp(uritable[i].action, ""))
+	 	{	
+	 		do_tc = 0;
+	 	}
+	 	if(uritable[i].needs_wiz && !wiz)
+	 	{
+	 		// if the action needs wiz and we haven't got wiz we don't tc
+	 		do_tc = 0;
+	 	}
+	 	if(do_tc)
+	 	{
+	 	 	c=dupstr(uritable[i].action,"");
+	 	 	i++;
+	 	 	return(c);
+	 	}
+	 	i++;
+	}
+	return(NULL);
+}
+
+char *uri_displaymodes[] = { "short", "full", NULL };
+
+// tab completes arguments for the uri list and uri displaymode commands
+// list: a username
+// displaymode: short | full
+char *uri_arg_tc(const char *text, int state)
+{
+	static int type=0;
+	static int ptr=0;
+	static int len=0;
+	char *c;
+	
+	if (state==0)
+	{
+		type = 0;
+		ptr = 0;
+		len = strlen(text);
+		
+		if(strcasestr(rl_line_buffer, " list "))
+		{
+			type = 1;
+		}
+		if(strcasestr(rl_line_buffer, " displaymode "))
+		{
+			type = 2;
+		}
+	}
+	
+	if(type == 1)
+	{
+		// tab complete .uri list. part_user function handles it
+		return(part_user(text, state));
+	}
+	if(type == 2)
+	{
+		// tab complete .uri displaymode
+		while (uri_displaymodes[ptr]!=NULL)
+		{
+			if ((len==0 || !strncasecmp(uri_displaymodes[ptr], text, len)) && strcmp(uri_displaymodes[ptr], ""))
+			{
+				c=dupstr(uri_displaymodes[ptr],"");
+				ptr++;
+				return(c);
+			}
+			ptr++;
+		}
+		
+	}
+	return(NULL);
+}
+	

Added: trunk/src/uri.h
===================================================================
--- trunk/src/uri.h	                        (rev 0)
+++ trunk/src/uri.h	2009-11-26 13:03:39 UTC (rev 1110)
@@ -0,0 +1,40 @@
+#define URLFLAG_NSFW	0x0001
+#define URLFLAG_ANON	0x0002
+#define URLFLAG_SUCS	0x0004
+
+#define MWURI_DB STATEDIR"/mwuri.db"
+
+
+typedef struct uriaction
+{
+	char *action;
+	int min_argc;
+	int max_argc;
+	int tc_mode;
+	int needs_wiz;
+	void (*function)(int, char **, int);
+} uriActionList;
+
+typedef struct uriflag
+{
+	int flag;
+	char *flagstr;
+	char *long_desc;
+	char *list_desc;
+} uriFlagList;
+
+extern uriActionList uritable[];
+
+void uri_make_flags_str(int flags, char *flagstr, int len);
+
+void uri_list_display(int number, const char * username);
+
+void uri_list(int argc, char **argv, int wiz);
+void uri_delete(int argc, char **argv, int wiz);
+void uri_nsfw(int argc, char **argv, int wiz);
+void uri_members_only(int argc, char **argv, int wiz);
+void uri_anon(int argc, char **argv, int wiz);
+void uri_display_mode(int argc, char **argv, int wiz);
+
+char *uri_action_tc(const char *text, int state);
+char *uri_arg_tc(const char *text, int state);

Added: trunk/talkhelp/uri
===================================================================
--- trunk/talkhelp/uri	                        (rev 0)
+++ trunk/talkhelp/uri	2009-11-26 13:03:39 UTC (rev 1110)
@@ -0,0 +1,47 @@
+NAME
+     uri - view/edit the mwuri db
+
+SYNOPSIS
+     uri [NUMBER]
+     uri list [USERNAME | *] [NUMBER]
+     
+     uri delete ID
+     uri nsfw ID
+     uri membersonly ID
+     uri anonymous ID
+     
+     uri displaymode short | full
+     
+DESCRIPTION
+     uri allows you to view or edit entires in the mwuri db.
+     
+     With no parameters it will list the last 10 uris from all users.
+     
+     uri list lists the last NUMBER uris posted by user USERNAME or * for 
+     all users.  If NUMBER is ommited it defaults to 10.  If neither 
+     [USERNAME] or [*] are used it will display your own entries.
+     
+     uri delete allows you to delete uri ID from the mwuri db if you posted it.
+     ID is as supplied by the uri list command. Can also be accessed using
+     uri -log or uri del.
+     
+     uri nsfw toggles the "not safe for work"(NSFW) flag for uri ID in the mwuri
+     db if you posted it.  ID is as supplied by the uri list command.
+
+     uri membersonly toggles the "members-only" flag for uri ID in the mwuri db
+     if you posted it.  ID is as supplied by the uri list command. Can also
+     be accessed using uri sucs.
+
+     uri anonymous toggles the "anonymous on web" flag for uri ID in the mwuri
+     db if you posted it.  ID is as supplied by the uri list command. Can also
+     be accessed using uri sucs.
+     
+     *Superusers may add ! to the start of any edit command to edit other users
+     uris.*
+     
+     uri displaymode lets you set the display mode for the uri line of the 
+     uri list command. When short the uri+title will only take up more than one
+     line on your terminal if the uri itself is longer than the width of your
+     terminal (the title is truncated to fit on one line).  When full the 
+     uri+title are displayed in full.
+




More information about the mw-devel mailing list