feed listing is started, and initial feed setup

This commit is contained in:
Fish 2006-07-15 07:09:12 +00:00
parent eb55e76836
commit 925f309aad
7 changed files with 320 additions and 22 deletions

1
.gitattributes vendored
View file

@ -13,6 +13,7 @@
/feed.c -text /feed.c -text
/feed.h -text /feed.h -text
/feed_help.c -text /feed_help.c -text
/feeds.dat -text
/html.css -text /html.css -text
/install-sh -text /install-sh -text
/modconfig.h.in -text /modconfig.h.in -text

View file

@ -11,5 +11,6 @@ feedserv_la_LDFLAGS = -module -avoid-version
EXTRA_DIST = autotools/ccdv.c autotools/shtool RELNOTES EXTRA_DIST = autotools/ccdv.c autotools/shtool RELNOTES
dist_doc_DATA = README.feedserv README.feedserv.html dist_doc_DATA = README.feedserv README.feedserv.html
dist_data_DATA = feeds.dat
include $(top_srcdir)/autotools/rules.mk include $(top_srcdir)/autotools/rules.mk

View file

@ -37,8 +37,8 @@ PRE_UNINSTALL = :
POST_UNINSTALL = : POST_UNINSTALL = :
build_triplet = @build@ build_triplet = @build@
host_triplet = @host@ host_triplet = @host@
DIST_COMMON = $(am__configure_deps) $(dist_doc_DATA) $(noinst_HEADERS) \ DIST_COMMON = $(am__configure_deps) $(dist_data_DATA) $(dist_doc_DATA) \
$(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(noinst_HEADERS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
$(srcdir)/modconfig.h.in $(top_srcdir)/autotools/rules.mk \ $(srcdir)/modconfig.h.in $(top_srcdir)/autotools/rules.mk \
$(top_srcdir)/configure ChangeLog autotools/compile \ $(top_srcdir)/configure ChangeLog autotools/compile \
autotools/config.guess autotools/config.sub autotools/depcomp \ autotools/config.guess autotools/config.sub autotools/depcomp \
@ -62,7 +62,8 @@ am__vpath_adj = case $$p in \
*) f=$$p;; \ *) f=$$p;; \
esac; esac;
am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
am__installdirs = "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)" am__installdirs = "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(datadir)" \
"$(DESTDIR)$(docdir)"
pkglibLTLIBRARIES_INSTALL = $(INSTALL) pkglibLTLIBRARIES_INSTALL = $(INSTALL)
LTLIBRARIES = $(pkglib_LTLIBRARIES) LTLIBRARIES = $(pkglib_LTLIBRARIES)
feedserv_la_LIBADD = feedserv_la_LIBADD =
@ -79,8 +80,9 @@ LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
CCLD = $(CC) CCLD = $(CC)
SOURCES = $(feedserv_la_SOURCES) SOURCES = $(feedserv_la_SOURCES)
DIST_SOURCES = $(feedserv_la_SOURCES) DIST_SOURCES = $(feedserv_la_SOURCES)
dist_dataDATA_INSTALL = $(INSTALL_DATA)
dist_docDATA_INSTALL = $(INSTALL_DATA) dist_docDATA_INSTALL = $(INSTALL_DATA)
DATA = $(dist_doc_DATA) DATA = $(dist_data_DATA) $(dist_doc_DATA)
HEADERS = $(noinst_HEADERS) HEADERS = $(noinst_HEADERS)
ETAGS = etags ETAGS = etags
CTAGS = ctags CTAGS = ctags
@ -208,6 +210,7 @@ noinst_HEADERS = feed.h
feedserv_la_LDFLAGS = -module -avoid-version feedserv_la_LDFLAGS = -module -avoid-version
EXTRA_DIST = autotools/ccdv.c autotools/shtool RELNOTES EXTRA_DIST = autotools/ccdv.c autotools/shtool RELNOTES
dist_doc_DATA = README.feedserv README.feedserv.html dist_doc_DATA = README.feedserv README.feedserv.html
dist_data_DATA = feeds.dat
LINK = $(LIBTOOL) --tag=CXX --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ LINK = $(LIBTOOL) --tag=CXX --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@ $(AM_LDFLAGS) $(LDFLAGS) -o $@
@ -306,6 +309,14 @@ distclean-libtool:
-rm -f libtool -rm -f libtool
uninstall-info-am: uninstall-info-am:
uninstall-dist_dataDATA:
@$(NORMAL_UNINSTALL)
@list='$(dist_data_DATA)'; for p in $$list; do \
f=$(am__strip_dir) \
echo " rm -f '$(DESTDIR)$(datadir)/$$f'"; \
rm -f "$(DESTDIR)$(datadir)/$$f"; \
done
uninstall-dist_docDATA: uninstall-dist_docDATA:
@$(NORMAL_UNINSTALL) @$(NORMAL_UNINSTALL)
@list='$(dist_doc_DATA)'; for p in $$list; do \ @list='$(dist_doc_DATA)'; for p in $$list; do \
@ -493,7 +504,7 @@ check-am: all-am
check: check-am check: check-am
all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS) modconfig.h all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS) modconfig.h
installdirs: installdirs:
for dir in "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)"; do \ for dir in "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(datadir)" "$(DESTDIR)$(docdir)"; do \
test -z "$$dir" || $(mkdir_p) "$$dir"; \ test -z "$$dir" || $(mkdir_p) "$$dir"; \
done done
install: install-am install: install-am
@ -542,7 +553,7 @@ info: info-am
info-am: info-am:
install-data-am: install-dist_docDATA install-data-am: install-dist_dataDATA install-dist_docDATA
install-exec-am: install-pkglibLTLIBRARIES install-exec-am: install-pkglibLTLIBRARIES
@ -572,8 +583,8 @@ ps: ps-am
ps-am: ps-am:
uninstall-am: uninstall-dist_docDATA uninstall-info-am \ uninstall-am: uninstall-dist_dataDATA uninstall-dist_docDATA \
uninstall-pkglibLTLIBRARIES uninstall-info-am uninstall-pkglibLTLIBRARIES
.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \ .PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \
clean-generic clean-libtool clean-pkglibLTLIBRARIES ctags dist \ clean-generic clean-libtool clean-pkglibLTLIBRARIES ctags dist \
@ -582,12 +593,13 @@ uninstall-am: uninstall-dist_docDATA uninstall-info-am \
distclean-hdr distclean-libtool distclean-tags distcleancheck \ distclean-hdr distclean-libtool distclean-tags distcleancheck \
distdir distuninstallcheck dvi dvi-am html html-am info \ distdir distuninstallcheck dvi dvi-am html html-am info \
info-am install install-am install-data install-data-am \ info-am install install-am install-data install-data-am \
install-dist_docDATA install-exec install-exec-am install-info \ install-dist_dataDATA install-dist_docDATA install-exec \
install-info-am install-man install-pkglibLTLIBRARIES \ install-exec-am install-info install-info-am install-man \
install-strip installcheck installcheck-am installdirs \ install-pkglibLTLIBRARIES install-strip installcheck \
maintainer-clean maintainer-clean-generic mostlyclean \ installcheck-am installdirs maintainer-clean \
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ maintainer-clean-generic mostlyclean mostlyclean-compile \
pdf pdf-am ps ps-am tags uninstall uninstall-am \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags uninstall uninstall-am uninstall-dist_dataDATA \
uninstall-dist_docDATA uninstall-info-am \ uninstall-dist_docDATA uninstall-info-am \
uninstall-pkglibLTLIBRARIES uninstall-pkglibLTLIBRARIES

272
feed.c
View file

@ -1,3 +1,4 @@
/* NeoStats - IRC Statistical Services /* NeoStats - IRC Statistical Services
** Copyright (c) 1999-2006 Adam Rutter, Justin Hammond, Mark Hetherington ** Copyright (c) 1999-2006 Adam Rutter, Justin Hammond, Mark Hetherington
** http://www.neostats.net/ ** http://www.neostats.net/
@ -28,8 +29,11 @@
static int feed_cmd_list( const CmdParams *cmdparams ); static int feed_cmd_list( const CmdParams *cmdparams );
static int feed_cmd_add( const CmdParams *cmdparams ); static int feed_cmd_add( const CmdParams *cmdparams );
static int feed_cmd_del( const CmdParams *cmdparams ); static int feed_cmd_del( const CmdParams *cmdparams );
static int feed_cmd_info( const CmdParams *cmdparams );
static int feed_set_exclusions_cb( const CmdParams *cmdparams, SET_REASON reason ); static int feed_set_exclusions_cb( const CmdParams *cmdparams, SET_REASON reason );
static void FeedDownLoadHandler(void *ptr, int status, char *data, int datasize); static void FeedDownLoadHandler(void *ptr, int status, char *data, int datasize);
static void FeedRequestHandler(void *usrptr, int status, char *data, int datasize);
char *trim (char *tmp); char *trim (char *tmp);
Bot *feed_bot; Bot *feed_bot;
@ -40,6 +44,42 @@ typedef struct feeddata {
feedcfg feed; feedcfg feed;
typedef struct feedinfo {
char *title;
char *description;
char *link;
char *about;
char feedurl[BUFSIZE];
int setup;
} feedinfo;
typedef struct feedcache {
char *item;
char *link;
char *description;
char *author;
char *comments;
char *guid;
char *date;
char *hash;
} feedcache;
typedef struct subscribed {
hash_t *users;
hash_t *chans;
feedinfo *feed;
list_t *cache;
} subscribed;
typedef struct feedrequest {
Client *c;
feedinfo *fi;
} feedrequest;
list_t *lofeeds;
list_t *subscribedfeeds;
/** Copyright info */ /** Copyright info */
static const char *feed_copyright[] = { static const char *feed_copyright[] = {
"Copyright (c) 1999-2006, NeoStats", "Copyright (c) 1999-2006, NeoStats",
@ -67,9 +107,10 @@ ModuleInfo module_info = {
static bot_cmd feed_commands[]= static bot_cmd feed_commands[]=
{ {
{"ADD", feed_cmd_add, 2, NS_ULEVEL_ADMIN, feed_help_add, 0, NULL, NULL}, {"ADD", feed_cmd_add, 1, NS_ULEVEL_ADMIN, feed_help_add, 0, NULL, NULL},
{"DEL", feed_cmd_del, 1, NS_ULEVEL_ADMIN, feed_help_del, 0, NULL, NULL}, {"DEL", feed_cmd_del, 1, NS_ULEVEL_ADMIN, feed_help_del, 0, NULL, NULL},
{"LIST", feed_cmd_list, 0, NS_ULEVEL_ADMIN, feed_help_list, 0, NULL, NULL}, {"LIST", feed_cmd_list, 0, NS_ULEVEL_ADMIN, feed_help_list, 0, NULL, NULL},
{"INFO", feed_cmd_info, 1, NS_ULEVEL_ADMIN, feed_help_info, 0, NULL, NULL},
NS_CMD_END() NS_CMD_END()
}; };
@ -215,8 +256,26 @@ trim (char *tmp)
int feed_cmd_list (const CmdParams *cmdparams) int feed_cmd_list (const CmdParams *cmdparams)
{ {
feedinfo *fi;
lnode_t *node;
int i = 1;
int doing = 0;
SET_SEGV_LOCATION(); SET_SEGV_LOCATION();
node = list_first(lofeeds);
irc_prefmsg(feed_bot, cmdparams->source, "Available Feed Listing:");
while (node) {
fi = lnode_get(node);
if (fi->setup == 1) {
irc_prefmsg(feed_bot, cmdparams->source, "%d) Title: %s", i, fi->title);
} else {
doing++;
}
i++;
node = list_next(lofeeds, node);
}
irc_prefmsg(feed_bot, cmdparams->source, "End of List.");
if (doing > 0) irc_prefmsg(feed_bot, cmdparams->source, "Still Setting up %d feeds", doing);
CommandReport(feed_bot, "%s requested a feed listing", cmdparams->source->name);
return NS_SUCCESS; return NS_SUCCESS;
} }
@ -231,8 +290,65 @@ int feed_cmd_list (const CmdParams *cmdparams)
int feed_cmd_add (const CmdParams *cmdparams) int feed_cmd_add (const CmdParams *cmdparams)
{ {
feedinfo *fi;
feedrequest *fr;
lnode_t *node;
SET_SEGV_LOCATION(); SET_SEGV_LOCATION();
node = list_first(lofeeds);
while (node) {
fi = lnode_get(node);
if (!strcasecmp(fi->feedurl, cmdparams->av[0])) {
/* it exists, don't add */
irc_prefmsg(feed_bot, cmdparams->source, "A feed with that URL already exists: %s", fi->title);
return NS_SUCCESS;
}
node = list_next(lofeeds, node);
}
/* if we are here, add it */
fr = ns_malloc(sizeof(feedrequest));
fr->c = cmdparams->source;
fr->fi = ns_malloc(sizeof(feedinfo));
strncpy(fr->fi->feedurl, cmdparams->av[0], BUFSIZE);
if (new_transfer(fr->fi->feedurl, NULL, NS_MEMORY, "", fr, FeedRequestHandler) != NS_SUCCESS ) {
irc_prefmsg(feed_bot, cmdparams->source, "Feed Setup Failed");
ns_free(fr->fi);
ns_free(fr);
return NS_SUCCESS;
}
irc_prefmsg(feed_bot, cmdparams->source, "Checking Feed is valid. Please wait...");
return NS_SUCCESS;
}
/** @brief feed_cmd_info
*
* ADD command handler
*
* @param cmdparam struct
*
* @return NS_SUCCESS if suceeds else result of command
*/
int feed_cmd_info (const CmdParams *cmdparams)
{
feedinfo *fi;
lnode_t *node;
int i = 1;
SET_SEGV_LOCATION();
node = list_first(lofeeds);
while (node) {
if (i == atoi(cmdparams->av[0])) {
fi = lnode_get(node);
irc_prefmsg(feed_bot, cmdparams->source, "Feed Title: %s", fi->title);
irc_prefmsg(feed_bot, cmdparams->source, "Feed URL: %s", fi->link);
irc_prefmsg(feed_bot, cmdparams->source, "Feed Description: %s", fi->description);
irc_prefmsg(feed_bot, cmdparams->source, "Feed RSS Link: %s", fi->feedurl);
irc_prefmsg(feed_bot, cmdparams->source, "Feed About: %s",fi->about);
return NS_SUCCESS;
}
i++;
node = list_next(lofeeds, node);
}
return NS_SUCCESS; return NS_SUCCESS;
} }
@ -276,6 +392,7 @@ static int feed_set_exclusions_cb( const CmdParams *cmdparams, SET_REASON reason
static void ScheduleFeeds() { static void ScheduleFeeds() {
feeddata *ptr; feeddata *ptr;
SET_SEGV_LOCATION(); SET_SEGV_LOCATION();
return;
ptr = ns_malloc(sizeof(feeddata)); ptr = ns_malloc(sizeof(feeddata));
ptr->mrss = NULL; ptr->mrss = NULL;
mrss_new(&ptr->mrss); mrss_new(&ptr->mrss);
@ -297,12 +414,11 @@ static void CheckFeed(feeddata *ptr) {
mrss_hour_t *hour; mrss_hour_t *hour;
mrss_day_t *day; mrss_day_t *day;
mrss_category_t *category; mrss_category_t *category;
Channel *c;
irc_chanprivmsg(feed_bot, ptr->channel,"Generic:"); irc_chanprivmsg(feed_bot, ptr->channel,"Generic:");
irc_chanprivmsg(feed_bot, ptr->channel,"file: %s", ptr->mrss->file); irc_chanprivmsg(feed_bot, ptr->channel,"file: %s", ptr->mrss->file);
irc_chanprivmsg(feed_bot, ptr->channel,"encoding: %s", ptr->mrss->encoding); irc_chanprivmsg(feed_bot, ptr->channel,"encoding: %s", ptr->mrss->encoding);
irc_chanprivmsg(feed_bot, ptr->channel,"size: %d", ptr->mrss->size); irc_chanprivmsg(feed_bot, ptr->channel,"size: %d", (int)ptr->mrss->size);
irc_chanprivmsg(feed_bot, ptr->channel,"version:"); irc_chanprivmsg(feed_bot, ptr->channel,"version:");
switch (ptr->mrss->version) switch (ptr->mrss->version)
@ -416,7 +532,6 @@ static void CheckFeed(feeddata *ptr) {
category = category->next; category = category->next;
} }
irc_chanprivmsg(feed_bot, ptr->channel,"");
item = item->next; item = item->next;
} }
@ -449,6 +564,123 @@ static void FeedDownLoadHandler(void *usrptr, int status, char *data, int datasi
return; return;
} }
static int load_feeds( void *data, int size )
{
feedinfo *fi;
if( size == sizeof(feedinfo) )
{
fi = ns_calloc( sizeof(feedinfo));
os_memcpy(fi, data, sizeof (feedinfo));
lnode_create_append(lofeeds, fi);
}
return NS_FALSE;
}
/** @brief FeedSetupHandler
*/
static void FeedSetupHandler(void *usrptr, int status, char *data, int datasize) {
feedinfo *ptr = lnode_get((lnode_t *)usrptr);
feedinfo *next = NULL;
mrss_t *mrss;
mrss_error_t ret;
lnode_t *node;
SET_SEGV_LOCATION();
if (status != NS_SUCCESS) {
dlog(DEBUG1, "RSS Scrape Download failed: %s", data);
/* ok, move onto the next url */
node = list_next(lofeeds, (lnode_t *)usrptr);
if (node) next = lnode_get(node);
if ((next) && ((new_transfer(next->feedurl, NULL, NS_MEMORY, "", node, FeedSetupHandler) != NS_SUCCESS ))) {
nlog(LOG_WARNING, "Download Feed Setup failed");
}
return;
}
mrss = NULL;
mrss_new(&mrss);
/* ok, here is our data */
ret = mrss_parse_buffer(data, datasize, &mrss);
if (ret != MRSS_OK) {
dlog(DEBUG1, "RSS Parse Failed: %s", mrss_strerror(ret));
mrss_free(mrss);
/* ok, move onto the next url */
node = list_next(lofeeds, (lnode_t *)usrptr);
if (node) next = lnode_get(node);
if ((next) && ((new_transfer(next->feedurl, NULL, NS_MEMORY, "", node, FeedSetupHandler) != NS_SUCCESS ))) {
nlog(LOG_WARNING, "Download Feed Setup failed");
}
return;
}
ptr->title = strndup(mrss->title, strlen(mrss->title));
if (mrss->description)
ptr->description = strndup(mrss->description, strlen(mrss->description));
if (mrss->link)
ptr->link = strndup( mrss->link, strlen(mrss->link));
if (mrss->about) {
ptr->about = strndup(mrss->about, strlen(mrss->about));
} else {
ptr->about = NULL;
}
ptr->setup = 1;
mrss_free(mrss);
/* ok, move onto the next url */
node = list_next(lofeeds, (lnode_t *)usrptr);
if (node) next = lnode_get(node);
if ((next) && ((new_transfer(next->feedurl, NULL, NS_MEMORY, "", node, FeedSetupHandler) != NS_SUCCESS ))) {
nlog(LOG_WARNING, "Download Feed Setup failed");
}
return;
}
/** @brief FeedRequestHandler
*/
static void FeedRequestHandler(void *usrptr, int status, char *data, int datasize) {
feedrequest *ptr = (feedrequest *)usrptr;
mrss_t *mrss;
mrss_error_t ret;
SET_SEGV_LOCATION();
if (status != NS_SUCCESS) {
dlog(DEBUG1, "RSS Scrape Download failed: %s", data);
irc_prefmsg(feed_bot, ptr->c, "RSS Scrape Failed. %s not added", ptr->fi->feedurl);
ns_free(ptr->fi);
ns_free(ptr);
return;
}
mrss = NULL;
mrss_new(&mrss);
/* ok, here is our data */
ret = mrss_parse_buffer(data, datasize, &mrss);
if (ret != MRSS_OK) {
dlog(DEBUG1, "RSS Parse Failed: %s", mrss_strerror(ret));
irc_prefmsg(feed_bot, ptr->c, "RSS Parse Failed for URL %s: %s", ptr->fi->feedurl, mrss_strerror(ret));
mrss_free(mrss);
ns_free(ptr->fi);
ns_free(ptr);
return;
}
ptr->fi->title = strndup(mrss->title, strlen(mrss->title));
ptr->fi->description = strndup(mrss->description, strlen(mrss->description));
ptr->fi->link = strndup(mrss->link, strlen(mrss->link));
if (mrss->about) {
ptr->fi->about = strndup(mrss->about, strlen(mrss->about));
} else {
ptr->fi->about = NULL;
}
ptr->fi->setup = 1;
mrss_free(mrss);
lnode_create_append(lofeeds, ptr->fi);
irc_prefmsg(feed_bot, ptr->c, "%s has been added to Feed List", ptr->fi->title);
return;
}
/** @brief ModInit /** @brief ModInit
* *
* Init handler * Init handler
@ -460,8 +692,34 @@ static void FeedDownLoadHandler(void *usrptr, int status, char *data, int datasi
int ModInit( void ) int ModInit( void )
{ {
FILE *feeds;
static char buf[BUFSIZE];
feedinfo *fi, *ff = NULL;
lnode_t *node;
SET_SEGV_LOCATION(); SET_SEGV_LOCATION();
lofeeds = list_create( LISTCOUNT_T_MAX );
subscribedfeeds = list_create (LISTCOUNT_T_MAX );
DBAFetchRows("feeds", load_feeds);
/* if lofeeds count is 0, this is probably a first time load, so load from text file */
if (list_count(lofeeds) <= 0) {
feeds = os_fopen("data/feeds.dat", "r");
if (!feeds) {
nlog(LOG_WARNING, "Can't Open Feed Listing file feeds.dat. FeedServ will start with no list of feeds");
} else {
while (os_fgets(buf, BUFSIZE, feeds)) {
fi = os_malloc(sizeof(feedinfo));
strncpy(fi->feedurl, buf, BUFSIZE);
fi->setup = 0;
lnode_create_append(lofeeds, fi);
}
os_fclose(feeds);
node = list_first(lofeeds);
if (node) ff = lnode_get(node);
if ((ff) && ((new_transfer(ff->feedurl, NULL, NS_MEMORY, "", node, FeedSetupHandler) != NS_SUCCESS ))) {
nlog(LOG_WARNING, "Download Feed Setup failed");
}
}
}
return NS_SUCCESS; return NS_SUCCESS;
} }

1
feed.h
View file

@ -39,6 +39,7 @@ extern feedcfg feed;
extern const char *feed_about[]; extern const char *feed_about[];
extern const char *feed_help_add[]; extern const char *feed_help_add[];
extern const char *feed_help_del[]; extern const char *feed_help_del[];
extern const char *feed_help_info[];
extern const char *feed_help_list[]; extern const char *feed_help_list[];
extern const char *feed_help_set_exclusions[]; extern const char *feed_help_set_exclusions[];

View file

@ -48,6 +48,17 @@ const char *feed_help_add[] = {
"The new port is scanned straight away", "The new port is scanned straight away",
NULL NULL
}; };
const char *feed_help_info[] = {
"Add a port to scanning",
"Syntax: \2ADD <type> <port>\2",
"",
"Add an entry to the port scan list.",
"<type> must be one of:",
" HTTP, HTTPPOST, SOCKS4, SOCKS5, WINGATE, ROUTER",
"<port> must be a valid port number.",
"The new port is scanned straight away",
NULL
};
const char *feed_help_del[] = { const char *feed_help_del[] = {
"Delete a port from scanning", "Delete a port from scanning",

14
feeds.dat Normal file
View file

@ -0,0 +1,14 @@
http://productnews.userland.com/newsItems/departments/radioUserland.xml
http://www.scripting.com/rss.xml
http://www.wired.com/news_drop/netcenter/netcenter.rdf
http://news.com.com/2547-1_3-0-5.xml
http://www.dictionary.com/wordoftheday/wotd.rss
http://www.theregister.co.uk/tonys/slashdot.rdf
http://www.infoworld.com/rss/news.xml
http://www.csmonitor.com/rss/top.rss
http://radio.weblogs.com/0001011/rss.xml
http://rss.news.yahoo.com/rss/tech
http://static.userland.com/tomalak/links2.xml
http://www.nytimes.com/services/xml/rss/nyt/Technology.xml
http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml
http://www.computerworld.com/news/xml/10/0,5009,,00.xml