pax_global_header00006660000000000000000000000064122071146270014514gustar00rootroot0000000000000052 comment=fe0d8362626054a506e8e9c9819e2fe1623807db newsbeuter-2.7/000077500000000000000000000000001220711462700135475ustar00rootroot00000000000000newsbeuter-2.7/.gitignore000066400000000000000000000001531220711462700155360ustar00rootroot00000000000000*.[ao] config.mk po/*.mo stfl/*.h newsbeuter podbeuter test/test test/test-rss test/testlog.txt xlicense.h newsbeuter-2.7/.travis.yml000066400000000000000000000003541220711462700156620ustar00rootroot00000000000000before_install: - sudo apt-get install libsqlite3-dev libcurl4-openssl-dev libxml2-dev libstfl-dev libjson0-dev libncursesw5-dev bc language: cpp compiler: - gcc script: make after_script: - "make test && cd test && ./test" newsbeuter-2.7/AUTHORS000066400000000000000000000021171220711462700146200ustar00rootroot00000000000000Authors: Andreas Krennmair Code Contributors: see `git shortlog -s` Translation Contributors: cn Chinese (Simplified) joshyu cn_TW Chinese (Traditional) Aeglos Lin es Spanish OmeGa es_ES Spanish (Spain) epsilon@correoe.no-ip.org fr French Nicolas Martyanoff hu Hungarian Zsolt Udvari it Italian Andrea Marchesini nb Norwegian (bokmål) Daniel Aleksandersen nl Dutch Bart Van Loon pl Polish Maciej Delmanowski pt_BR Portuguese (Brazilian) Adiel Mittmann ru Russian Sergey Dryabzhinsky sv Swedish Niklas Grahn tr Turkish H.Gökhan SAR uk Ukrainian Ivan Kovnatsky newsbeuter-2.7/CHANGES000066400000000000000000000260521220711462700145470ustar00rootroot00000000000000Changes for newsbeuter: 2.7 (2013-08-27): Fix crash bug. Add option to colorize unread messages (Patrick Steinhardt). Add option to swap title and hints bar (Patrick Steinhardt). Add %u and %t support to itemview (Giuliano Schneider). Only force redraw if a form action is active (Patrick Steinhardt). 2.6 (2013-03-19): Fixed crash in RSS parser (thanks to Isaac Good). Fixed authentication issues with Google Reader (thanks to Fabrice Noilhan). Fixed bug in Google authentication (Daniel Aleksandersen). Style table headers in bold (Daniel Aleksandersen). Add support for q and aside tags (Daniel Aleksandersen). Remove all soft-hyphens (Daniel Aleksandersen). More compact default user-agent on Mac OS X (Daniel Aleksandersen). Add Norwegian bokmål translation (Daniel Aleksandersen). Updated Russian translation (Justin Forest). Updated Polish translation (Michal Siemek). 2.5 (2012-01-06): Implemented download-full-page configuration option. Added configuration option to use external URL viewer (fixes issue #242). Added ability to store Google Reader password in an external file (fixes issue #239). Added Tiny Tiny RSS support (fixes issue #243). Made HTTP authentication method configurable (fixes issue #247). Implemented "delete-read-articles-on-quit" option. Fixed rendering of nested
    lists. 2.4 (2011-02-01): Added support for query feeds in combination with Google Reader support. Added ability to configure proxy authentication method. Added commandline option -q to enable quiet startup (patch by Isaac Good) Re-sort feed list after all feeds have been reloaded. Added keys to jump to the next/previous feed or article regardless of its "unread" status (patches by Jim Pryor) Implemented on-demand loading of feeds to reduce memory usage. Removed Bloglines support as the service shuts down on October 1, 2010. Implemented XDG Base Directory support (patch by Elrond) Google Reader: when in offline mode, record unread status changes and later replay when in online mode. Fixed Google Reader authentication issue with certain passwords (fixes issue #238). Added configuration option "cookie-cache" (fixes issue #234). 2.3 (2010-06-24): Fixed HTML rendering of bold and underline text when light background is configured. Fixed issues #192, #194, #197, #198, #199, #200, #201, #202, #210, #216. Made newsbeuter silent on lockfile errors when '-x' option is used. Fixed Google Reader authentication (by Seth Mason) 2.2 (2010-03-14): Added Google Reader support. Fixed issues #90, #160, #161, #168, #169, #171, #179, #180, #184. Implemented article highlighting in article list based on the article content (fixes issue #174). Extended "ignore article" functionality with different ignore modes (download/display; fixes issue #52). Added "hard quit" key to immediately quit from newsbeuter (patch by Jim Pryor) Added "download status" format specifier for feedlist-format (fixes issue #181). Added HTML table renderer (patch by Stefan Erben) Fixed issues #183, #188 (patch by Stefan Erben) Added "open-in-browser-and-mark-read" key (patch by Isaac Good) 2.1 (2009-12-08): Added support for dc:creator tag for RSS 2.0 parser. Fixed issue #141 (podbeuter ignored use-proxy configuration command). When entering a feed, the first unread article is automatically selected (can be turned off with goto-first-unread no). When marking a feed read, move the selection to the next feed (unless a filter is currently applied). Improved HTML rendering (patch by Stefan Erben) Added length field to article list format (patch by Stefan Erben) Added support for 256-color terminals Added "dumpform" commandline command as a debugging aid. Allow deletion of articles from article view Added support for SOCKS proxies Added "notify-beep" notification beep (patch by Vern Sun) Added key to quickly jump to article URLs above #10 (patch by Stefan Erben) 2.0 (2009-04-21): Added more flexible dialog handling Improved position handling in article list (fixes #112; thanks to Isaac Good) Fixed a lot of bugs (#102, #111, #117, #130, #131). Added ability to specify a list of OPML URLs when using OPML as URL source. Added config option "keep-articles-days" to optionally keep articles only for a limited number of days. Added config option "bookmark-interactive" to indicate that the configured bookmarking command is interactive. Don't display authentication information in URLs (fixes #121). Replaced mrss with new RSS/Atom parser. Added ability to search for text from the article view. Added basic support for Yahoo Media RSS. Made article view pager configurable. Improved HTML rendering of links and underlined and bold text. Added ":source" commandline command to (re)load configuration files. Implemented "pipe-to" key to pipe articles to external commands. Implemented backtick evaluation for configuration files. Extended filter language with "between" operator. Added "age" attribute for articles to filter them for relative age (in days). Extended "set" commandline command to toggle boolean variables and reset configuration variables of all types to their default. Added ability to configure local files as feeds. Added a "random-unread" key to go to a random unread article. When opening articles from a search result dialog, make search phrase stand out in article view. Persist commandline and search history. Implemented commandline completion. Improved help dialog so that it now shows unbound functions. Added ability to sort feed list and article list by interactively choosing the sort method. Improved and extended conditional HTTP download handling. 1.3 (2008-12-06): Changed some internal data structures to smart pointers (stability improvement). Extended podbeuter to keep finished downloads in the queue until they've been played. Implemented placeholders for download-path (fixes #46). Added the ability to edit the list of subscribed URLs from newsbeuter through a text editor. Implemented a file format to exchange information about read articles between different newsbeuter instances. Extended keymap to allow dialog-specific configuration. Extended macros to enable modification of configuration variables. Implemented configuration option "feed-sort-order" to sort the feed list by the first tag. Added ability to toggle read flag from article view (thanks to Isaac Good). Added ability to configure the number of parallel reload threads (fixes #101). 1.2 (2008-09-02): Fixed crash in case of invalid color/attribute names in the configuration Implemented "download-timeout" and "download-retries" config options to make newsbeuter more reliable over unreliable connection (fixes #88). Improved whitespace handling in XML parser (fixes Debian issue #496765). Fixed broken open-in-browser operation for URLs that contained a single quote (fixes Debian issue #497495; fixes incomplete security fix). 1.1 (2008-09-01): Added a line wrap for the article view's headers and the link list on the bottom (fixes Debian issue #491122) Added test suite for functional tests of the user interface Fixed potential security issue when opening article URLs with the configured browser (thanks to J.H.M. Dassen (Ray) for pointing out) 1.0 (2008-08-20): Implemented support for highlighting of regular expressions Implemented search function in help dialog Implemented "show-read-articles" configuration option to toggle displaying of read articles Implemented "always-download" configuration option to configure a list of feed URLs for which newsbeuter ignores the Last-Modified timestamp Added read progress display in article view Added optional format string support for "browser" configuration option Added "reset-unread-on-update" configuration command 0.9.1 (2008-05-12): Fixed issue with filter feeds. Added possibility to open a feed's link by pressing the open-in-browser key in feed list. Fixed issue with RFC-822 date parsing where the year only had 2 digits. 0.9 (2008-05-01): Improved locking to allow multiple newsbeuter instances (one instance per cache file) Flagged articles don't get deleted anymore. Added commandline option to podbeuter to automatically start download. Added "article-sort-order" configuration option to freely configure the sort order of article lists Added possibility to delete articles Lots of bug fixes 0.8.2 (2008-03-16): fixed broken string conversion. 0.8.1 (2008-03-12): fixed crash (related to string conversion of format string support) 0.8 (2008-03-07): implemented custom configurability of feed list and article list format improved reload speed by checking the Last-Modified header added special tags to rename feeds added macro support added Ruby scripting support directly integrated nxml/mrss code since API and ABI are a moving target 0.7 (2007-09-18): implemented the possibility to predefine filters implemented bloglines synchronization support implemented OPML online subscription support implemented plugin-based bookmarking support implemented custom flagging of articles redesigned search function implemented more key commands to ease navigation even more added the possibility to optionally use an external HTML renderer 0.6 (2007-08-14): implemented support for reloading the urls file implemented query feeds implemented history for the most important input fields fixed a major bug with filtering in the item list bugfix in the OPML import functionality implemented additional commandline commands 0.5 (2007-08-02): improved HTML rendering improved lock file handling added Unicode compatibility added support for notifications implemented filter language it is now possible to freely configure e.g. the up/down-keys 0.4 (2007-05-08): refactored view introduced configuration option to disable cache cleanup (user request) introduced configuration option to set the HTTP user-agent header to a custom value significant speed improvement for reload and cache cleanup (by Jürgen Jung) added Italian translation (by Andrea Marchesini) added unit tests added an "include" configuration command to make it possible to separate the configuration into several files introduced global configuration file /etc/newsbeuter/config added support for Snownews/Liferea extension scripts 0.3 (2007-03-26): added gettext support added podcast support changed handling of encoding - now, everything is stored as UTF-8 internally, and gets converted on-the-fly removed dependency to libidn numerous bugs have been fixed 0.2 (2007-02-21): removed an unnecessary mutex lock/unlock that made newsbeuter lock up when the "max-items" config option was set improved HTML rendering (occasional missing spaces,
     tags)
    	added possibility to use the space key for key bindings
    	made "next unread" function work across feeds when in item view
    	added the possibility to view all URLs within an article and open them in a browser
    	added HTTP proxy support
    	added color configuration support
    	added tagging/categorization support
    	added auto-reload support
    	added search dialog
    
    0.1.1 (2007-01-17):
    	fixed a crash when ISO-8859-1 encoded feeds with umlauts in the title were displayed on systems with UTF-8 locales enabled.
    
    0.1 (2007-01-16):
    	Initial release.
    newsbeuter-2.7/LICENSE000066400000000000000000000021271220711462700145560ustar00rootroot00000000000000MIT/X Consortium License
    
    (C)opyright 2006-2013 Andreas Krennmair 
    
    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:
    
    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
    newsbeuter-2.7/Makefile000066400000000000000000000134001220711462700152050ustar00rootroot00000000000000# important directories
    prefix?=/usr/local
    mandir?=$(prefix)/share/man
    datadir?=$(prefix)/share
    localedir?=$(datadir)/locale
    docdir?=$(datadir)/doc/$(PACKAGE)
    
    # compiler
    CXX=c++
    
    # compiler and linker flags
    DEFINES=-DLOCALEDIR=\"$(localedir)\"
    WARNFLAGS=-Wall -Wextra
    CXXFLAGS+=-ggdb -Iinclude -Istfl -Ifilter -I. -Irss $(WARNFLAGS) $(DEFINES)
    LDFLAGS+=-L.
    
    PACKAGE=newsbeuter
    
    ifneq (distclean, $(MAKECMDGOALS))
    include config.mk
    endif
    
    ifeq ($(PROFILE),1)
    CXXFLAGS+=-fprofile-arcs -ftest-coverage
    endif
    
    LIB_SOURCES:=$(shell cat mk/libbeuter.deps)
    LIB_OBJS:=$(patsubst %.cpp,%.o,$(LIB_SOURCES))
    LIB_OUTPUT=libbeuter.a
    
    FILTERLIB_SOURCES=filter/Scanner.cpp filter/Parser.cpp filter/FilterParser.cpp
    FILTERLIB_OBJS:=$(patsubst %.cpp,%.o,$(FILTERLIB_SOURCES))
    FILTERLIB_OUTPUT=libfilter.a
    
    NEWSBEUTER=newsbeuter
    NEWSBEUTER_SOURCES:=$(shell cat mk/newsbeuter.deps)
    NEWSBEUTER_OBJS:=$(patsubst %.cpp,%.o,$(NEWSBEUTER_SOURCES))
    NEWSBEUTER_LIBS=-lbeuter -lfilter -lpthread -lrsspp
    
    RSSPPLIB_SOURCES=$(wildcard rss/*.cpp)
    RSSPPLIB_OBJS=$(patsubst rss/%.cpp,rss/%.o,$(RSSPPLIB_SOURCES))
    RSSPPLIB_OUTPUT=librsspp.a
    
    
    PODBEUTER=podbeuter
    PODBEUTER_SOURCES:=$(shell cat mk/podbeuter.deps)
    PODBEUTER_OBJS:=$(patsubst %.cpp,%.o,$(PODBEUTER_SOURCES))
    PODBEUTER_LIBS=-lbeuter -lpthread
    
    ifeq (, $(filter Linux GNU GNU/%, $(shell uname -s)))
    NEWSBEUTER_LIBS+=-liconv -lintl
    PODBEUTER_LIBS+=-liconv -lintl
    endif
    
    # additional commands
    MKDIR=mkdir -p
    INSTALL=install
    A2X=a2x
    MSGFMT=msgfmt
    RANLIB=ranlib
    AR=ar
    
    STFLHDRS:=$(patsubst %.stfl,%.h,$(wildcard stfl/*.stfl))
    POFILES:=$(wildcard po/*.po)
    MOFILES:=$(patsubst %.po,%.mo,$(POFILES))
    POTFILE=po/newsbeuter.pot
    
    TEXTCONV=./txt2h.pl
    RM=rm -f
    
    all: $(NEWSBEUTER) $(PODBEUTER)
    
    NB_DEPS=$(MOFILES) $(LIB_OUTPUT) $(FILTERLIB_OUTPUT) $(NEWSBEUTER_OBJS) $(RSSPPLIB_OUTPUT)
    
    $(NEWSBEUTER): $(NB_DEPS)
    	$(CXX) $(CXXFLAGS) -o $(NEWSBEUTER) $(NEWSBEUTER_OBJS) $(NEWSBEUTER_LIBS) $(LDFLAGS)
    
    $(PODBEUTER): $(MOFILES) $(LIB_OUTPUT) $(PODBEUTER_OBJS)
    	$(CXX) $(CXXFLAGS) -o $(PODBEUTER) $(PODBEUTER_OBJS) $(PODBEUTER_LIBS) $(LDFLAGS)
    
    $(LIB_OUTPUT): $(LIB_OBJS)
    	$(RM) $@
    	$(AR) qc $@ $^
    	$(RANLIB) $@
    
    $(RSSPPLIB_OUTPUT): $(RSSPPLIB_OBJS)
    	$(RM) $@
    	$(AR) qc $@ $^
    	$(RANLIB) $@
    
    $(FILTERLIB_OUTPUT): $(FILTERLIB_OBJS)
    	$(RM) $@
    	$(AR) qc $@ $^
    	$(RANLIB) $@
    
    regenerate-parser:
    	$(RM) filter/Scanner.cpp filter/Parser.cpp filter/Scanner.h filter/Parser.h
    	cococpp -frames filter filter/filter.atg
    
    %.o: %.cpp
    	$(CXX) $(CXXFLAGS) -o $@ -c $<
    
    %.h: %.stfl
    	$(TEXTCONV) $< .stfl > $@
    
    clean-newsbeuter:
    	$(RM) $(NEWSBEUTER) $(NEWSBEUTER_OBJS)
    
    clean-podbeuter:
    	$(RM) $(PODBEUTER) $(PODBEUTER_OBJS)
    
    clean-libbeuter:
    	$(RM) $(LIB_OUTPUT) $(LIB_OBJS)
    
    clean-librsspp:
    	$(RM) $(RSSPPLIB_OUTPUT) $(RSSPPLIB_OBJS)
    
    clean-libfilter:
    	$(RM) $(FILTERLIB_OUTPUT) $(FILTERLIB_OBJS)
    
    #clean-doc:
    #	$(RM) -r doc/xhtml 
    #	$(RM) doc/*.xml doc/*.1 doc/newsbeuter-cfgcmds.txt doc/podbeuter-cfgcmds.txt doc/newsbeuter-keycmds.txt
    
    clean: clean-newsbeuter clean-podbeuter clean-libbeuter clean-libfilter clean-librsspp
    	$(RM) $(STFLHDRS) xlicense.h
    
    distclean: clean clean-mo test-clean
    	$(RM) core *.core core.* config.mk
    
    doc:
    	$(MKDIR) doc/xhtml
    	$(A2X) -f xhtml -D doc/xhtml doc/newsbeuter.txt
    	doc/generate.pl doc/configcommands.dsv > doc/newsbeuter-cfgcmds.txt
    	doc/generate2.pl doc/keycmds.dsv > doc/newsbeuter-keycmds.txt
    	$(A2X) -f manpage -D doc doc/manpage-newsbeuter.txt
    	doc/generate.pl doc/podbeuter-cmds.dsv > doc/podbeuter-cfgcmds.txt
    	$(A2X) -f manpage -D doc doc/manpage-podbeuter.txt
    
    install: install-mo
    	$(MKDIR) $(DESTDIR)$(prefix)/bin
    	$(INSTALL) $(NEWSBEUTER) $(DESTDIR)$(prefix)/bin
    	$(INSTALL) $(PODBEUTER) $(DESTDIR)$(prefix)/bin
    	$(MKDIR) $(DESTDIR)$(mandir)/man1
    	$(INSTALL) doc/$(NEWSBEUTER).1 $(DESTDIR)$(mandir)/man1 || true
    	$(INSTALL) doc/$(PODBEUTER).1 $(DESTDIR)$(mandir)/man1 || true
    	$(MKDIR) $(DESTDIR)$(docdir)
    	$(INSTALL) -m 644 doc/xhtml/* $(DESTDIR)$(docdir) || true
    	$(MKDIR) $(DESTDIR)$(docdir)/examples
    	$(INSTALL) -m 644 doc/example-config $(DESTDIR)$(docdir)/examples/config || true
    
    uninstall:
    	$(RM) $(DESTDIR)$(prefix)/bin/$(NEWSBEUTER)
    	$(RM) $(DESTDIR)$(prefix)/bin/$(PODBEUTER)
    	$(RM) $(DESTDIR)$(mandir)/man1/$(NEWSBEUTER).1
    	$(RM) $(DESTDIR)$(mandir)/man1/$(PODBEUTER).1
    	$(RM) -r $(DESTDIR)$(docdir)
    
    .PHONY: doc clean distclean all test test-rss extract install uninstall regenerate-parser clean-newsbeuter \
    	clean-podbeuter clean-libbeuter clean-librsspp clean-libfilter install-mo msgmerge clean-mo \
    	test-clean config
    
    # the following targets are i18n/l10n-related:
    
    extract:
    	$(RM) $(POTFILE)
    	xgettext -k_ -o $(POTFILE) *.cpp src/*.cpp rss/*.cpp
    
    msgmerge:
    	for f in $(POFILES) ; do msgmerge -U $$f $(POTFILE) ; done
    
    %.mo: %.po
    	$(MSGFMT) --statistics -o $@ $<
    
    clean-mo:
    	$(RM) $(MOFILES) po/*~
    
    install-mo:
    	$(MKDIR) $(DESTDIR)$(datadir)
    	@for mof in $(MOFILES) ; do \
    		mofile=`basename $$mof` ; \
    		lang=`echo $$mofile | sed 's/\.mo$$//'`; \
    		dir=$(DESTDIR)$(localedir)/$$lang/LC_MESSAGES; \
    		$(MKDIR) $$dir ; \
    		$(INSTALL) -m 644 $$mof $$dir/$(PACKAGE).mo ; \
    		echo "Installing $$mofile as $$dir/$(PACKAGE).mo" ; \
    	done
    
    test: $(LIB_OUTPUT) $(NEWSBEUTER_OBJS) $(FILTERLIB_OUTPUT) $(RSSPPLIB_OUTPUT) test/test.o
    	$(CXX) $(CXXFLAGS) -o test/test src/history.o src/rss.o src/rss_parser.o src/htmlrenderer.o src/cache.o src/tagsouppullparser.o src/urlreader.o src/regexmanager.o test/test.o src/ttrss_api.o src/markreadthread.o $(NEWSBEUTER_LIBS) $(LDFLAGS)
    
    test-rss: $(RSSPPLIB_OUTPUT) test/test-rss.o
    	$(CXX) $(CXXFLAGS) -o test/test-rss test/test-rss.o src/utils.o $(NEWSBEUTER_LIBS) $(LDFLAGS)
    
    test/test.o: test/test.cpp
    	$(CXX) $(CXXFLAGS) -o $@ -c $<
    
    test-clean:
    	$(RM) test/test test/test.o test/test-rss test/test-rss.o
    
    profclean:
    	find . -name '*.gc*' -type f | xargs $(RM)
    	$(RM) app*.info
    
    config: config.mk
    
    config.mk:
    	@./config.sh
    
    xlicense.h: LICENSE
    	$(TEXTCONV) $< > $@
    
    include mk/mk.deps
    newsbeuter-2.7/README000066400000000000000000000027531220711462700144360ustar00rootroot00000000000000README for newsbeuter
    =====================
    Andreas Krennmair 
    
    Introduction
    ------------
    Newsbeuter is an RSS feed reader for the text console. It is designed to run
    Unix-like operating systems such as Linux. NetBSD is currently not supported,
    due to technical limitations.
    
    Downloading
    -----------
    You can download the latest version of newsbeuter from the following website:
    http://www.newsbeuter.org/
    
    Alternatively, you can check out the latest version from the newsbeuter
    Git repository (hosted on GitHub):
    
    	git clone git://github.com/akrennmair/newsbeuter.git
    
    Dependencies
    ------------
    Newsbeuter depends on a number of libraries, which need to be installed before
    newsbeuter can be compiled.
    
    - STFL (version 0.21 or newer): http://www.clifford.at/stfl/
    - SQLite3 (version 3.5 or newer): http://www.sqlite.org/download.html
    - libcurl (version 7.18.0 or newer): http://curl.haxx.se/download.html
    - GNU gettext (on systems that don't provide gettext in the libc): ftp://ftp.gnu.org/gnu/gettext/
    - pkg-config: http://pkg-config.freedesktop.org/wiki/
    - libxml2: http://xmlsoft.org/downloads.html
    - json-c: http://oss.metaparadigm.com/json-c/
    
    Debian unstable comes with ready-to-use packages for these dependencies.
    
    Installation
    ------------
    Compiling and installing newsbeuter is as simple as:
    
    	make
    	make install
    
    Contact
    -------
    Andreas Krennmair 
    
    License
    -------
    Newsbeuter is licensed under the MIT/X Consortium License. See the file LICENSE
    for further details.
    newsbeuter-2.7/TODO000066400000000000000000000221571220711462700142460ustar00rootroot00000000000000TODO:
    - in the article view, the headers should be an own color configuration element
    - add an auto-flag configuration command to automatically flag articles that match a certain query
    - when reload is finished, the focus shall be in the current form's list
    - per-feed refresh settings
    - make MacPort available for easy installation
    - compute "busy-ness" of feeds, make it a sort option
    - implement RFC 5005 (http://www.ietf.org/rfc/rfc5005.txt)
    - implement a single key with which it is possible to go through all unread articles (like space in slrn)
    - make it configurable whether "n" jumps to the next feed or stays in the same.
    
    
    DONE:
    - clean up items that have been added but whose URL has been removed from the config file.
    - key for directly jumping to next unread article.
    - OPML import/export
    - open link in browser
    - cache items in local database (sqlite?)
    	used location:
    		~/.newsbeuter/urls -- the list of feed URLs
    		~/.newsbeuter/cache.db -- the feed and item cache
    - optimize cache updates (every feed and every item needs something like a "dirty" flag)
    - improve HTML rendering (write/use XML/HTML pull parser)
    - configuration file
    - fix the "foobar"/ issue in the XML pull parser
    - fix display issues in test RSS file
    - implement custom keybindings
    - update status line to correct key mapping
    - preliminary fix for the sort-by-date problem
    - delete old entries _based_on_the_date_ (implement RFC 2822 parser!)
    - add online help screen
    - "next unread" error message must be shown differently
    - save function
    - use multithreading to download feeds so that simultaneous browsing/reading is possible.
    	- only one "reload-all" operation may run at once
    	- fix memleak (pthread_cleanup_push)
    - set current path in filebrowser head
    - set correct keymap hint in filebrowser
    - reload feed from the itemlist
    - "next unread" also for feedlist
    - improve configuration parser (!!comments!!)
    - implement "source view" in itemview.
    - made feedlist head fancier
    - added "toggle item read" function
    - implemented an urlview-like interface
    - add proxy configuration support
    - add auto-reload feature
    - add color configuration support
    - support for atom (talk to mRss guy?) - implement by yourself?
    - implement search
    	- own dialog
    	- result list on top
    	- search input field on bottom
    	- set correct title in search dialog
    - add default save path configuration option
    - improve configuration parser: support quoting
    - i18n/l10n
    - implemented podcast support:
    	- when newsbeuter finds new entries with podcast enclosures in it, it puts it into a "queue" (text file in ~/.newsbeuter)
    	- the actual downloading and saving is done by "podbeuter", which is a more a download manager that dequeues entries and downloads them.
    	- write "advanced topics - podcasts" section in documentation
    	- improved rendering of itunes:summary descriptions.
    	- implement "resume download" function
    	- write podbeuter.1 manpage
    	- set configured colors
    	- implement "start player" function in podbeuter.
    	- test more thoroughly
    - fill table with html entities
    - write "newsbeuter hacker's guide"
    	- describe the overall architecture
    	- describe debugging tricks (i.e. logging)
    	- describe design decisions, e.g. why certain things are only configurable via the config files
    - some spaces before the key on the help screen
    - refactor view
    	- provide a function to "modally" run certain screens and return a certain value. we need this for select tag, search and file browser.
    - add configuration option to disable cleanup
    - add configuration option to set a custom user-agent string
    - replace lockfile with fcntl()-based locking
    - make STFL and newsbeuter capable of correct handling of Unicode
    - implement command line (STFL issue?)
    	- make it possible to directly jump to the n-th entry by entering ":n" in the command line
    - implement free configurability of key bindings for widgets (STFL issue)
    - fix memory leak
    - set keybindings in podbeuter, too
    - implement "meta-feeds"
    - make date/time format customizable in the article list
    - make  cancel the commandline
    - the manpage shall be generated with asciidoc
    - implement "previous unread article" key
    - implement -V commandline option to see version number
    - predefine filters and select them from a view
    - implement detection when an item is outside of its regular feed (when item->feed->rssurl != feed->rssurl) for itemlist
    - implement bloglines support (including offline mode)
    - implement new urls-source "opml" to subscribe to opml files that are available online
    - test import/export
    - implement keys to jump to the next and previous unread feed from the article list
    - properly document changes in key binding stuff
    - do entitity decoding for titles (won't be fixed, as we fully comply with the RSS recommendations)
    - refine the search function (make it like the command line)
    - research (and fix) libnxml decoding issues
    - strip \r from title
    - maybe move the "newsbeuter 0.7" on the right side of the first line (implemented use of format string stuff for info line on feedlist etc.)
    - make mark-all-read also work in search results
    - add scripting support
    - make script functions callable via key bindings
    - don't delete flagged articles
    - check whether date parsing uses the correct timezone (long-term testing shows that this seems to work flawlessly)
    - improve string handling (no more std::string() + std::string()) (got much better)
    - add automatic download mode to podbeuter (commandline switch)
    - implement commandline commands quit [done], add, save [done], tag (select tag) [done], goto (by matching title of feed) [done]
    - add delete article functionality:
    	- mark articles as deleted in the DB
    	- after a successful reload, remove all those articles who bear a deleted flag and are not in the list of GUIDs from the reload
    - convert search strings to utf-8 prior to searching.
    - bug: when a user is in an itemlist that contains unread items, and returns to the feedlist that has show-unread disabled, the selected feed is not the same as previously shown in the itemlist. expected behaviour: when returning from the itemlist to the feedlist, the feed that was shown previously shall be selected.
    - make cursor in feedlist and itemlist stable when a filter is applied
    - update example config (added script to automatize task)
    - add -d and -l to about and manpage
    - refactored XML pull parser (many redundancies)
    - check issues with missing words from articles
    	- zed shaw blog has such issues (entity decode fuckup when no encoding was provided)
    - wrap long headers in article view (Debian issue #491122)
    - add filtering for correct color names
    - bug: don't squeeze whitespaces when inside a 
     environment.
    - add a second "downloaded, but unlistened" queue to podbeuter (solved by marking downloaded but unplayed files in the queue file)
    - implement "newsrc" style file format to exchange information about read articles.
    - make ":" work on urlview dialog
    - replace std::vector with std::vector > as a possible fix against these weird crashes.
      beta tester: mhellwig@in-ulm.de (regular crashes on sparc Linux)
    - write documentation on feed-sortorder and related changes
    - use categories from OPML also when it is directly used as source
    - make it possible to configure more than one opml source
    - when a feed is reloaded, and the article list is updated, the show-read-items flag is reset
    - add option similar to max-items but that deletes articles older than n days
    - add support for interactive bookmarking plugins
    - implement mark-as-read-on-hover
    - implement own RSS parser
    	- fix encoding issues
    	- implement Atom parsing
    	- fix TODOs in src/rss_parser.cpp
    - add configurable pager
    - implement reloading of configuration (:source)
    - fix W3CDTF parser
    - make boolean config variables toggable via commandline and resettable to default
    - backtick evaluation in configuration
    - add license to -V output
    - rename -v to something else to avoid confusion
    - make last search phrase stand out in article view.
    - persist search and command history to text files.
    - fix :source for bind-key: bind-key j down etc.
    - improve logging of which feeds are broken.
    - make search phrase stand out in help - combined with existing limit functionality
    - check correct sorting of query feeds
    - add option to prepopulate query feeds
    - fix help screen in podbeuter
    - add quoting when printing out config variable values so that copy/paste can be applied.
    - check for stfl in config.sh script
    - Google Reader support
    	- add options to define flags that mark whether an article should be "shared" or "starred" and communicate this to Google Reader if necessary
    	- use  information to update read/unread status
    	- add option to show "special feeds" such as what your friends shared.
    - implement internal alias mechanism to allow transition of renamed config commands.
    - fix HTML rendering of bold and underlined text when light background is configured
    - add support for query feeds to Google Reader support.
    - reduce memory usage by loading feeds on demand when being opened
    - when in offline mode of Google Reader support, record which articles have been marked as read, and sync that back to Google Reader.
    - document XDG base directory support.
    - implement filter extension support also for OPML
    newsbeuter-2.7/config.h000066400000000000000000000010261220711462700151640ustar00rootroot00000000000000#ifndef NEWSBEUTER_CONFIG__H
    #define NEWSBEUTER_CONFIG__H
    
    #define PACKAGE				"newsbeuter"
    #define PROGRAM_NAME			PACKAGE
    #define PROGRAM_VERSION			"2.7"
    #define PROGRAM_URL			"http://www.newsbeuter.org/"
    
    #define NEWSBEUTER_PATH_SEP			"/"
    #define NEWSBEUTER_CONFIG_SUBDIR	".newsbeuter"
    #define NEWSBEUTER_SUBDIR_XDG		"newsbeuter"
    
    #include 
    #include 
    
    #ifdef _
    #undef _
    #endif
    
    #define _(string) gettext(string)
    
    /* #define NDEBUG */ // only enable this #define if you want to disable all debug logging.
    
    #endif
    newsbeuter-2.7/config.sh000077500000000000000000000056441220711462700153640ustar00rootroot00000000000000#!/bin/sh
    
    FAILSTATUS=""
    
    check_pkg() {
    	pkgname=$1
    	add_define=$2
    	pkgconfig_args=$3
    	echo -n "Checking for package ${pkgname}... "
    	if pkg-config --silence-errors "${pkgname}" ; then
    		echo "found"
    		echo "# configuration for package ${pkgname}" >> config.mk
    		result=`pkg-config --cflags $pkgconfig_args ${pkgname}`
    		if [ -n "$result" ] ; then
    			echo "DEFINES+=$result" >> config.mk
    		fi
    		if [ -n "$add_define" ] ; then
    			echo "DEFINES+=${add_define}" >> config.mk
    		fi
    		echo "LDFLAGS+=`pkg-config --libs $pkgconfig_args ${pkgname}`" >> config.mk
    		echo "" >> config.mk
    	else
    		echo "not found"
    		return 1
    	fi
    	return 0
    }
    
    check_custom() {
    	pkgname=$1
    	customconfig=$2
    	add_define=$3
    	echo -n "Checking for package ${pkgname} using ${customconfig}... "
    	if ${customconfig} --cflags > /dev/null 2>&1 ; then
    		echo "found"
    		echo "# configuration for package ${pkgname}" >> config.mk
    		result=`${customconfig} --cflags`
    		if [ -n "$result" ] ; then
    			echo "DEFINES+=${result}" >> config.mk
    		fi
    		if [ -n "$add_define" ] ; then
    			echo "DEFINES+=${add_define}" >> config.mk
    		fi
    		echo "LDFLAGS+=`${customconfig} --libs`" >> config.mk
    		echo "" >> config.mk
    	else
    		echo "not found"
    		return 1
    	fi
    	return 0
    }
    
    fail() {
    	pkgname=$1
    	rm -f config.mk
    	dlurl=`grep -i "$pkgname" README | awk '{ print $NF }'`
    	echo ""
    	echo "You need package ${pkgname} in order to compile this program."
    	echo "Please make sure it is installed."
    	echo ""
    	echo "You can download ${pkgname} from here: ${dlurl}"
    	FAILSTATUS="1"
    }
    
    fail_custom() {
    	err=$1
    	echo ""
    	echo "ERROR: ${err}"
    	FAILSTATUS="1"
    }
    
    all_aboard_the_fail_boat() {
    	if [ "x$FAILSTATUS" != "x" ] ; then
    		rm -f config.mk
    		echo ""
    		echo "One or more dependencies couldn't be found. Please install"
    		echo "these packages and retry compilation."
    		exit 1
    	fi
    }
    
    check_ssl_implementation() {
    	if curl-config --static-libs | egrep -- "-lssl( |^)" > /dev/null 2>&1 ; then
    		check_pkg "libcrypto" || fail "libcrypto"
    		echo "DEFINES+=-DHAVE_OPENSSL=1" >> config.mk
    	elif curl-config --static-libs | grep -- -lgcrypt > /dev/null 2>&1 ; then
    		check_pkg "gnutls" || fail "gnutls"
    		check_custom "libgcrypt" "libgcrypt-config" || fail "libgcrypt"
    		echo "DEFINES+=-DHAVE_GCRYPT=1" >> config.mk
    	fi
    }
    
    echo "# overrides of LDFLAGS and LDFLAGS from environment" > config.mk
    [ -n "$CXXFLAGS" ] && echo "CXXFLAGS+=$CXXFLAGS" >> config.mk
    [ -n "$LDFLAGS" ] && echo "LDFLAGS+=$LDFLAGS" >> config.mk
    echo "" >> config.mk
    
    check_pkg "sqlite3" || fail "sqlite3"
    check_pkg "libcurl" || check_custom "libcurl" "curl-config" || fail "libcurl"
    check_pkg "libxml-2.0" || check_custom "libxml2" "xml2-config" || fail "libxml2"
    check_pkg "stfl" || fail "stfl"
    ( check_pkg "json" || check_pkg "json-c" ) || fail "json-c"
    
    if [ `uname -s` = "Darwin" ]; then
    	check_custom "ncurses5.4" "ncurses5.4-config" || fail "ncurses5.4"
    else 
    	check_custom "ncursesw5" "ncursesw5-config" || fail "ncursesw5"
    fi
    check_ssl_implementation
    all_aboard_the_fail_boat
    newsbeuter-2.7/contrib/000077500000000000000000000000001220711462700152075ustar00rootroot00000000000000newsbeuter-2.7/contrib/bookmark-delicious.sh000077500000000000000000000011021220711462700213230ustar00rootroot00000000000000#!/bin/sh
    # newsbeuter bookmarking plugin for del.icio.us
    # (c) 2007 Andreas Krennmair
    # documentation: http://delicious.com/help/api#posts_add
    
    username="your delicious.com username here"
    password="your delicious.com password here"
    
    url="$1"
    title="$2"
    desc="$3"
    
    delicious_url="https://api.del.icio.us/v1/posts/add?url=${url}&description=${title}&extended=${desc}"
    
    output=`wget --http-user=$username --http-passwd=$password -O - "$delicious_url" 2> /dev/null`
    
    output=`echo $output | sed 's/^.*code="\([^"]*\)".*$/\1/'`
    
    if [ "$output" != "done" ] ; then
      echo "$output"
    fi
    newsbeuter-2.7/contrib/bookmark-pinboard.sh000077500000000000000000000010631220711462700211470ustar00rootroot00000000000000#!/bin/sh
    # newsbeuter bookmarking plugin for pinboard
    # (c) 2007 Andreas Krennmair
    # documentation: https://pinboard.in/api
    
    username="pinboard_username"
    password="pinboard_password"
    
    tag="via:newsbeuter"
    
    url="$1"
    title="$2"
    desc="$3"
    
    pinboard_url="https://api.pinboard.in/v1/posts/add?url=${url}&description=${title}&extended=${desc}&tags="${tag}""
    
    output=`wget --http-user=$username --http-passwd=$password -O - "$pinboard_url" 2> /dev/null`
    
    output=`echo $output | sed 's/^.*code="\([^"]*\)".*$/\1/'`
    
    if [ "$output" != "done" ] ; then
      echo "$output"
    fi
    newsbeuter-2.7/contrib/bookmark-scuttle.sh000077500000000000000000000016401220711462700210350ustar00rootroot00000000000000#!/bin/sh
    # newsbeuter generic bookmarking plugin for a scuttle installation (http://sourceforge.net/projects/scuttle/)
    # adapted by Igorette
    # (c) 2007 Andreas Krennmair
    # documentation: http://delicious.com/help/api#posts_add
    # (scuttle is nearly 100% api compatible with delicious.com)
    
    username="your scuttle username here"
    password="your scuttle password here"
    site="your scuttle installation base url"
    
    url="$1"
    title="$2"
    desc="$3"
    
    # scuttle installation without url rewriting
    scuttle_url=${site}"/api/posts_add.php?url=${url}&description=${title}&extended=${desc}&tag=mytag"
    
    # for clean urls (using mod_rewrite)
    # scuttle_url=${site}"/api/posts/add?url=${url}&description=${title}&extended=${desc}&tag=mytag"
    
    output=`wget --http-user=$username --http-passwd=$password -O - "$scuttle_url" 2> /dev/null`
    
    output=`echo $output | sed 's/^.*code="\([^"]*\)".*$/\1/'`
    
    if [ "$output" != "done" ] ; then
      echo "$output"
    fi
    newsbeuter-2.7/contrib/colorschemes/000077500000000000000000000000001220711462700176755ustar00rootroot00000000000000newsbeuter-2.7/contrib/colorschemes/commander000066400000000000000000000003711220711462700215660ustar00rootroot00000000000000# newsbeuter color scheme that somehow resembles the infamous N*rt*n Commander.
    
    color listnormal yellow blue bold
    color listfocus  black cyan bold
    color info       black cyan bold
    color background yellow blue bold
    color article    yellow blue bold
    newsbeuter-2.7/contrib/colorschemes/cyanism000066400000000000000000000002761220711462700212700ustar00rootroot00000000000000# cyan-colored newsbeuter color scheme
    
    color listnormal cyan black
    color listfocus  cyan black reverse
    color info       white blue
    color background white black
    color article    white black
    newsbeuter-2.7/contrib/colorschemes/greenscreen000066400000000000000000000005061220711462700221210ustar00rootroot00000000000000# greenscreen color scheme for newsbeuter 
    # a simple theme that resembles the look and feel of old "green screen" terminals.
    
    color listnormal green default
    color listfocus  green default reverse
    color info       green default reverse
    color background green default
    color article    green default
    newsbeuter-2.7/contrib/colorschemes/inkpot000066400000000000000000000013101220711462700211170ustar00rootroot00000000000000# inkpotish color scheme for newsbeuter 
    # more on inkpot: http://www.vim.org/scripts/script.php?script_id=1143
    
    # colors
    color background   color229   default
    color listnormal   color229   default
    color listfocus    color229   color61 bold
    color info         color247   color235
    color article      color229   default
    
    # highlights
    highlight article "^(Feed|Link):.*$" color46 default bold
    highlight article "^(Title|Date|Author):.*$" color39 default bold
    highlight article "https?://[^ ]+" color46 default underline
    highlight article "\\[[0-9]+\\]" color63 default bold
    highlight article "\\[image\\ [0-9]+\\]" color63 default bold
    highlight feedlist "^─.*$" color61 color235 bold
    newsbeuter-2.7/contrib/colorschemes/light000066400000000000000000000003241220711462700207260ustar00rootroot00000000000000# a lightly-colored, well-readable newsbeuter color scheme
    
    color listnormal black white
    color listfocus  white blue bold
    color info       white red bold
    color background black white
    color article    black white
    newsbeuter-2.7/contrib/colorschemes/plain000066400000000000000000000005411220711462700207230ustar00rootroot00000000000000# plain color scheme for newsbeuter 
    # boring black and white color configuration that resembles the classic look of really old terminals
    
    color listnormal default default
    color listfocus  default default reverse bold
    color info       default default reverse
    color background default default
    color article    default default
    newsbeuter-2.7/contrib/colorschemes/psychedelic000066400000000000000000000002761220711462700221210ustar00rootroot00000000000000# a psychedelic newsbeuter color scheme
    
    color listnormal magenta green
    color listfocus  blue yellow
    color info       cyan red dim
    color background white cyan
    color article    black magenta
    newsbeuter-2.7/contrib/colorschemes/schleichfahrt000066400000000000000000000003501220711462700224250ustar00rootroot00000000000000# a newsbeuter color scheme especially designed for dark environments
    
    color listnormal red black
    color listfocus  red black bold reverse
    color info       red black reverse bold
    color background red black
    color article    red black
    newsbeuter-2.7/contrib/colorschemes/simple000066400000000000000000000002701220711462700211100ustar00rootroot00000000000000# a simple newsbeuter color scheme.
    
    color listnormal white black
    color listfocus  yellow red bold
    color info       cyan blue
    color background white black
    color article    white black
    newsbeuter-2.7/contrib/colorschemes/solarized-dark000066400000000000000000000004611220711462700225340ustar00rootroot00000000000000# solarized color scheme for newsbeuter 
    # more on solarized: http://ethanschoonover.com/solarized
    
    color listnormal color244 color234
    color listfocus  color166 color235 
    color info       color136 color235 
    color background color244 color234
    color article    color244 color234
    newsbeuter-2.7/contrib/f1sa.rb000077500000000000000000000054601220711462700163760ustar00rootroot00000000000000#!/usr/bin/ruby
    #
    # get, parse and enrich heise rss feeds
    #
    # call with the feed specified you like to retrieve. Currently supported:
    #
    #  news      - heise newsticker
    #  teleopils - Telepolis
    #  security  - heise security news
    #
    # Change history
    #
    #  26.06.2009    erb    suppressed error messages due to unrepsonsive servers
    #
    
    require 'net/http'
    require 'uri'
    
    require 'rexml/document'
    include REXML
    
    require 'hpricot'
    
    require "open-uri"
    require 'timeout'
    
    #try to retrieve web site, following up to 5 redirects
    def geturl(url, depth=5)
      raise ArgumentError, 'Followed more 4 redirections. Stopping this nightmare now.' if depth == 0
      response = Net::HTTP.get_response(URI.parse(url))
      case response
        when Net::HTTPSuccess     then response.body
        when Net::HTTPRedirection then geturl(response['location'], depth-1) # follow redirection
      else
        # any other error shall not make any noise (maybe shall we produce a fake RSS item)
        ""
      end
    end
    
    if ENV['http_proxy'].nil? && !ENV['HTTP_PROXY'].nil?
      ENV['http_proxy'] = ENV['HTTP_PROXY']
    end
    
    feedurl="http://www.f1sa.com/index2.php?option=com_rss&feed=RSS2.0&no_html=1"
    
    # get feed
    feed_text = ""
    retries=4
    begin
      Timeout::timeout(15) do
        f = open(feedurl)
        feed_text = f.read unless f.nil?
      end
    rescue Timeout::Error
      retries -= 1
      exit 1 if retries < 1
      sleep 1
      retry
    rescue
      # any other error shall not make any noise (maybe shall we produce a fake RSS item)
    end
    
    exit 2 if feed_text.length < 20
    
    #print "Got this feed: ", feed_text, "\n"; STDOUT.flush
    
    xml = Document.new(feed_text)
    
    #loop over items
    xml.elements.each("//item") do |item|
      # extract link to article
      article_url = item.elements['link'].text
    
      # get full text for article
      begin
        article = open(article_url)
      rescue
        next
      end
      next if article.nil?
    
      article_text=""
      begin
        article_xml = Hpricot(article)
      rescue
        next
      end
    
      #puts "Got article from #{article_url}"
    
      # F1SA special: extract the division:
      #   first 
    # and combine them in that order article_xml.search("//div[@id]").each do |divitem| if divitem.attributes['id'] == "body_outer" article_text = "
    " article_text << divitem.inner_html << "
    " break end end article_text.gsub!(/.*\Z/m, "") #puts "Got this text: #{article_text}" # get rid of comments and other annoying artifacts article_text.gsub!(//, "") article_text.gsub!(/\s+/m, " ") next if article_text.length < 10 # insert full text article into feed item.delete_element("description") description = Element.new("description") description.text= CData.new(article_text) item.add_element(description) guid = Element.new("guid") guid.text= article_url item.add_element(guid) end #reproduce enriched feed xml.write($stdout, -1) newsbeuter-2.7/contrib/feedgrabber.rb000077500000000000000000000057341220711462700200000ustar00rootroot00000000000000#!/usr/bin/ruby # # This module has the methods to get, parse and enrich rss feeds # # Change history # # 29.03.2010 erb classes and methods to ease up feed parser writing # require 'net/http' require "uri" require 'timeout' require 'gdbm' # # This class capsules DB caching and HTTP getting pages for articles # # You instantiate a FeedGrabber giving at least a unique feed name (for DB # name generation) Then you can call getURL with the article url to get. If # it is found in the cache, that one is retrieved. If you parsed your feed # you should call cleanupDB to get rid of all those unused entries in the # cache # #module FeedGrabber class FeedGrabber # create a FeedGrabber instance def initialize(uniqueName, path = nil, retries = 4, depth = 5, timeout = 15) path = File.expand_path("~") if path.nil? @dbCacheName = "#{path}/.newsbeuter/#{uniqueName}.db" # generate db cache filename @maxRetries = retries @maxDepth = depth @timeout = timeout @usedURLs = Array.new # empty array to hold used URLs end # # try to retrieve web site, following up to maxDepth redirects, having up to maxRetries retries # def getURL_uncached(url) result = nil retries = @maxRetries begin Timeout::timeout(@timeout) do tempurl = url depth = @maxRetries while true raise ArgumentError, "Followed more #{@maxDepth} redirections. Stopping this nightmare now." if depth == 0 response = Net::HTTP.get_response(URI.parse(tempurl)) case response when Net::HTTPSuccess then result = response.body break when Net::HTTPRedirection then tempurl = response['location'] depth -= 1 next # follow redirection end end end rescue Timeout::Error retries -= 1 exit 1 if retries < 1 sleep 1 retry rescue # maybe an ArgumentError or anything the net layer throws # any other error shall not make any noise (maybe shall we produce a fake RSS item) end result end # # get url, but create and use a DB cache for each feed # def getURL(url) @usedURLs << url # remember, we used that URL for cleanup later db = GDBM.new(@dbCacheName) if db.has_key?(url) data = db[url] # get cached data from DB else # not in DB? so get it and store it into DB data = getURL_uncached(url) db[url] = data end db.close data end # # remove all URLs not used from DB cache # def cleanupDB toRemove = Array.new db = GDBM.new(@dbCacheName) db.each_key do |key| toRemove << key if @usedURLs.index(key) == nil end toRemove.each do |url| db.delete(url) end db.close end end #class #end # module newsbeuter-2.7/contrib/fixwesnoth.xsl000066400000000000000000000021111220711462700201300ustar00rootroot00000000000000 <xsl:value-of select="title" /> <xsl:value-of select="title" /> newsbeuter-2.7/contrib/heise.rb000077500000000000000000000070231220711462700166360ustar00rootroot00000000000000#!/usr/bin/ruby # # get, parse and enrich heise rss feeds # # call with the feed specified you like to retrieve. Currently supported: # # news - heise newsticker # teleopils - Telepolis # security - heise security news # # Change history # # 26.06.2009 erb suppressed error messages due to unrepsonsive servers # 28.03.2010 erb Added DB cache to speed things up (significantly!) # $:.push(File.dirname($0)) require 'feedgrabber' require 'rexml/document' include REXML if ENV['http_proxy'].nil? && !ENV['HTTP_PROXY'].nil? ENV['http_proxy'] = ENV['HTTP_PROXY'] end # key feed URL FEEDS = { "news" => "http://www.heise.de/newsticker/heise-atom.xml", "telepolis" => "http://www.heise.de/tp/news-atom.xml", "security" => "http://www.heise.de/security/news/news-atom.xml", "netze" => "http://www.heise.de/netze/rss/netze-atom.xml", "it-blog" => "http://www.heise.de/developer/rss/world-of-it/blog-atom.xml" } GOOGLEON="" GOOGLEOFF="" def listFeeds FEEDS.each_key { |k| print " #{k}\n" } end if ARGV.length < 1 print "usage: #{File::basename($0)} \n" print " is one of\n" listFeeds exit end def shortenArticle(article_text) article_text.gsub!(//, "") # now, heise speciality: get everything between GOOGLEON and GOOGLEOFF patterns :-) p1 = article_text.index(GOOGLEON) p2 = article_text.index(GOOGLEOFF) if (p1 && p2) result = "" pos = p1 while(pos < article_text.length) do p1 = article_text.index(GOOGLEON, pos) break unless p1 p2 = article_text.index(GOOGLEOFF, pos) p2 = article_text.length unless p2 if p1 < p2 result += article_text[p1+GOOGLEON.length..p2-1] pos = p2+GOOGLEOFF.length else pos = p1+GOOGLEON.length end end article_text = result end # get rid of comments and other annoying artifacts article_text.gsub!(/]*>/m, " ") article_text.gsub!(//, "") article_text.gsub!(/\s+/m, " ") article_text.gsub!(/href=\"\//m, "href=\"http://www.heise.de/") article_text.gsub!(/src=\"\//m, "src=\"http://www.heise.de/") article_text end feed=ARGV[0] unless FEEDS.has_key?(feed) print "unknown feed '#{feed}'. Use one of these:\n" listFeeds exit end feedurl = FEEDS[feed] #get feed fg = FeedGrabber.new("heisecache-#{feed}") feed_text = fg.getURL_uncached(feedurl) exit 2 unless feed_text && feed_text.length > 20 xml = Document.new(feed_text) #loop over items xml.elements.each("//entry") do |item| # extract link to article article_url = item.elements['id'].text article_url.sub!(%r{from/.*$}, "") article_short_url = article_url.sub(%r{/[^/]*--/}, "/") # get full text for article article_text = fg.getURL(article_url) next unless article_text && article_text.length > 20 # extract article comment link begin comments = /Kommentare

    " if comments.length > 5 && comments.length < 150 # insert full text article into feed description = Element.new("content") description.add_attribute("type", "html") description.text= CData.new(article_text) item.add_element(description) end fg.cleanupDB # reproduce the content enriched feed xml.write($stdout, -1) newsbeuter-2.7/contrib/pinboard.pl000077500000000000000000000024431220711462700173500ustar00rootroot00000000000000#!/usr/bin/perl use strict; use LWP::UserAgent; use URI::Escape; # Daemonising the bookmarking process # Use this only is you are sure things # are working as expected # set to '0' if not needed my $daemon = 1; if ($daemon){ eval{ require Proc::Daemon; Proc::Damoen->import(); }; unless ($@){ Proc::Daemon::Init(); } } my $API_URL='https://api.pinboard.in/v1/posts/add?'; my $bkmrk_url=''; my $tag='newsbeuter'; my $API_token='***REPLACE***'; # Get yours at https://pinboard.in/settings/password # Of the form 'username:alphanumeric' # Get redirected URL's permalink my $ua = LWP::UserAgent->new( requests_redirectable => [], ); # $ARGV[0] is the URL of the article # $ARGV[1] is the title of the article my $res = $ua->get($ARGV[0]); if ($res->status_line == 301){ $bkmrk_url = $res->header( 'location'); }else{ $bkmrk_url = $ARGV[0]; } my $safe_desc=uri_escape($ARGV[1]); my $pinboard_url = $API_URL . "url=$bkmrk_url&tags=$tag&shared=no&toread=yes&description=$safe_desc&auth_token=$API_token"; my $content = `curl -s \"$pinboard_url\"`; if ($content =~ m!!){ # print "Added to Pinboard\n"; }else{ print "Something went wrong, not added. "; print "See response: $content" if $content; } newsbeuter-2.7/contrib/slashdot.rb000077500000000000000000000042371220711462700173660ustar00rootroot00000000000000#!/usr/bin/ruby # # get, parse and enrich slashdot rss feed # # Change history # # 26.06.2009 erb stopped error from appearing if servers do not respond # $:.push(File.dirname($0)) require 'feedgrabber' require 'rexml/document' include REXML require 'hpricot' if ARGV.length > 0 print "usage: #{File::basename($0)}\n" exit end if ENV['http_proxy'].nil? && !ENV['HTTP_PROXY'].nil? ENV['http_proxy'] = ENV['HTTP_PROXY'] end feedurl = 'http://rss.slashdot.org/Slashdot/slashdot' fg = FeedGrabber.new("slashdot") feed_text = fg.getURL_uncached(feedurl) exit 3 unless feed_text && feed_text.length >= 20 xml = Document.new(feed_text) xml.elements.each("//item") do |item| # correct entities in title title=item.elements['title'].text title.gsub!("\&", "\&") title.gsub!("\&", "\&") # needs to be in there twice, because the error is in there twice :-) title.gsub!("\‘", "\"") title.gsub!("\’", "\"") title.gsub!("\&quo;", "\"") title.gsub!("\—", "--") item.elements['title'].text= title # extract link to article article_url = item.attributes.get_attribute('rdf:about').value article_url.sub!(%r{\?from=rss$}, "/") # get full text for article begin article = fg.getURL(article_url) rescue next end next unless article && article.length >= 20 # now parse the article article_text="" begin article_xml = Hpricot(article) rescue next end # /. special: extract the two divisions: # first
    # first
    # and combine them in that order article_xml.search("//div[@id]").each do |divitem| if divitem.attributes['id'][0,5] == "text-" article_text = "
    " article_text << divitem.inner_html << "
    " break end end article_text << "
    " << article_xml.search("//div[@class='bodytext']").inner_html << "
    " # get rid of comments and other annoying artifacts article_text.gsub!(//, "") article_text.gsub!(/\s+/m, " ") next if article_text.length < 10 # set full text article into feed item.elements['description'].text= CData.new(article_text) end fg.cleanupDB xml.write($stdout, -1) newsbeuter-2.7/doc/000077500000000000000000000000001220711462700143145ustar00rootroot00000000000000newsbeuter-2.7/doc/chapter-cmdline.txt000066400000000000000000000040011220711462700201070ustar00rootroot00000000000000Like other text-oriented software, newsbeuter contains an internal commandline to modify configuration variables ad hoc and to run own commands. It provides a flexible access to the functionality of newsbeuter which is especially useful for advanced users. To start the commandline, type ":". You will see a ":" prompt at the bottom of the screen, similar to tools like vi(m) or mutt. You can now enter commands. Pressing the return key executes the command (possibly giving feedback to the user) and closes the commandline. You can cancel entering commands by pressing the ESC key. The history of all the commands that you enter will be saved to \~/.newsbeuter/history.cmdline. The backlog is limited to 100 entries by default, but can be influenced by setting the "history-limit" configuration variable. To disable history saving, set the history-limit to 0. Starting with newsbeuter 2.0, the commandline provides you with some help if you can't remember the full names of commandline commands. By pressing the TAB key, newsbeuter will try to automatically complete your command. If there is more than one possible completion, you can subsequently press the TAB key to cycle through all results. If no match is found, no suggestion will be inserted into the commandline. For the "set" command, the completion also works for configuration variable names. In addition, some common key combination such as Ctrl-G (to cancel input), Ctrl-K (to delete text from the cursor position to the end of line), Ctrl-U (to clear the whole line) and Ctrl-W (to delete the word before the current cursor position) were added. Please be aware that the input history of both the command line and the search functions are saved to the filesystems, to the files \~/.newsbeuter/history.cmdline resp. \~/.newsbeuter/history.search. By default, the last 100 entries are saved, but this can be configured (configuration variable history-limit) and also totally disabled (by setting said variable to 0). Currently, the following command line commands are available: newsbeuter-2.7/doc/chapter-firststeps.txt000066400000000000000000000135261220711462700207160ustar00rootroot00000000000000After you've installed newsbeuter, you can run it for the first time by typing "newsbeuter" on your command prompt. This will bring you the following message: Error: no URLs configured. Please fill the file /home/ak/.newsbeuter/urls with RSS feed URLs or import an OPML file. newsbeuter 2.4 usage: ./newsbeuter [-i |-e] [-u ] [-c ] [-x ...] [-h] -e export OPML feed to stdout -r refresh feeds on start -i import OPML file -u read RSS feed URLs from -c use as cache file -C read configuration from -X clean up cache thoroughly -x ... execute list of commands -o activate offline mode (only applies to Google Reader synchronization mode) -q quiet startup -v get version information -l write a log with a certain loglevel (valid values: 1 to 6) -d use as output log file -E export list of read articles to -I import list of read articles from -h this help This means that newsbeuter can't start without any configured feeds. To add feeds to newsbeuter, you can either add URLs to the configuration file $HOME/.newsbeuter/urls or you can import an OPML file by running "newsbeuter -i blogroll.opml". To manually add URLs, open the file with your favorite text editor and add the URLs, one per line: http://rss.cnn.com/rss/cnn_topstories.rss http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml If you need to add URLs that have restricted access via username/password, simply provide the username/password in the following way: http://username:password@hostname.domain.tld/feed.rss In order to protect username and password, make sure that $HOME/.newsbeuter/urls has the appropriate permissions. Newsbeuter also makes sure that usernames and passwords within URLs aren't displayed in its user interface. In case there is a '@' in the username, you need to write it as '%40' instead so that it can be distinguished from the '@' that separates the username/password part from the hostname part. You can also configure local files as feeds, by prefixing the local path with "file://" and adding it to the $HOME/.newsbeuter/urls file: file:///var/log/rss_eventlog.xml Now you can run newsbeuter again, and it will present you with a controllable list of the URLs that you configured previously. You can now start downloading the feeds, either by pressing "R" to download all feeds, or by pressing "r" to download the currently selected feed. You can then select a feed you want to read, and by pressing "Enter", you can go to the article list for this feed. This works even while the downloading is still in progress. You can now see the list of available articles by their title. A "N" on the left indicates that an article wasn't read yet. Pressing Enter brings you to the content of the article. You can scroll through this text, and also run a browser (default: lynx) to view the complete article if the content is empty or just an abstract or a short description. Pressing "q" brings you back to the article list, and pressing "q" again brings you back to the feed list. Pressing "q" a third time then closes newsbeuter. Newsbeuter caches the article that it downloads. This means that when you start newsbeuter again and reload a feed, the old articles can still be read even if they aren't in the current RSS feeds anymore. Optionally you can configure how many articles shall be preserved by feed so that the article backlog doesn't grow endlessly (see "max-items" below). Newsbeuter also uses a number of measures to preserve the users' and feed providers' bandwidth, by trying to avoid unnecessary feed downloads through the use of conditional HTTP downloading. It saves every feed's "Last-Modified" and "ETag" response header values (if present) and advises the feed's HTTP server to only send data if the feed has been updated by modification date/time or "ETag" header. This doesn't only make feed downloads for RSS feeds with no new updates faster, it also reduces the amount of transferred data per request. Conditional HTTP downloading can be optionally disabled per feed by using the "always-download" configuration command. Several aspects of newsbeuter's behaviour can be configured via a configuration file, by default $HOME/.newsbeuter/config. This configuration file contains lines in the form " ...". The configuration file can also contain comments, which start with the '#' character and go as far as the end of line. If you need to enter a configuration argument that contains spaces, use quotes (") around the whole argument. It's even possible to integrate the output of external commands into the configuration. The text between two backticks ("`") is evaluated as shell command, and its output is put on its place instead. This works like backtick evaluation in Bourne-compatible shells and allows users to use external information from the system within the configuration. Searching for articles is possible in newsbeuter, too. Just press the "/" key, enter your search phrase, and the title and content of all articles are searched for it. When you do a search from the list of feeds, all articles of all feeds will be searched. When you do a search from the article list of a feed, only the articles of the currently viewed feed are searched. When opening an article from a search result dialog, the search phrase is highlighted. The history of all your searches is saved to the filesystem, to \~/.newsbeuter/history.search. By default, the last 100 search phrases are stored, but this limited can be influenced through the "history-limit" configuration variable. To disable search history saving, simply set the history-limit to 0. newsbeuter-2.7/doc/chapter-podcasts.txt000066400000000000000000000025601220711462700203240ustar00rootroot00000000000000A podcast is a media file distributed over the internet using syndication feeds such as RSS, for later playback on portable players or computers. Newsbeuter contains support for downloading and saving podcasts. This support differs a bit from other podcast aggregators or "podcatchers" in how it is done. Podcast content is transported in RSS feeds via special tags called "enclosures". Newsbeuter recognizes these enclosures and stores the relevant information for every podcast item it finds in an RSS feed. Since version 2.0, it also recognizes and handles the Yahoo Media RSS extensions. What the user then can do is to add the podcast download URL to a download queue. Alternatively, newsbeuter can be configured to automatically do that. This queue is stored in the file $HOME/.newsbeuter/queue. The user can then use the download manager "podbeuter" to download these files to a directory on the local filesystem. Podbeuter comes with the newsbeuter package, and features a look and feel very close to the one of newsbeuter. It also shares the same configuration file. Podcasts that have been downloaded but haven't been played yet remain in the queue but are marked as downloaded. You can remove them by purging them from the queue with the 'P' key. After you've played a file and close podbeuter, it will be removed from the queue. The downloaded file remains on the filesystem. newsbeuter-2.7/doc/chapter-snownews.txt000066400000000000000000000034721220711462700203720ustar00rootroot00000000000000From version 0.4 on, newsbeuter contains support for Snownews extensions. The RSS feed readers Snownews and Liferea share a common way of extending the readers with custom scripts. Two mechanisms, namely "execurl" and "filter" type scripts, are available and supported by newsbeuter. An "execurl" script can be any program that gets executed and whose output is interpreted as RSS feed, while "filter" scripts are fed with the content of a configured URL and whose output is interpreted as RSS feed. The configuration is simple and straight-forward. Just add to your ~/.newsbeuter/urls file configuration lines like the following ones: exec:~/bin/execurl-script filter:~/bin/filter-script:http://some.test/url The first line shows how to add an execurl script to your configuration: start the line with "exec:" and then immediately append the path of the script that shall be executed. If this script requires additional parameters, simply use quotes: "exec:~/bin/execurl-script param1 param2" The second line shows how to add a filter script to your configuration: start the line with "filter:", then immediately append the path of the script, then append a colon (":"), and then append the URL of the file that shall be fed to the script. Again, if the script requires any parameters, simply quote: "filter:~/bin/filter-script param1 param2:http://url/foobar" In both cases, the tagging feature as described above is still available: exec:~/bin/execurl-script tag1 tag2 "quoted tag" filter:~/bin/filter-script:http://some.test/url tag3 tag4 tag5 A collection of such extension scripts can be found on this website: http://kiza.kcore.de/software/snownews/snowscripts/extensions[] If you want to write your own extensions, refer to this website for further instructions: http://kiza.kcore.de/software/snownews/snowscripts/writing[] newsbeuter-2.7/doc/chapter-tagging.txt000066400000000000000000000033151220711462700201230ustar00rootroot00000000000000Newsbeuter comes with the possibility to categorize or "tag", as we call it, RSS feeds. Every RSS feed can be assigned 0 or more tags. Within newsbeuter, you can then select to only show RSS feeds that match a certain tag. That makes it easy to categorize your feeds in a flexible and powerful way. Usually, the \~/.newsbeuter/urls file contains one RSS feed URL per line. To assign a tag to an RSS feed, simply attach it as a single word, separated by blanks such as space or tab. If the tag needs to contain spaces, you must use quotes (") around the tag (see example below). An example \~/.newsbeuter/urls file may look like this: http://blog.fefe.de/rss.xml?html interesting conspiracy news "cool stuff" http://rss.orf.at/news.xml news orf http://www.heise.de/newsticker/heise.rdf news interesting When you now start newsbeuter with this configuration, you can press "t" to select a tag. When you select the tag "news", you will see all three RSS feeds. Pressing "t" again and e.g. selecting the "conspiracy" tag, you will only see the http://blog.fefe.de/rss.xml?html RSS feed. Pressing "^T" clears the current tag, and again shows all RSS feeds, regardless of their assigned tags. A special type of tag are tags that start with the tilde character ("\~"). When such a tag is found, the feed title is set to the tag name (excluding the \~ character). With this feature, you can give feeds any title you want in your feed list: http://rss.orf.at/news.xml "~ORF News" Another special type of tag are tags that start with the exclamation mark. When such a tag is found, the feed is hidden from the regular list of feeds and its content can only be found through a query feed. http://rss.orf.at/news.xml "!ORF News (hidden)" newsbeuter-2.7/doc/configcommands.dsv000066400000000000000000000444461220711462700200350ustar00rootroot00000000000000always-display-description|[true/false]|false|If true, then the description will always displayed even if e.g. a content:encoded tag has been found.|always-display-description true always-download| []|n/a|The parameters of this configuration command are one or more RSS URLs. These URLs will always get downloaded, regardless of their Last-Modified timestamp and ETag header.|always-download "http://www.n-tv.de/23.rss" article-sort-order|[-]|date|The sortfield specifies which article property shall be used for sorting (currently available: date, title, flags, author, link, guid). The optional direction specifies the sort direction ("asc" specifies ascending sorting, "desc" specifies descending sorting. for date, "desc" is default, for all others, "asc" is default).|article-sort-order author-desc articlelist-format||"%4i %f %D %6L %?T?;%-17T; ?%t"|This variable defines the format of entries in the article list. See the respective section in the documentation for more information on format strings (note that the semicolon should actually be a vertical bar; this is a limitation in AsciiDoc).|articlelist-format "%4i %f %D %?T?;%-17T; ?%t" auto-reload|[yes/no]|no|If enabled, all feeds will be automatically reloaded at start up and then continuously after a certain time has passed (see reload-time).|auto-reload yes bind-key| []|n/a|Bind key to . This means that whenever is pressed, then is executed (if applicable in the current dialog). A list of available operations can be found below. Optionally, you can specify a dialog. If you specify one, the key binding will only be added to the specified dialog. Available dialogs are "all" (default if none is specified), "feedlist", "filebrowser", "help", "articlelist", "article", "tagselection", "filterselection", "urlview" and "podbeuter".|bind-key ^R reload-all bookmark-cmd||""|If set, then will be used as bookmarking plugin. See the documentation on bookmarking for further information.|bookmark-cmd "~/bin/delicious-bookmark.sh" bookmark-interactive|[yes/no]|no|If set to yes, then the configured bookmark command is an interactive program.|bookmark-interactive yes bookmark-autopilot|[yes/no]|no|If set to yes, the configured bookmark command is executed without any further input asked from user, uless the url or the title cannot be found/guessed.|bookmark-autopilot yes browser||lynx|Set the browser command to use when opening an article in the browser. If contains %u, it will be used as complete commandline and %u will be replaced with the URL that shall be opened.|browser "w3m %u" cache-file||"~/.newsbeuter/cache.db"|This configuration option sets the cache file. This is especially useful if the filesystem of your home directory doesn't support proper locking (e.g. NFS).|cache-file "/tmp/testcache.db" cleanup-on-quit|[yes/no]|yes|If yes, then the cache gets locked and superfluous feeds and items are removed, such as feeds that can't be found in the urls configuration file anymore.|cleanup-on-quit no color| [ ...]|n/a|Set the foreground color, background color and optional attributes for a certain element|color background white black confirm-exit|[yes/no]|no|If set to yes, then newsbeuter will ask for confirmation whether the user really wants to quit newsbeuter.|confirm-exit yes cookie-cache||""|Set a cookie cache. If set, then cookies will be cached (i.e. read from and written to) in this file.|cookie-cache "~/.newsbeuter/cookies.txt" datetime-format||%b %d|This format specifies the date/time format in the article list. For a detailed documentation on the allowed formats, consult the manpage of strftime(3).|datetime-format "%D, %R" define-filter| |n/a|With this command, you can predefine filters, which can you later select from a list, and which are then applied after selection. This is especially useful for filters that you need often and you don't want to enter them every time you need them.|define-filter "all feeds with 'fun' tag" "tags # \\"fun\\"" delete-read-articles-on-quit|[yes/no]|"no"|If set to "yes", then all read articles will be deleted when you quit newsbeuter.|delete-read-articles-on-quit yes display-article-progress|[yes/no]|yes|If set to yes, then a read progress (in percent) is displayed in the article view. Otherwise, no read progress is displayed.|display-article-progress no download-retries||1|How many times newsbeuter shall try to successfully download a feed before giving up. This is an option to improve the success of downloads on slow and shaky connections such as via a TOR proxy.|download-retries 4 download-full-page|[yes/no]|no|If set to yes, then for all feed items with no content but with a link, the link is downloaded and the result used as content instead. This may significantly increase the download times of "empty" feeds.|download-full-page yes download-timeout||30|The number of seconds newsbeuter shall wait when downloading a feed before giving up. This is an option to improve the success of downloads on slow and shaky connections such as via a TOR proxy.|download-timeout 60 error-log||""|If set, then user errors (e.g. errors regarding defunct RSS feeds) will be logged to this file.|error-log "~/.newsbeuter/error.log" external-url-viewer||""|If set, then "show-urls" will pipe the current article to a specific external tool instead of using the internal URL viewer. This can be used to integrate tools such as urlview.|external-url-viewer "urlview" feed-sort-order||none|If set to "firsttag", the feeds in the feed list will be sorted by their first tag in the urls file.|feed-sort-order firsttag feedlist-format||"%4i %n %11u %t"|This variable defines the format of entries in the feed list. See the respective section in the documentation for more information on format strings.|feedlist-format " %n %4i - %11u -%> %t" googlereader-flag-share||""|If this is set and Google Reader support is used, then all articles that are flagged with the specified flag are being "shared" in Google Reader so that people that follow you can see it.|googlereader-flag-share "a" googlereader-flag-star||""|If this is set and Google Reader support is used, then all articles that are flagged with the specified flag are being "starred" in Google Reader and appear in the list of "Starred items".|googlereader-flag-star "b" googlereader-login||""|This variable sets your Google Reader login for the Google Reader support.|googlereader-login "your-login" googlereader-min-items||20|This variable sets the number of articles that are loaded from Google Reader per feed.|googlereader-min-items 100 googlereader-password||""|This variable sets your Google Reader password for the Google Reader support.|googlereader-password "your-password" googlereader-passwordfile| [ [ ...]]|n/a|With this command, you can highlight text parts in the feed list, the article list and the article view. For a detailed documentation, see the chapter on highlighting.|highlight all "newsbeuter" red highlight-article| [ ...]|n/a|With this command, you can highlight articles in the article list if they match a filter expression. For a detailed documentation, see the chapter on highlighting.|highlight-article "author =~ \\"Andreas Krennmair\\"" white red bold history-limit||100|Defines the maximum number of entries of commandline resp. search history to be saved. To disable history saving, set history-limit to 0.|history-limit 0 html-renderer||internal|If set to "internal", then the internal HTML renderer will be used. Otherwise, the specified command will be executed, the HTML to be rendered will be written to the command's stdin, and the program's output will be displayed. This makes it possible to use other, external programs, such as w3m, links or lynx, to render HTML.|html-renderer "w3m -dump -T text/html" http-auth-method||any|Set HTTP authentication method. Allowed values: any, basic, digest, digest_ie (only available with libcurl 7.19.3 and newer), gssnegotiate, ntlm, anysafe.|http-auth-method digest ignore-article| |n/a|If a downloaded article from matches , then it is ignored and not presented to the user. This command is further explained in the "kill file" section below.|ignore-article "*" "title =~ \\"Windows\\"" ignore-mode|[download/display]|download|This configuration option defines in what way an article is ignored (see ignore-article). If set to "download", then it is ignored in the download/parsing phase (which is the default) and thus never written to the cache, if it set to "display", it is ignored when displaying articles but is kept in the cache.|ignore-mode "display" include||n/a|With this command, you can include other files to be interpreted as configuration files. This is especially useful to separate your configuration into several files, e.g. key configuration, color configuration, ...|include "~/.newsbeuter/colors" keep-articles-days||0|If set the a number greater than 0, only articles that are were published within the last days are kept, and older articles are deleted. If set to 0 (default value), this option is not active.|keep-articles-days 30 macro| |n/a|With this command, you can define a macro key and specify a list of commands that shall be executed when the macro prefix and the macro key are pressed.|macro k open ; reload ; quit mark-as-read-on-hover|[yes/no]|no|If set to yes, then all articles that get selected in the article list are marked as read.|mark-as-read-on-hover yes max-download-speed||0|If set to a number great than 0, the download speed per download is set to that limit (in kB).|max-download-speed 50 max-items||0|Set the number of articles to maximally keep per feed. If the number is set to 0, then all articles are kept.|max-items 100 notify-format||"newsbeuter: finished reload, %f unread feeds (%n unread articles total)"|Format string that is used for formatting notifications. See the chapter on format strings for more information.|notify-format "%d new articles (%n unread articles, %f unread feeds)" notify-program||""|If set, then the configured program will be executed if new articles arrived (through a reload) or if notify-always is true. The first parameter of the called program contains the notification message.|notify-program "~/bin/my-notifier" notify-always|[yes/no]|no|If no, notifications will only be made when there are new feeds or articles. If yes, notifications will be made regardless.|notify-always yes notify-screen|[yes/no]|no|If yes, then a "privacy message" will be sent to the terminal, containing a notification message about new articles. This is especially useful if you use terminal emulations such as GNU screen which implement privacy messages.|notify-screen yes notify-xterm|[yes/no]|no|If yes, then the xterm window title will be set to a notification message about new articles.|notify-xterm yes notify-beep|[yes/no]|no|If yes, then the speaker beep on new articles.|notify-beep yes opml-url| ...|""|If the OPML online subscription mode is enabled, then the list of feeds will be taken from the OPML file found on this location. Optionally, you can specify more than one URL. All the listed OPML URLs will then be taken into account when loading the feed list.|opml-url "http://host.domain.tld/blogroll.opml" "http://example.com/anotheropmlfile.opml" pager|[/internal]|internal|If set to "internal", then the internal pager will be used. Otherwise, the article to be displayed will be rendered to be a temporary file and then displayed with the configured pager. If the pager path is set to an empty string, the content of the "PAGER" environment variable will be used. If the pager path contains a placeholder "%f", it will be replaced with the temporary filename.|less %f podcast-auto-enqueue|[yes/no]|no|If yes, then all podcast URLs that are found in articles are added to the podcast download queue. See the respective section in the documentation for more information on podcast support in newsbeuter.|podcast-auto-enqueue yes prepopulate-query-feeds|[yes/no]|no|If yes, then all query feeds are prepopulated with articles on startup.|prepopulate-query-feeds yes proxy||n/a|Set the proxy to use for downloading RSS feeds.|proxy localhost:3128 proxy-auth||n/a|Set the proxy authentication string.|proxy-auth user:password proxy-auth-method||any|Set proxy authentication method. Allowed values: any, basic, digest, digest_ie (only available with libcurl 7.19.3 and newer), gssnegotiate, ntlm, anysafe.|proxy-auth-method ntlm proxy-type||http|Set proxy type. Allowed values: http, socks4, socks4a, socks5.|proxy-type socks5 refresh-on-startup|[yes/no]|no|If yes, then all feeds will be reloaded when newsbeuter starts up. This is equivalent to the -r commandline option.|refresh-on-startup yes reload-only-visible-feeds|[yes/no]|no|If yes, then manually reloading all feeds will only reload the currently visible feeds, e.g. if a filter or a tag is set.|reload-only-visible-feeds yes reload-time||60|The number of minutes between automatic reloads.|reload-time 120 reload-threads||1|The number of parallel reload threads that shall be started when all feeds are reloaded.|reload-threads 3 reset-unread-on-update| ...|n/a|With this configuration command, you can provide a list of RSS feed URLs for whose articles the unread flag will be reset if an article has been updated, i.e. its content has been changed. This is especially useful for RSS feeds where single articles are updated after publication, and you want to be notified of the updates.|reset-unread-on-update "http://blog.fefe.de/rss.xml?html" save-path||~/|The default path where articles shall be saved to. If an invalid path is specified, the current directory is used.|save-path "~/Saved Articles" search-highlight-colors| [ ...]|black yellow bold|This configuration command specifies the highlighting colors when searching for text from the article view.|search-highlight-colors white black bold show-keymap-hint|[yes/no]|yes|If no, then the keymap hints on the bottom of screen will not be displayed.|show-keymap-hint no show-read-feeds|[yes/no]|yes|If yes, then all feeds, including those without unread articles, are listed. If no, then only feeds with one or more unread articles are list.|show-read-feeds no show-read-articles|[yes/no]|yes|If yes, then all articles of a feed are listed in the article list. If no, then only unread articles are listed.|show-read-articles no suppress-first-reload|[yes/no]|no|If yes, then the first automatic reload will be suppressed if auto-reload is set to yes.|suppress-first-reload yes swap-title-and-hints|[yes/no]|no|If yes, then the title at the top of screen and keymap hints at the bottom of screen will be swapped.|swap-title-and-hints yes text-width||0|If set to a number greater than 0, then all HTML will be rendered to this maximum line length. If set to 0, the terminal width will be used.|text-width 72 ttrss-flag-publish||""|If this is set and Tiny Tiny RSS support is used, then all articles that are flagged with the specified flag are being marked as "published" in Tiny Tiny RSS.|ttrss-flag-publish "b" ttrss-flag-star||""|If this is set and Tiny Tiny RSS support is used, then all articles that are flagged with the specified flag are being "starred" in Tiny Tiny RSS.|ttrss-flag-star "a" ttrss-login||""|Sets the username for use with Tiny Tiny RSS.|ttrss-login "admin" ttrss-mode|[multi/single]|multi|Configures the mode in which Tiny Tiny RSS is used. In single-user mode, login and password are used for HTTP authentication, while in multi-user mode, they are used for authenticating with Tiny Tiny RSS.|ttrss-mode "single" ttrss-password||""|Configures the password for use with Tiny Tiny RSS.|ttrss-password "mypassword" ttrss-url||""|Configures the URL where the Tiny Tiny RSS installation you want to use resides.|ttrss-url "http://example.com/ttrss/" unbind-key| []|n/a|Unbind key . This means that no operation is called when is pressed. Optionally, you can specify a dialog (for a list of available dialogs, see "bind-key" above). If you specify one, the key binding will only be unbound for the specified dialog.|unbind-key R urls-source||"local"|This configuration command sets the source where URLs shall be retrieved from. By default, this is ~/.newsbeuter/urls. Alternatively, you can set it to "opml", which enables newsbeuter's OPML online subscription mode, to "ttrss" which enables newsbeuter's Tiny Tiny RSS support, or to "googlereader", which enables newsbeuter's Google Reader support. In order to make Google Reader support work correctly, you also need to set googlereader-login and googlereader-password, while the Tiny Tiny RSS support requires login, password and URL of the Tiny Tiny RSS installation to use (see above).|urls-source "googlereader" use-proxy|[yes/no]|no|If yes, then the configured proxy will be used for downloading the RSS feeds.|use-proxy yes user-agent||""|If set to a non-zero-length string, this value will be used as HTTP User-Agent header for all HTTP requests.|user-agent "Lynx/2.8.5rel.1 libwww-FM/2.14" newsbeuter-2.7/doc/example-bookmark-plugin.sh000077500000000000000000000003671220711462700214130ustar00rootroot00000000000000#!/bin/sh # this is a simple example script that demonstrates how bookmarking plugins for newsbeuter are implemented # (c) 2007 Andreas Krennmair url="$1" title="$2" description="$3" echo -e "${url}\t${title}\t${description}" >> ~/bookmarks.txt newsbeuter-2.7/doc/example-config000066400000000000000000000370051220711462700171420ustar00rootroot00000000000000#################################### # newsbeuter example configuration # #################################### ## configuration option: always-display-description ## description: If true, then the description will always displayed even if e.g. a content:encoded tag has been found. ## parameter syntax: [true/false] # always-display-description false ## configuration option: article-sort-order ## description: The sortfield specifies which article property shall be used for sorting (currently available: date, title, flags, author, link, guid). The optional direction specifies the sort direction ("asc" specifies ascending sorting, "desc" specifies descending sorting. for date, "desc" is default, for all others, "asc" is default). ## parameter syntax: [-] # article-sort-order date ## configuration option: articlelist-format ## description: This variable defines the format of entries in the article list. See the respective section in the documentation for more information on format strings. ## parameter syntax: # articlelist-format "%4i %f %D %6L %?T?|%-17T| ?%t" ## configuration option: auto-reload ## description: If enabled, all feeds will be automatically reloaded at start up and then continuously after a certain time has passed (see reload-time). ## parameter syntax: [yes/no] # auto-reload no ## configuration option: bookmark-cmd ## description: If set, then will be used as bookmarking plugin. See the documentation on bookmarking for further information. ## parameter syntax: # bookmark-cmd "" ## configuration option: bookmark-interactive ## description: If set to yes, then the configured bookmark command is an interactive program. ## parameter syntax: [yes/no] # bookmark-interactive no ## configuration option: bookmark-autopilot ## description: If set to yes, the configured bookmark command is executed without any further input asked from user, uless the url or the title cannot be found/guessed. ## parameter syntax: [yes/no] # bookmark-autopilot no ## configuration option: browser ## description: Set the browser command to use when opening an article in the browser. If contains %u, it will be used as complete commandline and %u will be replaced with the URL that shall be opened. ## parameter syntax: # browser lynx ## configuration option: cache-file ## description: This configuration option sets the cache file. This is especially useful if the filesystem of your home directory doesn't support proper locking (e.g. NFS). ## parameter syntax: # cache-file "~/.newsbeuter/cache.db" ## configuration option: cleanup-on-quit ## description: If yes, then the cache gets locked and superfluous feeds and items are removed, such as feeds that can't be found in the urls configuration file anymore. ## parameter syntax: [yes/no] # cleanup-on-quit yes ## configuration option: confirm-exit ## description: If set to yes, then newsbeuter will ask for confirmation whether the user really wants to quit newsbeuter. ## parameter syntax: [yes/no] # confirm-exit no ## configuration option: datetime-format ## description: This format specifies the date/time format in the article list. For a detailed documentation on the allowed formats, consult the manpage of strftime(3). ## parameter syntax: # datetime-format %b %d ## configuration option: display-article-progress ## description: If set to yes, then a read progress (in percent) is displayed in the article view. Otherwise, no read progress is displayed. ## parameter syntax: [yes/no] # display-article-progress yes ## configuration option: download-retries ## description: How many times newsbeuter shall try to successfully download a feed before giving up. This is an option to improve the success of downloads on slow and shaky connections such as via a TOR proxy. ## parameter syntax: # download-retries 1 ## configuration option: download-timeout ## description: The number of seconds newsbeuter shall wait when downloading a feed before giving up. This is an option to improve the success of downloads on slow and shaky connections such as via a TOR proxy. ## parameter syntax: # download-timeout 30 ## configuration option: error-log ## description: If set, then user errors (e.g. errors regarding defunct RSS feeds) will be logged to this file. ## parameter syntax: # error-log "" ## configuration option: feed-sort-order ## description: If set to "firsttag", the feeds in the feed list will be sorted by their first tag in the urls file. ## parameter syntax: # feed-sort-order none ## configuration option: feedlist-format ## description: This variable defines the format of entries in the feed list. See the respective section in the documentation for more information on format strings. ## parameter syntax: # feedlist-format "%4i %n %11u %t" ## configuration option: googlereader-flag-share ## description: If this is set and Google Reader support is used, then all articles that are flagged with the specified flag are being "shared" in Google Reader so that people that follow you can see it. ## parameter syntax: # googlereader-flag-share "" ## configuration option: googlereader-flag-star ## description: If this is set and Google Reader support is used, then all articles that are flagged with the specified flag are being "starred" in Google Reader and appear in the list of "Starred items". ## parameter syntax: # googlereader-flag-star "" ## configuration option: googlereader-login ## description: This variable sets your Google Reader login for the Google Reader support. ## parameter syntax: # googlereader-login "" ## configuration option: googlereader-min-items ## description: This variable sets the number of articles that are loaded from Google Reader per feed. ## parameter syntax: # googlereader-min-items 20 ## configuration option: googlereader-password ## description: This variable sets your Google Reader password for the Google Reader support. ## parameter syntax: # googlereader-password "" ## configuration option: googlereader-show-special-feeds ## description: If this is set, then "special feeds" like "People you follow" (articles shared by people you follow), "Starred items" (your starred articles), "Shared items" (your shared articles) and "Popular items" (articles considered to be popular by Google's magic algorithms) appear in your subscription list. ## parameter syntax: [yes/no] # googlereader-show-special-feeds yes ## configuration option: goto-first-unread ## description: If set to yes (the default), then the first unread article will be selected whenever a feed is entered. ## parameter syntax: [yes/no] # goto-first-unread yes ## configuration option: goto-next-feed ## description: If set to yes, then the next-unread and prev-unread keys will search in other feeds for unread articles if all articles in the current feed are read. If set to no, then the next-unread and prev-unread keys will stop in the current feed. ## parameter syntax: [yes/no] # goto-next-feed yes ## configuration option: history-limit ## description: Defines the maximum number of entries of commandline resp. search history to be saved. To disable history saving, set history-limit to 0. ## parameter syntax: # history-limit 100 ## configuration option: html-renderer ## description: If set to "internal", then the internal HTML renderer will be used. Otherwise, the specified command will be executed, the HTML to be rendered will be written to the command's stdin, and the program's output will be displayed. This makes it possible to use other, external programs, such as w3m, links or lynx, to render HTML. ## parameter syntax: # html-renderer internal ## configuration option: ignore-mode ## description: This configuration option defines in what way an article is ignored (see ignore-article). If set to "download", then it is ignored in the download/parsing phase (which is the default) and thus never written to the cache, if it set to "display", it is ignored when displaying articles but is kept in the cache. ## parameter syntax: [download/display] # ignore-mode download ## configuration option: keep-articles-days ## description: If set to a number greater than 0, only articles that are were published within the last days are kept, and older articles are deleted. If set to 0 (default value), this option is not active. ## parameter syntax: # keep-articles-days 0 ## configuration option: mark-as-read-on-hover ## description: If set to yes, then all articles that get selected in the article list are marked as read. ## parameter syntax: [yes/no] # mark-as-read-on-hover no ## configuration option: max-items ## description: Set the number of articles to maximally keep per feed. If the number is set to 0, then all articles are kept. ## parameter syntax: # max-items 0 ## configuration option: notify-format ## description: Format string that is used for formatting notifications. See the chapter on format strings for more information. ## parameter syntax: # notify-format "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" ## configuration option: notify-program ## description: If set, then the configured program will be executed if new articles arrived (through a reload) or if notify-always is true. The first parameter of the called program contains the notification message. ## parameter syntax: # notify-program "" ## configuration option: notify-always ## description: If no, notifications will only be made when there are new feeds or articles. If yes, notifications will be made regardless. ## parameter syntax: [yes/no] # notify-always no ## configuration option: notify-screen ## description: If yes, then a "privacy message" will be sent to the terminal, containing a notification message about new articles. This is especially useful if you use terminal emulations such as GNU screen which implement privacy messages. ## parameter syntax: [yes/no] # notify-screen no ## configuration option: notify-xterm ## description: If yes, then the xterm window title will be set to a notification message about new articles. ## parameter syntax: [yes/no] # notify-xterm no ## configuration option: notify-beep ## description: If yes, then the speaker beep on new articles. ## parameter syntax: [yes/no] # notify-beep no ## configuration option: opml-url ## description: If the OPML online subscription mode is enabled, then the list of feeds will be taken from the OPML file found on this location. Optionally, you can specify more than one URL. All the listed OPML URLs will then be taken into account when loading the feed list. ## parameter syntax: ... # opml-url "" ## configuration option: pager ## description: If set to "internal", then the internal pager will be used. Otherwise, the article to be displayed will be rendered to be a temporary file and then displayed with the configured pager. If the pager path is set to an empty string, the content of the "PAGER" environment variable will be used. If the pager path contains a placeholder "%f", it will be replaced with the temporary filename. ## parameter syntax: [/internal] # pager internal ## configuration option: podcast-auto-enqueue ## description: If yes, then all podcast URLs that are found in articles are added to the podcast download queue. See the respective section in the documentation for more information on podcast support in newsbeuter. ## parameter syntax: [yes/no] # podcast-auto-enqueue no ## configuration option: prepopulate-query-feeds ## description: If yes, then all query feeds are prepopulated with articles on startup. ## parameter syntax: [yes/no] # prepopulate-query-feeds no ## configuration option: proxy-auth-method ## description: Set proxy authentication method. Allowed values: any, basic, digest, digest_ie (only available with libcurl 7.19.3 and newer), gssnegotiate, ntlm, anysafe. ## parameter syntax: # proxy-auth-method any ## configuration option: proxy-type ## description: Set proxy type. Allowed values: http, socks4, socks4a, socks5. ## parameter syntax: # proxy-type http ## configuration option: refresh-on-startup ## description: If yes, then all feeds will be reloaded when newsbeuter starts up. This is equivalent to the -r commandline option. ## parameter syntax: [yes/no] # refresh-on-startup no ## configuration option: reload-only-visible-feeds ## description: If yes, then manually reloading all feeds will only reload the currently visible feeds, e.g. if a filter or a tag is set. ## parameter syntax: [yes/no] # reload-only-visible-feeds no ## configuration option: reload-time ## description: The number of minutes between automatic reloads. ## parameter syntax: # reload-time 60 ## configuration option: reload-threads ## description: The number of parallel reload threads that shall be started when all feeds are reloaded. ## parameter syntax: # reload-threads 1 ## configuration option: save-path ## description: The default path where articles shall be saved to. If an invalid path is specified, the current directory is used. ## parameter syntax: # save-path ~/ ## configuration option: search-highlight-colors ## description: This configuration command specifies the highlighting colors when searching for text from the article view. ## parameter syntax: [ ...] # search-highlight-colors black yellow bold ## configuration option: show-keymap-hint ## description: If no, then the keymap hints on the bottom of screen will not be displayed. ## parameter syntax: [yes/no] # show-keymap-hint yes ## configuration option: show-read-feeds ## description: If yes, then all feeds, including those without unread articles, are listed. If no, then only feeds with one or more unread articles are list. ## parameter syntax: [yes/no] # show-read-feeds yes ## configuration option: show-read-articles ## description: If yes, then all articles of a feed are listed in the article list. If no, then only unread articles are listed. ## parameter syntax: [yes/no] # show-read-articles yes ## configuration option: suppress-first-reload ## description: If yes, then the first automatic reload will be suppressed if auto-reload is set to yes. ## parameter syntax: [yes/no] # suppress-first-reload no ## configuration option: swap-title-and-hints ## description: If yes, then the title at the top of screen and keymap hints at the bottom of screen will be swapped. ## parameter syntax: [yes/no] # swap-title-and-hints yes ## configuration option: text-width ## description: If set to a number greater than 0, then all HTML will be rendered to this maximum line length. If set to 0, the terminal width will be used. ## parameter syntax: # text-width 0 ## configuration option: urls-source ## description: This configuration command sets the source where URLs shall be retrieved from. By default, this is ~/.newsbeuter/urls. Alternatively, you can set it to "opml", which enables newsbeuter's OPML online subscription mode, or to "googlereader", which enables newsbeuter's Google Reader support. In order to make Google Reader support work correctly, you also need to set googlereader-login and googlereader-password. ## parameter syntax: # urls-source "local" ## configuration option: use-proxy ## description: If yes, then the configured proxy will be used for downloading the RSS feeds. ## parameter syntax: [yes/no] # use-proxy no ## configuration option: user-agent ## description: If set to a non-zero-length string, this value will be used as HTTP User-Agent header for all HTTP requests. ## parameter syntax: # user-agent "" # EOF newsbeuter-2.7/doc/gen-example-config.pl000077500000000000000000000012051220711462700203170ustar00rootroot00000000000000#!/usr/bin/perl -w use strict; print "####################################\n"; print "# newsbeuter example configuration #\n"; print "####################################\n\n"; while (my $line = ) { my ($option,$syntax,$defaultparam,$desc,$example) = split(/\|/, $line); if ($defaultparam ne "n/a") { print "## configuration option: " . $option . "\n"; if ($desc =~ /limitation in AsciiDoc/) { $desc =~ s/ \([^)]*\)\.$/./; $defaultparam =~ s/;/|/g; } print "## description: " . $desc . "\n"; print "## parameter syntax: " . $syntax . "\n"; print "# " . $option . " " . $defaultparam . "\n\n"; } } print "# EOF\n" newsbeuter-2.7/doc/generate.pl000077500000000000000000000006141220711462700164470ustar00rootroot00000000000000#!/usr/bin/perl -w use strict; if (scalar(@ARGV) < 1) { print STDERR "usage: $0 \n"; exit(1); } open(my $fh, '<', $ARGV[0]) or die "couldn't open $ARGV[0]: $!\n"; while (my $line = <$fh>) { chomp($line); my @fields = split(/\|/, $line); print "'$fields[0]' (parameters: $fields[1]; default value: '$fields[2]')::\n $fields[3] (example: $fields[4])\n\n"; } close($fh); newsbeuter-2.7/doc/generate2.pl000077500000000000000000000005361220711462700165340ustar00rootroot00000000000000#!/usr/bin/perl -w use strict; if (scalar(@ARGV) < 1) { print STDERR "usage: $0 \n"; exit(1); } open(my $fh, '<', $ARGV[0]) or die "couldn't open $ARGV[0]: $!\n"; while (my $line = <$fh>) { chomp($line); my @fields = split(/:/, $line, 3); print "'$fields[0]' (default key: '$fields[1]')::\n $fields[2]\n\n"; } close($fh); newsbeuter-2.7/doc/hackers-guide.txt000066400000000000000000000206631220711462700175770ustar00rootroot00000000000000The Newsbeuter Hacker's Guide ============================= Andreas Krennmair Introduction ------------ This is the "hacker's guide" to newsbeuter. It describes the overall architecture of newsbeuter, the most important design decisions and some other noteworthy things that don't belong anywhere else. This guide assumes that you know about Unix programming with C++, multithreading, and some more stuff. This is not for end users, so if you don't have C++ programming experience, then this is not for you. Architecture ------------ Classes ~~~~~~~ This section describes the different classes and their purpose. *class cache*: the persistence backend of newsbeuter. It takes rss_item and rss_feed objects and writes them to the cache.db using the SQLite library, respectively reads the content of cache.db and creates rss_item and rss_feed objects. *class colormanager*: manages the color configuration. It hooks into the configuration parser, stores the color configuration information and sets them in the view. This is currently a bit ugly, because colormanager knows about the internals of view resp. pb_view. This should be changed in a way that colormanager knows nothing about who gets the configuration, and that the views retrieve this configuration from colormanager. It is derived from config_action_handler, a helper class for the configuration parser. *class configcontainer*: manages the normal program configuration. It hooks into the configuration parser and the stores the configuration information. Other components can then query the configcontainer for configuration values. It is derived from config_action_handler. *class configparser*: parses the configuration file and hands over the results to all hooked config_action_handler objects. *class controller*: the controller does a lot of the work within newsbeuter. It is the connector between view and cache. It parses the command line option, controls the configuration parser and hands over data to the view. It also contains code to control the reloading of feeds. *class downloadthread*: a thread that does nothing but start a reload operation for all feeds. Derived from thread. *class htmlrenderer*: takes a string and renders the HTML it contains into a textual representation. It also extracts URLs from a and img tag for later use. *class keymap*: hooks into the configuration parser and manages all the keymapping. Additionally, it generates the keymapping information with hint texts for the view. *class logger*: helper class that manages the optional logging to a text file. Logging can be enabled by developers (see below). *class mutex*: a C++ wrapper around the pthread mutex. *class reloadthread*: similar to downloadthread, but starts a reload every n minutes (configurable). *class rss_feed*: represents an RSS feed, including RSS url, page link, title, author, description and RSS items (articles). Uses the cache to persist itself. Internally, all text data (especially the title and the author) are stored as UTF-8 strings, but the getters return data that matches the current locale charset setting. *class rss_item*: represents an RSS item (article), including link to the article, title, author, publication date and description. Internally, all text data (especially the title, the author and the description) are stored as UTF-8 strings, but the getters return data that matches the current locale charset setting. *class stflpp*: a C++ wrapper around STFL. STFL is the ncurses widget library that newsbeuter heavily relies upon. *class thread*: a wrapper around Unix pthreads. *class urlreader*: manages reading and writing the urls file, including handling of tags. *class utils*: contains several static utility functions, such as a tokenizer, the lock file code and a text converter that builds upon iconv. *class view*: the class that draws the user interface. It manages a stack of so-called "form actions", each of which represents one dialog. The view class delegates all received user input events to the correct form action. *class formaction*: the abstract base class for all form actions. Currently, the following formaction-derived classes exist: - feedlist_formaction - itemlist_formaction - itemview_formaction - urlview_formaction - filebrowser_formaction - help_formaction - selecttag_formaction *class tagsouppullparser*: Parses virtually everything that vaguely looks like XML/HTML tags, even when totally invalid, and provides the parsing result as a continuous stream of tokens (tags and text). It is solely used by the htmlrenderer class. Interaction ~~~~~~~~~~~ TODO: describe interaction between classes. Design Decisions ---------------- Use text file as configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The "classical" text tools, like vim, slrn and mutt, are all configurable solely via text files. Newsbeuter follows the same spirit, especially since the other prominent RSS feed readers for the text console primarily encourage configuration via an often crude user interface within the application itself. The consequence for newsbeuter is: no configuration via the user interface, but solely via configuration files. Text editors are easier to handle than some crude menus that are somehow hard to use. Keep a good balance of customizability ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The problem with user wishes is that too many people demand a possibility to customize this bell or that whistle within newsbeuter. Often, these possibilities only have a very limited purpose, and their value is in no relation to the added complexity of the code. Every customization needs to be tested, and means a lot more testing whenever some related code changes. The code shouldn't get too bloated, it should be kept straight-forward and easy to read. With too much customizability, this goal would be in danger. Why C++ and not C, [insert your favorite language], ...? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ has many advantages compared to other programming languages. - C++ is backwards-compatible to C. That means we can theoretically use all the C libraries. - C++ makes it easier to structure your program in an object-oriented way, and helps maintain inheritance hierarchies without a lot of fuzz. - C++ compiles to fast, native code. - C++ comes with an extensive standard library (see next section). - C++ is widespread. - C++ on Linux/Unix systems does not require any exotic compilers to be installed in order to compile newsbeuter. g++ (part of GCC) is enough. These were the reasons why C++ was initially chosen, and it proved to be a useable language during the development process. Use the full potential of modern C++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The C++ standard library comes with an extensive set of algorithms and data structures. Developers are encouraged to use especially the data structures, because the available container classes are standardized, their behaviour and usage is well-documented, and makes it possible to keep the overall logic at a pretty high level. More complex things that can only be done in C (like special system calls) /should/ be encapsulated by a wrapper class in order to avoid potential mis-use of low-level functions and data structures. Good examples for wrapping low-level stuff are *class rss_feed*, *class rss_item* and *class stflpp*. Tips and Tricks --------------- Getting a detailed debug log ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you want to get a detailed debug log from newsbeuter, you only need to run newsbeuter with special parameters: newsbeuter -d log.txt -l 6 Some of this output doesn't make sense very much unless you know the source code, so it's only helpful for developers. Use (and extend) the unit tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In the test subdirectory resides a simple unit test to check the most important functionality of the newsbeuter internals. These test build upon the lemon test framework which comes bundled as test/lemon.h with newsbeuter. Run "make test" to build the tests, the result is a binary called "test" within the test subdirectory. Run it and see whether everything still works as expected. Run "make clean-test" to clean up after the tests. Dump an STFL form ~~~~~~~~~~~~~~~~~ You can dump the currently shown STFL form with the "dumpform" command on the internal commandline. This can help debugging of rendering issues. Keys ---- Unused keys ~~~~~~~~~~~ _b_____hi_____________wxyz _B_____HI__LM_____STUVWXYZ Ctrl- A__D___HIJ____O_Q_S___W_Y_ Used special keys: ENTER ? / # + - : , $ | newsbeuter-2.7/doc/keycmds.dsv000066400000000000000000000062721220711462700165000ustar00rootroot00000000000000open:ENTER:Open the currently selected feed or article. quit:q:Quit the program or return to the previous dialog (depending on the context). reload:r:Reload the currently selected feed. reload-all:R:Reload all feeds. mark-feed-read:A:Mark all articles in the currently selected feed read. mark-all-feeds-read:C:Mark articles in all feeds read. save:s:Save the currently selected article to a file. next-unread:n:Jump to the next unread article. prev-unread:p:Jump to the previous unread article. next:J:Jump to next article. prev:K:Jump to previous article. random-unread:^K:Jump to a random unread article. open-in-browser:o:Opens the URL associated with the current article. open-in-browser-and-mark-read:O:Opens the URL associated with the current article and marks the article as read. help:?:Runs the help screen. toggle-source-view:^U:Toggles between the HTML view and the source view in the article view. toggle-article-read:N:Toggle the read flag for the currently selected article. toggle-show-read-feeds:l:Toggle whether read feeds should be shown in the feed list. show-urls:u:Show all URLs in the article in a list (similar to urlview). clear-tag:^T:Clear current tag. set-tag:t:Select tag. open-search:/:Opens the search dialog. When a search is done in the article list, then the search operation only applies to the articles of the current feed, otherwise to all articles. goto-url:#:Open the URL dialog and then opens specified URL. enqueue:e:Add the podcast download URL of the current article (if any is found) to the podcast download queue (see the respective section in the documentation for more information on podcast support). edit-urls:E:Edit the list of subscribed URLs. newsbeuter will start the editor configured through the $VISUAL environment variable (if unset, $EDITOR is used; fallback: "vi"). When editing is finished, newsbeuter will reload the URLs file. reload-urls:^R:Reload the URLs configuration file. redraw:^L:Redraw the screen. cmdline::Open the command line. set-filter:F:Set a filter. select-filter:f:Select a predefined filter. clear-filter:^F:Clear currently set filter. bookmark:^B:Bookmark currently selected article or URL. edit-flags:^E:Edit the flags of the currently selected article. next-unread-feed:^N:Go to the next feed with unread articles. This only works from the article list. prev-unread-feed:^P:Go to the previous feed with unread articles. This only works from the article list. next-feed:j:Go to the next feed. This only works from the article list. prev-feed:k:Go to the previous feed. This only works from the article list. delete-article:D:Delete the currently selected article. purge-deleted:$:Purge all article that are marked as deleted from the article list. view-dialogs:v:View list of open dialogs. close-dialog:^X:Close currently selected dialog. next-dialog:^V:Go to next dialog. prev-dialog:^G:Go to previous dialog. pipe-to:|:Pipe article to command. sort:g:Sort feeds/articles by interactively choosing the sort method. revsort:G:Sort feeds/articles by interactively choosing the sort method (reversed). up:UP:Goes up one item in the list. down:DOWN:Goes down one item in the list. pageup:PPAGE:Goes up one page in the list. pagedown:NPAGE:Goes down one page in the list. newsbeuter-2.7/doc/manpage-newsbeuter.txt000066400000000000000000000077641220711462700206640ustar00rootroot00000000000000NEWSBEUTER(1) =========== Andreas Krennmair NAME ---- newsbeuter - an RSS feed reader for text terminals SYNOPSIS -------- 'newsbeuter' [-r] [-e] [-i opmlfile] [-u urlfile] [-c cachefile] [-C configfile] [-X] [-o] [-x ...] [-h] DESCRIPTION ----------- 'newsbeuter' is an RSS feed reader for text terminals. RSS is a number of widely-used XML formats to transmit, publish and syndicate articles, for example news or blog articles. Newsbeuter is designed to be used on text terminals on Unix or Unix-like systems such as Linux, BSD or Mac OS X. OPTIONS ------- -h:: Display help -r:: Refresh feeds on start -e:: Export feeds as OPML to stdout -X:: Clean up cache thoroughly (i.e. reduce it in size if possible) -v, -V:: Get version information about newsbeuter and the libraries it uses -i opmlfile:: Import an OPML file -u urlfile:: Use an alternative URL file -c cachefile:: Use an alternative cache file -C configfile:: Use an alternative configuration file -x command ...:: Execute one or more commands to run newsbeuter unattended. Currently available commands are "reload" and "print-unread". -o:: Active offline reading mode. When Google Reader synchronization mode is configured, then the list of feeds will not be loaded from Google Reader, but instead from the local cache. This makes it possible to read locally cached articles even without internet connection to connect to Google Reader. -l loglevel:: Generate a loglevel with a certain loglevel. Valid loglevels are 1 to 6. An actual logfile will only be written when you provide a logfile name. -d logfile:: Use this logfile as output when logging debug messages. Please note that this only works when providing a loglevel. -E file:: Export a list of read articles (resp. their GUIDs). This can be used to transfer information about read articles between different computers. -I file:: Import a list of read articles and mark them as read if they are held in the cache. This is to be used in conjunction with the -E commandline parameter. FIRST STEPS ----------- include::chapter-firststeps.txt[] CONFIGURATION COMMANDS ---------------------- include::newsbeuter-cfgcmds.txt[] AVAILABLE OPERATIONS ---------------------- include::newsbeuter-keycmds.txt[] TAGGING ------- include::chapter-tagging.txt[] SCRIPTS AND FILTERS ------------------- include::chapter-snownews.txt[] COMMAND LINE ------------ include::chapter-cmdline.txt[] 'quit':: Quit newsbeuter 'save' :: Save current article to 'set' [=|&|!]:: Set (or get) configuration variable value. Specifying a '!' after the name of a boolean configuration variable toggles their values, a '&' directly after the name of a configuration variable of any type resets its value to the documented default value. 'tag' :: Select a certain tag 'goto' :: Go to the next feed whose name contains the case-insensitive substring. 'source' [...]:: Load the specified configuration files. This allows it to load alternative configuration files or reload already loaded configuration files on-the-fly from the filesystem. 'dumpconfig' :: Save current internal state of configuration to file, so that it can be instantly reused as configuration file. '':: Jump to the th entry in the current dialog FILES ----- '$HOME/.newsbeuter/config' '$HOME/.newsbeuter/urls' SEE ALSO -------- podbeuter(1). The documentation that comes with newsbeuter is a good source about the general use and configuration of newsbeuter. AUTHORS ------- Andreas Krennmair , for contributors see AUTHORS file. newsbeuter-2.7/doc/manpage-podbeuter.txt000066400000000000000000000022671220711462700204630ustar00rootroot00000000000000PODBEUTER(1) =========== Andreas Krennmair NAME ---- podbeuter - a podcast download manage for text terminals SYNOPSIS -------- 'podbeuter' [-C configfile] [-q queuefile] [-a] [-h] DESCRIPTION ----------- 'podbeuter' is a podcast manager for text terminals. It is a helper program to 'newsbeuter' which queues podcast downloads into a file. These queued downloads can then be download with 'newsbeuter'. OPTIONS ------- -h:: Display help -C configfile:: Use an alternative configuration file -q queuefile:: Use an alternative queue file -a:: Start automatic download of all queued files on startup PODCAST SUPPORT --------------- include::chapter-podcasts.txt[] CONFIGURATION COMMANDS ---------------------- include::podbeuter-cfgcmds.txt[] FILES ----- '$HOME/.newsbeuter/config' '$HOME/.newsbeuter/queue' SEE ALSO -------- newsbeuter(1). The documentation that comes with newsbeuter is a good source about the general use and configuration of newsbeuter's podcast support. AUTHORS ------- Andreas Krennmair , for contributors see AUTHORS file. newsbeuter-2.7/doc/newsbeuter.1000066400000000000000000001365741220711462700166010ustar00rootroot00000000000000'\" t .\" Title: newsbeuter .\" Author: Andreas Krennmair .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 08/27/2013 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" .TH "NEWSBEUTER" "1" "08/27/2013" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" newsbeuter \- an RSS feed reader for text terminals .SH "SYNOPSIS" .sp \fInewsbeuter\fR [\-r] [\-e] [\-i opmlfile] [\-u urlfile] [\-c cachefile] [\-C configfile] [\-X] [\-o] [\-x \&...] [\-h] .SH "DESCRIPTION" .sp \fInewsbeuter\fR is an RSS feed reader for text terminals\&. RSS is a number of widely\-used XML formats to transmit, publish and syndicate articles, for example news or blog articles\&. Newsbeuter is designed to be used on text terminals on Unix or Unix\-like systems such as Linux, BSD or Mac OS X\&. .SH "OPTIONS" .PP \-h .RS 4 Display help .RE .PP \-r .RS 4 Refresh feeds on start .RE .PP \-e .RS 4 Export feeds as OPML to stdout .RE .PP \-X .RS 4 Clean up cache thoroughly (i\&.e\&. reduce it in size if possible) .RE .PP \-v, \-V .RS 4 Get version information about newsbeuter and the libraries it uses .RE .PP \-i opmlfile .RS 4 Import an OPML file .RE .PP \-u urlfile .RS 4 Use an alternative URL file .RE .PP \-c cachefile .RS 4 Use an alternative cache file .RE .PP \-C configfile .RS 4 Use an alternative configuration file .RE .PP \-x command \&... .RS 4 Execute one or more commands to run newsbeuter unattended\&. Currently available commands are "reload" and "print\-unread"\&. .RE .PP \-o .RS 4 Active offline reading mode\&. When Google Reader synchronization mode is configured, then the list of feeds will not be loaded from Google Reader, but instead from the local cache\&. This makes it possible to read locally cached articles even without internet connection to connect to Google Reader\&. .RE .PP \-l loglevel .RS 4 Generate a loglevel with a certain loglevel\&. Valid loglevels are 1 to 6\&. An actual logfile will only be written when you provide a logfile name\&. .RE .PP \-d logfile .RS 4 Use this logfile as output when logging debug messages\&. Please note that this only works when providing a loglevel\&. .RE .PP \-E file .RS 4 Export a list of read articles (resp\&. their GUIDs)\&. This can be used to transfer information about read articles between different computers\&. .RE .PP \-I file .RS 4 Import a list of read articles and mark them as read if they are held in the cache\&. This is to be used in conjunction with the \-E commandline parameter\&. .RE .SH "FIRST STEPS" .sp After you\(cqve installed newsbeuter, you can run it for the first time by typing "newsbeuter" on your command prompt\&. This will bring you the following message: .sp .if n \{\ .RS 4 .\} .nf Error: no URLs configured\&. Please fill the file /home/ak/\&.newsbeuter/urls with RSS feed URLs or import an OPML file\&. .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf newsbeuter 2\&.4 usage: \&./newsbeuter [\-i |\-e] [\-u ] [\-c ] [\-x \&.\&.\&.] [\-h] \-e export OPML feed to stdout \-r refresh feeds on start \-i import OPML file \-u read RSS feed URLs from \-c use as cache file \-C read configuration from \-X clean up cache thoroughly \-x \&.\&.\&. execute list of commands \-o activate offline mode (only applies to Google Reader synchronization mode) \-q quiet startup \-v get version information \-l write a log with a certain loglevel (valid values: 1 to 6) \-d use as output log file \-E export list of read articles to \-I import list of read articles from \-h this help .fi .if n \{\ .RE .\} .sp This means that newsbeuter can\(cqt start without any configured feeds\&. To add feeds to newsbeuter, you can either add URLs to the configuration file $HOME/\&.newsbeuter/urls or you can import an OPML file by running "newsbeuter \-i blogroll\&.opml"\&. To manually add URLs, open the file with your favorite text editor and add the URLs, one per line: .sp .if n \{\ .RS 4 .\} .nf http://rss\&.cnn\&.com/rss/cnn_topstories\&.rss http://newsrss\&.bbc\&.co\&.uk/rss/newsonline_world_edition/front_page/rss\&.xml .fi .if n \{\ .RE .\} .sp If you need to add URLs that have restricted access via username/password, simply provide the username/password in the following way: .sp .if n \{\ .RS 4 .\} .nf http://username:password@hostname\&.domain\&.tld/feed\&.rss .fi .if n \{\ .RE .\} .sp In order to protect username and password, make sure that $HOME/\&.newsbeuter/urls has the appropriate permissions\&. Newsbeuter also makes sure that usernames and passwords within URLs aren\(cqt displayed in its user interface\&. In case there is a \fI@\fR in the username, you need to write it as \fI%40\fR instead so that it can be distinguished from the \fI@\fR that separates the username/password part from the hostname part\&. .sp You can also configure local files as feeds, by prefixing the local path with "file://" and adding it to the $HOME/\&.newsbeuter/urls file: .sp .if n \{\ .RS 4 .\} .nf file:///var/log/rss_eventlog\&.xml .fi .if n \{\ .RE .\} .sp Now you can run newsbeuter again, and it will present you with a controllable list of the URLs that you configured previously\&. You can now start downloading the feeds, either by pressing "R" to download all feeds, or by pressing "r" to download the currently selected feed\&. You can then select a feed you want to read, and by pressing "Enter", you can go to the article list for this feed\&. This works even while the downloading is still in progress\&. You can now see the list of available articles by their title\&. A "N" on the left indicates that an article wasn\(cqt read yet\&. Pressing Enter brings you to the content of the article\&. You can scroll through this text, and also run a browser (default: lynx) to view the complete article if the content is empty or just an abstract or a short description\&. Pressing "q" brings you back to the article list, and pressing "q" again brings you back to the feed list\&. Pressing "q" a third time then closes newsbeuter\&. .sp Newsbeuter caches the article that it downloads\&. This means that when you start newsbeuter again and reload a feed, the old articles can still be read even if they aren\(cqt in the current RSS feeds anymore\&. Optionally you can configure how many articles shall be preserved by feed so that the article backlog doesn\(cqt grow endlessly (see "max\-items" below)\&. .sp Newsbeuter also uses a number of measures to preserve the users\*(Aq and feed providers\*(Aq bandwidth, by trying to avoid unnecessary feed downloads through the use of conditional HTTP downloading\&. It saves every feed\(cqs "Last\-Modified" and "ETag" response header values (if present) and advises the feed\(cqs HTTP server to only send data if the feed has been updated by modification date/time or "ETag" header\&. This doesn\(cqt only make feed downloads for RSS feeds with no new updates faster, it also reduces the amount of transferred data per request\&. Conditional HTTP downloading can be optionally disabled per feed by using the "always\-download" configuration command\&. .sp Several aspects of newsbeuter\(cqs behaviour can be configured via a configuration file, by default $HOME/\&.newsbeuter/config\&. This configuration file contains lines in the form " \&..."\&. The configuration file can also contain comments, which start with the \fI#\fR character and go as far as the end of line\&. If you need to enter a configuration argument that contains spaces, use quotes (") around the whole argument\&. It\(cqs even possible to integrate the output of external commands into the configuration\&. The text between two backticks ("`") is evaluated as shell command, and its output is put on its place instead\&. This works like backtick evaluation in Bourne\-compatible shells and allows users to use external information from the system within the configuration\&. .sp Searching for articles is possible in newsbeuter, too\&. Just press the "/" key, enter your search phrase, and the title and content of all articles are searched for it\&. When you do a search from the list of feeds, all articles of all feeds will be searched\&. When you do a search from the article list of a feed, only the articles of the currently viewed feed are searched\&. When opening an article from a search result dialog, the search phrase is highlighted\&. .sp The history of all your searches is saved to the filesystem, to \e~/\&.newsbeuter/history\&.search\&. By default, the last 100 search phrases are stored, but this limited can be influenced through the "history\-limit" configuration variable\&. To disable search history saving, simply set the history\-limit to 0\&. .SH "CONFIGURATION COMMANDS" .PP \fIalways\-display\-description\fR (parameters: [true/false]; default value: \fIfalse\fR) .RS 4 If true, then the description will always displayed even if e\&.g\&. a content:encoded tag has been found\&. (example: always\-display\-description true) .RE .PP \fIalways\-download\fR (parameters: []; default value: \fIn/a\fR) .RS 4 The parameters of this configuration command are one or more RSS URLs\&. These URLs will always get downloaded, regardless of their Last\-Modified timestamp and ETag header\&. (example: always\-download "http://www\&.n\-tv\&.de/23\&.rss") .RE .PP \fIarticle\-sort\-order\fR (parameters: [\-]; default value: \fIdate\fR) .RS 4 The sortfield specifies which article property shall be used for sorting (currently available: date, title, flags, author, link, guid)\&. The optional direction specifies the sort direction ("asc" specifies ascending sorting, "desc" specifies descending sorting\&. for date, "desc" is default, for all others, "asc" is default)\&. (example: article\-sort\-order author\-desc) .RE .PP \fIarticlelist\-format\fR (parameters: ; default value: \fI"%4i %f %D %6L %?T?;%\-17T; ?%t"\fR) .RS 4 This variable defines the format of entries in the article list\&. See the respective section in the documentation for more information on format strings (note that the semicolon should actually be a vertical bar; this is a limitation in AsciiDoc)\&. (example: articlelist\-format "%4i %f %D %?T?;%\-17T; ?%t") .RE .PP \fIauto\-reload\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If enabled, all feeds will be automatically reloaded at start up and then continuously after a certain time has passed (see reload\-time)\&. (example: auto\-reload yes) .RE .PP \fIbind\-key\fR (parameters: []; default value: \fIn/a\fR) .RS 4 Bind key to \&. This means that whenever is pressed, then is executed (if applicable in the current dialog)\&. A list of available operations can be found below\&. Optionally, you can specify a dialog\&. If you specify one, the key binding will only be added to the specified dialog\&. Available dialogs are "all" (default if none is specified), "feedlist", "filebrowser", "help", "articlelist", "article", "tagselection", "filterselection", "urlview" and "podbeuter"\&. (example: bind\-key ^R reload\-all) .RE .PP \fIbookmark\-cmd\fR (parameters: ; default value: \fI""\fR) .RS 4 If set, then will be used as bookmarking plugin\&. See the documentation on bookmarking for further information\&. (example: bookmark\-cmd "~/bin/delicious\-bookmark\&.sh") .RE .PP \fIbookmark\-interactive\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If set to yes, then the configured bookmark command is an interactive program\&. (example: bookmark\-interactive yes) .RE .PP \fIbookmark\-autopilot\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If set to yes, the configured bookmark command is executed without any further input asked from user, uless the url or the title cannot be found/guessed\&. (example: bookmark\-autopilot yes) .RE .PP \fIbrowser\fR (parameters: ; default value: \fIlynx\fR) .RS 4 Set the browser command to use when opening an article in the browser\&. If contains %u, it will be used as complete commandline and %u will be replaced with the URL that shall be opened\&. (example: browser "w3m %u") .RE .PP \fIcache\-file\fR (parameters: ; default value: \fI"~/\&.newsbeuter/cache\&.db"\fR) .RS 4 This configuration option sets the cache file\&. This is especially useful if the filesystem of your home directory doesn\(cqt support proper locking (e\&.g\&. NFS)\&. (example: cache\-file "/tmp/testcache\&.db") .RE .PP \fIcleanup\-on\-quit\fR (parameters: [yes/no]; default value: \fIyes\fR) .RS 4 If yes, then the cache gets locked and superfluous feeds and items are removed, such as feeds that can\(cqt be found in the urls configuration file anymore\&. (example: cleanup\-on\-quit no) .RE .PP \fIcolor\fR (parameters: [ \&...]; default value: \fIn/a\fR) .RS 4 Set the foreground color, background color and optional attributes for a certain element (example: color background white black) .RE .PP \fIconfirm\-exit\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If set to yes, then newsbeuter will ask for confirmation whether the user really wants to quit newsbeuter\&. (example: confirm\-exit yes) .RE .PP \fIcookie\-cache\fR (parameters: ; default value: \fI""\fR) .RS 4 Set a cookie cache\&. If set, then cookies will be cached (i\&.e\&. read from and written to) in this file\&. (example: cookie\-cache "~/\&.newsbeuter/cookies\&.txt") .RE .PP \fIdatetime\-format\fR (parameters: ; default value: \fI%b %d\fR) .RS 4 This format specifies the date/time format in the article list\&. For a detailed documentation on the allowed formats, consult the manpage of strftime(3)\&. (example: datetime\-format "%D, %R") .RE .PP \fIdefine\-filter\fR (parameters: ; default value: \fIn/a\fR) .RS 4 With this command, you can predefine filters, which can you later select from a list, and which are then applied after selection\&. This is especially useful for filters that you need often and you don\(cqt want to enter them every time you need them\&. (example: define\-filter "all feeds with \fIfun\fR tag" "tags # \e\e"fun\e\e"") .RE .PP \fIdelete\-read\-articles\-on\-quit\fR (parameters: [yes/no]; default value: \fI"no"\fR) .RS 4 If set to "yes", then all read articles will be deleted when you quit newsbeuter\&. (example: delete\-read\-articles\-on\-quit yes) .RE .PP \fIdisplay\-article\-progress\fR (parameters: [yes/no]; default value: \fIyes\fR) .RS 4 If set to yes, then a read progress (in percent) is displayed in the article view\&. Otherwise, no read progress is displayed\&. (example: display\-article\-progress no) .RE .PP \fIdownload\-retries\fR (parameters: ; default value: \fI1\fR) .RS 4 How many times newsbeuter shall try to successfully download a feed before giving up\&. This is an option to improve the success of downloads on slow and shaky connections such as via a TOR proxy\&. (example: download\-retries 4) .RE .PP \fIdownload\-full\-page\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If set to yes, then for all feed items with no content but with a link, the link is downloaded and the result used as content instead\&. This may significantly increase the download times of "empty" feeds\&. (example: download\-full\-page yes) .RE .PP \fIdownload\-timeout\fR (parameters: ; default value: \fI30\fR) .RS 4 The number of seconds newsbeuter shall wait when downloading a feed before giving up\&. This is an option to improve the success of downloads on slow and shaky connections such as via a TOR proxy\&. (example: download\-timeout 60) .RE .PP \fIerror\-log\fR (parameters: ; default value: \fI""\fR) .RS 4 If set, then user errors (e\&.g\&. errors regarding defunct RSS feeds) will be logged to this file\&. (example: error\-log "~/\&.newsbeuter/error\&.log") .RE .PP \fIexternal\-url\-viewer\fR (parameters: ; default value: \fI""\fR) .RS 4 If set, then "show\-urls" will pipe the current article to a specific external tool instead of using the internal URL viewer\&. This can be used to integrate tools such as urlview\&. (example: external\-url\-viewer "urlview") .RE .PP \fIfeed\-sort\-order\fR (parameters: ; default value: \fInone\fR) .RS 4 If set to "firsttag", the feeds in the feed list will be sorted by their first tag in the urls file\&. (example: feed\-sort\-order firsttag) .RE .PP \fIfeedlist\-format\fR (parameters: ; default value: \fI"%4i %n %11u %t"\fR) .RS 4 This variable defines the format of entries in the feed list\&. See the respective section in the documentation for more information on format strings\&. (example: feedlist\-format " %n %4i \- %11u \-%> %t") .RE .PP \fIgooglereader\-flag\-share\fR (parameters: ; default value: \fI""\fR) .RS 4 If this is set and Google Reader support is used, then all articles that are flagged with the specified flag are being "shared" in Google Reader so that people that follow you can see it\&. (example: googlereader\-flag\-share "a") .RE .PP \fIgooglereader\-flag\-star\fR (parameters: ; default value: \fI""\fR) .RS 4 If this is set and Google Reader support is used, then all articles that are flagged with the specified flag are being "starred" in Google Reader and appear in the list of "Starred items"\&. (example: googlereader\-flag\-star "b") .RE .PP \fIgooglereader\-login\fR (parameters: ; default value: \fI""\fR) .RS 4 This variable sets your Google Reader login for the Google Reader support\&. (example: googlereader\-login "your\-login") .RE .PP \fIgooglereader\-min\-items\fR (parameters: ; default value: \fI20\fR) .RS 4 This variable sets the number of articles that are loaded from Google Reader per feed\&. (example: googlereader\-min\-items 100) .RE .PP \fIgooglereader\-password\fR (parameters: ; default value: \fI""\fR) .RS 4 This variable sets your Google Reader password for the Google Reader support\&. (example: googlereader\-password "your\-password") .RE .PP \fIgooglereader\-passwordfile\fR (parameters: [ [ \&...]]; default value: \fIn/a\fR) .RS 4 With this command, you can highlight text parts in the feed list, the article list and the article view\&. For a detailed documentation, see the chapter on highlighting\&. (example: highlight all "newsbeuter" red) .RE .PP \fIhighlight\-article\fR (parameters: [ \&...]; default value: \fIn/a\fR) .RS 4 With this command, you can highlight articles in the article list if they match a filter expression\&. For a detailed documentation, see the chapter on highlighting\&. (example: highlight\-article "author =~ \e\e"Andreas Krennmair\e\e"" white red bold) .RE .PP \fIhistory\-limit\fR (parameters: ; default value: \fI100\fR) .RS 4 Defines the maximum number of entries of commandline resp\&. search history to be saved\&. To disable history saving, set history\-limit to 0\&. (example: history\-limit 0) .RE .PP \fIhtml\-renderer\fR (parameters: ; default value: \fIinternal\fR) .RS 4 If set to "internal", then the internal HTML renderer will be used\&. Otherwise, the specified command will be executed, the HTML to be rendered will be written to the command\(cqs stdin, and the program\(cqs output will be displayed\&. This makes it possible to use other, external programs, such as w3m, links or lynx, to render HTML\&. (example: html\-renderer "w3m \-dump \-T text/html") .RE .PP \fIhttp\-auth\-method\fR (parameters: ; default value: \fIany\fR) .RS 4 Set HTTP authentication method\&. Allowed values: any, basic, digest, digest_ie (only available with libcurl 7\&.19\&.3 and newer), gssnegotiate, ntlm, anysafe\&. (example: http\-auth\-method digest) .RE .PP \fIignore\-article\fR (parameters: ; default value: \fIn/a\fR) .RS 4 If a downloaded article from matches , then it is ignored and not presented to the user\&. This command is further explained in the "kill file" section below\&. (example: ignore\-article "*" "title =~ \e\e"Windows\e\e"") .RE .PP \fIignore\-mode\fR (parameters: [download/display]; default value: \fIdownload\fR) .RS 4 This configuration option defines in what way an article is ignored (see ignore\-article)\&. If set to "download", then it is ignored in the download/parsing phase (which is the default) and thus never written to the cache, if it set to "display", it is ignored when displaying articles but is kept in the cache\&. (example: ignore\-mode "display") .RE .PP \fIinclude\fR (parameters: ; default value: \fIn/a\fR) .RS 4 With this command, you can include other files to be interpreted as configuration files\&. This is especially useful to separate your configuration into several files, e\&.g\&. key configuration, color configuration, \&... (example: include "~/\&.newsbeuter/colors") .RE .PP \fIkeep\-articles\-days\fR (parameters: ; default value: \fI0\fR) .RS 4 If set the a number greater than 0, only articles that are were published within the last days are kept, and older articles are deleted\&. If set to 0 (default value), this option is not active\&. (example: keep\-articles\-days 30) .RE .PP \fImacro\fR (parameters: ; default value: \fIn/a\fR) .RS 4 With this command, you can define a macro key and specify a list of commands that shall be executed when the macro prefix and the macro key are pressed\&. (example: macro k open ; reload ; quit) .RE .PP \fImark\-as\-read\-on\-hover\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If set to yes, then all articles that get selected in the article list are marked as read\&. (example: mark\-as\-read\-on\-hover yes) .RE .PP \fImax\-download\-speed\fR (parameters: ; default value: \fI0\fR) .RS 4 If set to a number great than 0, the download speed per download is set to that limit (in kB)\&. (example: max\-download\-speed 50) .RE .PP \fImax\-items\fR (parameters: ; default value: \fI0\fR) .RS 4 Set the number of articles to maximally keep per feed\&. If the number is set to 0, then all articles are kept\&. (example: max\-items 100) .RE .PP \fInotify\-format\fR (parameters: ; default value: \fI"newsbeuter: finished reload, %f unread feeds (%n unread articles total)"\fR) .RS 4 Format string that is used for formatting notifications\&. See the chapter on format strings for more information\&. (example: notify\-format "%d new articles (%n unread articles, %f unread feeds)") .RE .PP \fInotify\-program\fR (parameters: ; default value: \fI""\fR) .RS 4 If set, then the configured program will be executed if new articles arrived (through a reload) or if notify\-always is true\&. The first parameter of the called program contains the notification message\&. (example: notify\-program "~/bin/my\-notifier") .RE .PP \fInotify\-always\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If no, notifications will only be made when there are new feeds or articles\&. If yes, notifications will be made regardless\&. (example: notify\-always yes) .RE .PP \fInotify\-screen\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If yes, then a "privacy message" will be sent to the terminal, containing a notification message about new articles\&. This is especially useful if you use terminal emulations such as GNU screen which implement privacy messages\&. (example: notify\-screen yes) .RE .PP \fInotify\-xterm\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If yes, then the xterm window title will be set to a notification message about new articles\&. (example: notify\-xterm yes) .RE .PP \fInotify\-beep\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If yes, then the speaker beep on new articles\&. (example: notify\-beep yes) .RE .PP \fIopml\-url\fR (parameters: \&...; default value: \fI""\fR) .RS 4 If the OPML online subscription mode is enabled, then the list of feeds will be taken from the OPML file found on this location\&. Optionally, you can specify more than one URL\&. All the listed OPML URLs will then be taken into account when loading the feed list\&. (example: opml\-url "http://host\&.domain\&.tld/blogroll\&.opml" "http://example\&.com/anotheropmlfile\&.opml") .RE .PP \fIpager\fR (parameters: [/internal]; default value: \fIinternal\fR) .RS 4 If set to "internal", then the internal pager will be used\&. Otherwise, the article to be displayed will be rendered to be a temporary file and then displayed with the configured pager\&. If the pager path is set to an empty string, the content of the "PAGER" environment variable will be used\&. If the pager path contains a placeholder "%f", it will be replaced with the temporary filename\&. (example: less %f) .RE .PP \fIpodcast\-auto\-enqueue\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If yes, then all podcast URLs that are found in articles are added to the podcast download queue\&. See the respective section in the documentation for more information on podcast support in newsbeuter\&. (example: podcast\-auto\-enqueue yes) .RE .PP \fIprepopulate\-query\-feeds\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If yes, then all query feeds are prepopulated with articles on startup\&. (example: prepopulate\-query\-feeds yes) .RE .PP \fIproxy\fR (parameters: ; default value: \fIn/a\fR) .RS 4 Set the proxy to use for downloading RSS feeds\&. (example: proxy localhost:3128) .RE .PP \fIproxy\-auth\fR (parameters: ; default value: \fIn/a\fR) .RS 4 Set the proxy authentication string\&. (example: proxy\-auth user:password) .RE .PP \fIproxy\-auth\-method\fR (parameters: ; default value: \fIany\fR) .RS 4 Set proxy authentication method\&. Allowed values: any, basic, digest, digest_ie (only available with libcurl 7\&.19\&.3 and newer), gssnegotiate, ntlm, anysafe\&. (example: proxy\-auth\-method ntlm) .RE .PP \fIproxy\-type\fR (parameters: ; default value: \fIhttp\fR) .RS 4 Set proxy type\&. Allowed values: http, socks4, socks4a, socks5\&. (example: proxy\-type socks5) .RE .PP \fIrefresh\-on\-startup\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If yes, then all feeds will be reloaded when newsbeuter starts up\&. This is equivalent to the \-r commandline option\&. (example: refresh\-on\-startup yes) .RE .PP \fIreload\-only\-visible\-feeds\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If yes, then manually reloading all feeds will only reload the currently visible feeds, e\&.g\&. if a filter or a tag is set\&. (example: reload\-only\-visible\-feeds yes) .RE .PP \fIreload\-time\fR (parameters: ; default value: \fI60\fR) .RS 4 The number of minutes between automatic reloads\&. (example: reload\-time 120) .RE .PP \fIreload\-threads\fR (parameters: ; default value: \fI1\fR) .RS 4 The number of parallel reload threads that shall be started when all feeds are reloaded\&. (example: reload\-threads 3) .RE .PP \fIreset\-unread\-on\-update\fR (parameters: \&...; default value: \fIn/a\fR) .RS 4 With this configuration command, you can provide a list of RSS feed URLs for whose articles the unread flag will be reset if an article has been updated, i\&.e\&. its content has been changed\&. This is especially useful for RSS feeds where single articles are updated after publication, and you want to be notified of the updates\&. (example: reset\-unread\-on\-update "http://blog\&.fefe\&.de/rss\&.xml?html") .RE .PP \fIsave\-path\fR (parameters: ; default value: \fI~/\fR) .RS 4 The default path where articles shall be saved to\&. If an invalid path is specified, the current directory is used\&. (example: save\-path "~/Saved Articles") .RE .PP \fIsearch\-highlight\-colors\fR (parameters: [ \&...]; default value: \fIblack yellow bold\fR) .RS 4 This configuration command specifies the highlighting colors when searching for text from the article view\&. (example: search\-highlight\-colors white black bold) .RE .PP \fIshow\-keymap\-hint\fR (parameters: [yes/no]; default value: \fIyes\fR) .RS 4 If no, then the keymap hints on the bottom of screen will not be displayed\&. (example: show\-keymap\-hint no) .RE .PP \fIshow\-read\-feeds\fR (parameters: [yes/no]; default value: \fIyes\fR) .RS 4 If yes, then all feeds, including those without unread articles, are listed\&. If no, then only feeds with one or more unread articles are list\&. (example: show\-read\-feeds no) .RE .PP \fIshow\-read\-articles\fR (parameters: [yes/no]; default value: \fIyes\fR) .RS 4 If yes, then all articles of a feed are listed in the article list\&. If no, then only unread articles are listed\&. (example: show\-read\-articles no) .RE .PP \fIsuppress\-first\-reload\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If yes, then the first automatic reload will be suppressed if auto\-reload is set to yes\&. (example: suppress\-first\-reload yes) .RE .PP \fIswap\-title\-and\-hints\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If yes, then the title at the top of screen and keymap hints at the bottom of screen will be swapped\&. (example: swap\-title\-and\-hints yes) .RE .PP \fItext\-width\fR (parameters: ; default value: \fI0\fR) .RS 4 If set to a number greater than 0, then all HTML will be rendered to this maximum line length\&. If set to 0, the terminal width will be used\&. (example: text\-width 72) .RE .PP \fIttrss\-flag\-publish\fR (parameters: ; default value: \fI""\fR) .RS 4 If this is set and Tiny Tiny RSS support is used, then all articles that are flagged with the specified flag are being marked as "published" in Tiny Tiny RSS\&. (example: ttrss\-flag\-publish "b") .RE .PP \fIttrss\-flag\-star\fR (parameters: ; default value: \fI""\fR) .RS 4 If this is set and Tiny Tiny RSS support is used, then all articles that are flagged with the specified flag are being "starred" in Tiny Tiny RSS\&. (example: ttrss\-flag\-star "a") .RE .PP \fIttrss\-login\fR (parameters: ; default value: \fI""\fR) .RS 4 Sets the username for use with Tiny Tiny RSS\&. (example: ttrss\-login "admin") .RE .PP \fIttrss\-mode\fR (parameters: [multi/single]; default value: \fImulti\fR) .RS 4 Configures the mode in which Tiny Tiny RSS is used\&. In single\-user mode, login and password are used for HTTP authentication, while in multi\-user mode, they are used for authenticating with Tiny Tiny RSS\&. (example: ttrss\-mode "single") .RE .PP \fIttrss\-password\fR (parameters: ; default value: \fI""\fR) .RS 4 Configures the password for use with Tiny Tiny RSS\&. (example: ttrss\-password "mypassword") .RE .PP \fIttrss\-url\fR (parameters: ; default value: \fI""\fR) .RS 4 Configures the URL where the Tiny Tiny RSS installation you want to use resides\&. (example: ttrss\-url "http://example\&.com/ttrss/") .RE .PP \fIunbind\-key\fR (parameters: []; default value: \fIn/a\fR) .RS 4 Unbind key \&. This means that no operation is called when is pressed\&. Optionally, you can specify a dialog (for a list of available dialogs, see "bind\-key" above)\&. If you specify one, the key binding will only be unbound for the specified dialog\&. (example: unbind\-key R) .RE .PP \fIurls\-source\fR (parameters: ; default value: \fI"local"\fR) .RS 4 This configuration command sets the source where URLs shall be retrieved from\&. By default, this is ~/\&.newsbeuter/urls\&. Alternatively, you can set it to "opml", which enables newsbeuter\(cqs OPML online subscription mode, to "ttrss" which enables newsbeuter\(cqs Tiny Tiny RSS support, or to "googlereader", which enables newsbeuter\(cqs Google Reader support\&. In order to make Google Reader support work correctly, you also need to set googlereader\-login and googlereader\-password, while the Tiny Tiny RSS support requires login, password and URL of the Tiny Tiny RSS installation to use (see above)\&. (example: urls\-source "googlereader") .RE .PP \fIuse\-proxy\fR (parameters: [yes/no]; default value: \fIno\fR) .RS 4 If yes, then the configured proxy will be used for downloading the RSS feeds\&. (example: use\-proxy yes) .RE .PP \fIuser\-agent\fR (parameters: ; default value: \fI""\fR) .RS 4 If set to a non\-zero\-length string, this value will be used as HTTP User\-Agent header for all HTTP requests\&. (example: user\-agent "Lynx/2\&.8\&.5rel\&.1 libwww\-FM/2\&.14") .RE .SH "AVAILABLE OPERATIONS" .PP \fIopen\fR (default key: \fIENTER\fR) .RS 4 Open the currently selected feed or article\&. .RE .PP \fIquit\fR (default key: \fIq\fR) .RS 4 Quit the program or return to the previous dialog (depending on the context)\&. .RE .PP \fIreload\fR (default key: \fIr\fR) .RS 4 Reload the currently selected feed\&. .RE .PP \fIreload\-all\fR (default key: \fIR\fR) .RS 4 Reload all feeds\&. .RE .PP \fImark\-feed\-read\fR (default key: \fIA\fR) .RS 4 Mark all articles in the currently selected feed read\&. .RE .PP \fImark\-all\-feeds\-read\fR (default key: \fIC\fR) .RS 4 Mark articles in all feeds read\&. .RE .PP \fIsave\fR (default key: \fIs\fR) .RS 4 Save the currently selected article to a file\&. .RE .PP \fInext\-unread\fR (default key: \fIn\fR) .RS 4 Jump to the next unread article\&. .RE .PP \fIprev\-unread\fR (default key: \fIp\fR) .RS 4 Jump to the previous unread article\&. .RE .PP \fInext\fR (default key: \fIJ\fR) .RS 4 Jump to next article\&. .RE .PP \fIprev\fR (default key: \fIK\fR) .RS 4 Jump to previous article\&. .RE .PP \fIrandom\-unread\fR (default key: \fI^K\fR) .RS 4 Jump to a random unread article\&. .RE .PP \fIopen\-in\-browser\fR (default key: \fIo\fR) .RS 4 Opens the URL associated with the current article\&. .RE .PP \fIopen\-in\-browser\-and\-mark\-read\fR (default key: \fIO\fR) .RS 4 Opens the URL associated with the current article and marks the article as read\&. .RE .PP \fIhelp\fR (default key: \fI?\fR) .RS 4 Runs the help screen\&. .RE .PP \fItoggle\-source\-view\fR (default key: \fI^U\fR) .RS 4 Toggles between the HTML view and the source view in the article view\&. .RE .PP \fItoggle\-article\-read\fR (default key: \fIN\fR) .RS 4 Toggle the read flag for the currently selected article\&. .RE .PP \fItoggle\-show\-read\-feeds\fR (default key: \fIl\fR) .RS 4 Toggle whether read feeds should be shown in the feed list\&. .RE .PP \fIshow\-urls\fR (default key: \fIu\fR) .RS 4 Show all URLs in the article in a list (similar to urlview)\&. .RE .PP \fIclear\-tag\fR (default key: \fI^T\fR) .RS 4 Clear current tag\&. .RE .PP \fIset\-tag\fR (default key: \fIt\fR) .RS 4 Select tag\&. .RE .PP \fIopen\-search\fR (default key: \fI/\fR) .RS 4 Opens the search dialog\&. When a search is done in the article list, then the search operation only applies to the articles of the current feed, otherwise to all articles\&. .RE .PP \fIgoto\-url\fR (default key: \fI#\fR) .RS 4 Open the URL dialog and then opens specified URL\&. .RE .PP \fIenqueue\fR (default key: \fIe\fR) .RS 4 Add the podcast download URL of the current article (if any is found) to the podcast download queue (see the respective section in the documentation for more information on podcast support)\&. .RE .PP \fIedit\-urls\fR (default key: \fIE\fR) .RS 4 Edit the list of subscribed URLs\&. newsbeuter will start the editor configured through the $VISUAL environment variable (if unset, $EDITOR is used; fallback: "vi")\&. When editing is finished, newsbeuter will reload the URLs file\&. .RE .PP \fIreload\-urls\fR (default key: \fI^R\fR) .RS 4 Reload the URLs configuration file\&. .RE .PP \fIredraw\fR (default key: \fI^L\fR) .RS 4 Redraw the screen\&. .RE .PP \fIcmdline\fR (default key: \fI\fR) .RS 4 Open the command line\&. .RE .PP \fIset\-filter\fR (default key: \fIF\fR) .RS 4 Set a filter\&. .RE .PP \fIselect\-filter\fR (default key: \fIf\fR) .RS 4 Select a predefined filter\&. .RE .PP \fIclear\-filter\fR (default key: \fI^F\fR) .RS 4 Clear currently set filter\&. .RE .PP \fIbookmark\fR (default key: \fI^B\fR) .RS 4 Bookmark currently selected article or URL\&. .RE .PP \fIedit\-flags\fR (default key: \fI^E\fR) .RS 4 Edit the flags of the currently selected article\&. .RE .PP \fInext\-unread\-feed\fR (default key: \fI^N\fR) .RS 4 Go to the next feed with unread articles\&. This only works from the article list\&. .RE .PP \fIprev\-unread\-feed\fR (default key: \fI^P\fR) .RS 4 Go to the previous feed with unread articles\&. This only works from the article list\&. .RE .PP \fInext\-feed\fR (default key: \fIj\fR) .RS 4 Go to the next feed\&. This only works from the article list\&. .RE .PP \fIprev\-feed\fR (default key: \fIk\fR) .RS 4 Go to the previous feed\&. This only works from the article list\&. .RE .PP \fIdelete\-article\fR (default key: \fID\fR) .RS 4 Delete the currently selected article\&. .RE .PP \fIpurge\-deleted\fR (default key: \fI$\fR) .RS 4 Purge all article that are marked as deleted from the article list\&. .RE .PP \fIview\-dialogs\fR (default key: \fIv\fR) .RS 4 View list of open dialogs\&. .RE .PP \fIclose\-dialog\fR (default key: \fI^X\fR) .RS 4 Close currently selected dialog\&. .RE .PP \fInext\-dialog\fR (default key: \fI^V\fR) .RS 4 Go to next dialog\&. .RE .PP \fIprev\-dialog\fR (default key: \fI^G\fR) .RS 4 Go to previous dialog\&. .RE .PP \fIpipe\-to\fR (default key: \fI|\fR) .RS 4 Pipe article to command\&. .RE .PP \fIsort\fR (default key: \fIg\fR) .RS 4 Sort feeds/articles by interactively choosing the sort method\&. .RE .PP \fIrevsort\fR (default key: \fIG\fR) .RS 4 Sort feeds/articles by interactively choosing the sort method (reversed)\&. .RE .PP \fIup\fR (default key: \fIUP\fR) .RS 4 Goes up one item in the list\&. .RE .PP \fIdown\fR (default key: \fIDOWN\fR) .RS 4 Goes down one item in the list\&. .RE .PP \fIpageup\fR (default key: \fIPPAGE\fR) .RS 4 Goes up one page in the list\&. .RE .PP \fIpagedown\fR (default key: \fINPAGE\fR) .RS 4 Goes down one page in the list\&. .RE .SH "TAGGING" .sp Newsbeuter comes with the possibility to categorize or "tag", as we call it, RSS feeds\&. Every RSS feed can be assigned 0 or more tags\&. Within newsbeuter, you can then select to only show RSS feeds that match a certain tag\&. That makes it easy to categorize your feeds in a flexible and powerful way\&. .sp Usually, the ~/\&.newsbeuter/urls file contains one RSS feed URL per line\&. To assign a tag to an RSS feed, simply attach it as a single word, separated by blanks such as space or tab\&. If the tag needs to contain spaces, you must use quotes (") around the tag (see example below)\&. An example \e~/\&.newsbeuter/urls file may look like this: .sp .if n \{\ .RS 4 .\} .nf http://blog\&.fefe\&.de/rss\&.xml?html interesting conspiracy news "cool stuff" http://rss\&.orf\&.at/news\&.xml news orf http://www\&.heise\&.de/newsticker/heise\&.rdf news interesting .fi .if n \{\ .RE .\} .sp When you now start newsbeuter with this configuration, you can press "t" to select a tag\&. When you select the tag "news", you will see all three RSS feeds\&. Pressing "t" again and e\&.g\&. selecting the "conspiracy" tag, you will only see the http://blog\&.fefe\&.de/rss\&.xml?html RSS feed\&. Pressing "^T" clears the current tag, and again shows all RSS feeds, regardless of their assigned tags\&. .sp A special type of tag are tags that start with the tilde character ("~")\&. When such a tag is found, the feed title is set to the tag name (excluding the \e~ character)\&. With this feature, you can give feeds any title you want in your feed list: .sp .if n \{\ .RS 4 .\} .nf http://rss\&.orf\&.at/news\&.xml "~ORF News" .fi .if n \{\ .RE .\} .sp Another special type of tag are tags that start with the exclamation mark\&. When such a tag is found, the feed is hidden from the regular list of feeds and its content can only be found through a query feed\&. .sp .if n \{\ .RS 4 .\} .nf http://rss\&.orf\&.at/news\&.xml "!ORF News (hidden)" .fi .if n \{\ .RE .\} .SH "SCRIPTS AND FILTERS" .sp From version 0\&.4 on, newsbeuter contains support for Snownews extensions\&. The RSS feed readers Snownews and Liferea share a common way of extending the readers with custom scripts\&. Two mechanisms, namely "execurl" and "filter" type scripts, are available and supported by newsbeuter\&. .sp An "execurl" script can be any program that gets executed and whose output is interpreted as RSS feed, while "filter" scripts are fed with the content of a configured URL and whose output is interpreted as RSS feed\&. .sp The configuration is simple and straight\-forward\&. Just add to your ~/\&.newsbeuter/urls file configuration lines like the following ones: .sp .if n \{\ .RS 4 .\} .nf exec:~/bin/execurl\-script filter:~/bin/filter\-script:http://some\&.test/url .fi .if n \{\ .RE .\} .sp The first line shows how to add an execurl script to your configuration: start the line with "exec:" and then immediately append the path of the script that shall be executed\&. If this script requires additional parameters, simply use quotes: .sp .if n \{\ .RS 4 .\} .nf "exec:~/bin/execurl\-script param1 param2" .fi .if n \{\ .RE .\} .sp The second line shows how to add a filter script to your configuration: start the line with "filter:", then immediately append the path of the script, then append a colon (":"), and then append the URL of the file that shall be fed to the script\&. Again, if the script requires any parameters, simply quote: .sp .if n \{\ .RS 4 .\} .nf "filter:~/bin/filter\-script param1 param2:http://url/foobar" .fi .if n \{\ .RE .\} .sp In both cases, the tagging feature as described above is still available: .sp .if n \{\ .RS 4 .\} .nf exec:~/bin/execurl\-script tag1 tag2 "quoted tag" filter:~/bin/filter\-script:http://some\&.test/url tag3 tag4 tag5 .fi .if n \{\ .RE .\} .sp A collection of such extension scripts can be found on this website: http://kiza\&.kcore\&.de/software/snownews/snowscripts/extensions .sp If you want to write your own extensions, refer to this website for further instructions: http://kiza\&.kcore\&.de/software/snownews/snowscripts/writing .SH "COMMAND LINE" .sp Like other text\-oriented software, newsbeuter contains an internal commandline to modify configuration variables ad hoc and to run own commands\&. It provides a flexible access to the functionality of newsbeuter which is especially useful for advanced users\&. .sp To start the commandline, type ":"\&. You will see a ":" prompt at the bottom of the screen, similar to tools like vi(m) or mutt\&. You can now enter commands\&. Pressing the return key executes the command (possibly giving feedback to the user) and closes the commandline\&. You can cancel entering commands by pressing the ESC key\&. The history of all the commands that you enter will be saved to \e~/\&.newsbeuter/history\&.cmdline\&. The backlog is limited to 100 entries by default, but can be influenced by setting the "history\-limit" configuration variable\&. To disable history saving, set the history\-limit to 0\&. .sp Starting with newsbeuter 2\&.0, the commandline provides you with some help if you can\(cqt remember the full names of commandline commands\&. By pressing the TAB key, newsbeuter will try to automatically complete your command\&. If there is more than one possible completion, you can subsequently press the TAB key to cycle through all results\&. If no match is found, no suggestion will be inserted into the commandline\&. For the "set" command, the completion also works for configuration variable names\&. .sp In addition, some common key combination such as Ctrl\-G (to cancel input), Ctrl\-K (to delete text from the cursor position to the end of line), Ctrl\-U (to clear the whole line) and Ctrl\-W (to delete the word before the current cursor position) were added\&. .sp Please be aware that the input history of both the command line and the search functions are saved to the filesystems, to the files ~/\&.newsbeuter/history\&.cmdline resp\&. \e~/\&.newsbeuter/history\&.search\&. By default, the last 100 entries are saved, but this can be configured (configuration variable history\-limit) and also totally disabled (by setting said variable to 0)\&. .sp Currently, the following command line commands are available: .PP \fIquit\fR .RS 4 Quit newsbeuter .RE .PP \fIsave\fR .RS 4 Save current article to .RE .PP \fIset\fR [=|&|!] .RS 4 Set (or get) configuration variable value\&. Specifying a \fI!\fR after the name of a boolean configuration variable toggles their values, a \fI&\fR directly after the name of a configuration variable of any type resets its value to the documented default value\&. .RE .PP \fItag\fR .RS 4 Select a certain tag .RE .PP \fIgoto\fR .RS 4 Go to the next feed whose name contains the case\-insensitive substring\&. .RE .PP \fIsource\fR [\&...] .RS 4 Load the specified configuration files\&. This allows it to load alternative configuration files or reload already loaded configuration files on\-the\-fly from the filesystem\&. .RE .PP \fIdumpconfig\fR .RS 4 Save current internal state of configuration to file, so that it can be instantly reused as configuration file\&. .RE .PP \fI\fR .RS 4 Jump to the th entry in the current dialog .RE .SH "FILES" .sp \fI$HOME/\&.newsbeuter/config\fR .sp \fI$HOME/\&.newsbeuter/urls\fR .SH "SEE ALSO" .sp podbeuter(1)\&. The documentation that comes with newsbeuter is a good source about the general use and configuration of newsbeuter\&. .SH "AUTHORS" .sp Andreas Krennmair , for contributors see AUTHORS file\&. .SH "AUTHOR" .PP \fBAndreas Krennmair\fR <\&ak@newsbeuter\&.org\&> .RS 4 Author. .RE newsbeuter-2.7/doc/newsbeuter.txt000066400000000000000000001250561220711462700172510ustar00rootroot00000000000000The Newsbeuter RSS Feedreader ============================= Andreas Krennmair Introduction ------------ Newsbeuter is an RSS feedreader. RSS is a number of widely-used XML formats to transmit, publish and syndicate articles, for example news or blog articles. Newsbeuter is designed to be used on text terminals on Unix or Unix-like systems such as Linux, FreeBSD or Mac OS X. Platforms ~~~~~~~~~ Newsbeuter has been tested on Linux, FreeBSD and Mac OS X, and is available in the form of pre-built packages for many popular Linux distributions. For a current list of distributions with newsbeuter packages, consult http://www.newsbeuter.org/download.html[this list on the newsbeuter website]. OpenBSD is currently unsupported, as it lacks even the most basic support for internationalization and localization. NetBSD is currently not supported, due to technical limitations in the iconv() implementation. Why "Newsbeuter"? ~~~~~~~~~~~~~~~~ "Newsbeuter" is a pun on the German word "Wildbeuter", which means "hunter-gatherer". During the stone age, people hunted and gathered their food, and these days, they hunt and gather news and information. Credits for this idea goes to Clifford Wolf, who submitted it to a little competition that was started when I got aware that the original name would violate French and European registered trademarks. Installation ------------ This chapter describes how to compile and install newsbeuter from source. Downloading Newsbeuter ~~~~~~~~~~~~~~~~~~~~~~ Newsbeuter is available as source package. Simply go to http://www.newsbeuter.org/[] and download the latest source package, which is usually in the .tar.gz file format. Alternatively, you can check out the latest development source tree from the newsbeuter Git repository (hosted on GitHub) by running the following command on the commandline: git clone git://github.com/akrennmair/newsbeuter.git Dependencies ~~~~~~~~~~~~ Newsbeuter depends on a number of libraries to function correctly. This table lists these dependencies. Please be aware that the list libraries may themselves depend on other libraries. These dependencies are not listed here. Please also be aware that you need a recent C++ compiler. Currently, newsbeuter has only been tested with GCC. - STFL (version 0.21 or newer): http://www.clifford.at/stfl/[] - SQLite 3 (version 3.5 or newer): http://www.sqlite.org/[] - libcurl: http://curl.haxx.se/download.html[] - GNU gettext (on systems that don't provide gettext in the libc): ftp://ftp.gnu.org/gnu/gettext/[] - pkg-config: http://pkg-config.freedesktop.org/wiki/[] - libxml2: http://xmlsoft.org/[] If you intend to modify and regenerate the filter language parser, you will also need Coco/R for C++, which you can download from http://www.ssw.uni-linz.ac.at/coco/[]. The Coco/R binary must be installed as "cococpp" in your PATH. Debian users only need to install the package "coco-cpp". Use the "regenerate-parser" make target to regenerate the necessary files. Compiling and Installing ~~~~~~~~~~~~~~~~~~~~~~~~ After you've downloaded and installed the dependencies mentioned above, you can start compiling and installing newsbeuter. To compile newsbeuter, simply run "make" in the source tree. After a short time, this should complete successfully, and you can go on with installation by running "make install". By default, this will install the "newsbeuter" binary to the /usr/local/bin directory. You can provide an alternative installation path using the prefix parameter, e.g. running "make install prefix=/opt/newsbeuter" will install the binary to the directory /opt/newsbeuter/bin. First Steps ----------- include::chapter-firststeps.txt[] .Configuration Commands [frame="all", grid="all",format="dsv",separator="|"] `10`15`15`40`20~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Configuration Command|Argument(s)|Default|Description|Example ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include::configcommands.dsv[] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .Available Operations [frame="all", grid="all", format="dsv",separator=":"] `20`20`60~~~~~~~~~~~~~~~~~~~~~~~~ Operation:Default key:Description ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include::keycmds.dsv[] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Keys, as used in the bind-key configuration command, use a special syntax. Lowercase keys, uppercase keys and special characters are written literally. The Enter key is written as "ENTER", while the Esc key is written as "ESC". The function keys F1 to F12 are written as "F1" to "F12". The Space key is written as "SPACE". Key combinations with the Ctrl key, such as Ctrl-R, are written as ^R. Please be aware that all Ctrl-related key combinations need to be written in uppercase. The following identifiers for keys are supported: - ENTER (Enter key) - BACKSPACE (backspace key) - LEFT (left cursor) - RIGHT (right cursor) - UP (up cursor) - PPAGE (page up cursor) - NPAGE (page down cursor) - DOWN (down cursor) - ESC (Esc key) The "Tab" key can't be bound due to technical limitations of STFL. Example Configuration ~~~~~~~~~~~~~~~~~~~~~ # a comment max-items 100 # such comments are possible, too browser links show-read-feeds no unbind-key R bind-key ^R reload-all Configuring Colors ~~~~~~~~~~~~~~~~~~ It is possible to configure custom color settings in newsbeuter. The basic configuration syntax is: color [ ...] This means that if you configure colors for a certain element, you need to provide a foreground color and a background color as a minimum. The following colors are supported: - black - red - green - yellow - blue - magenta - cyan - white - default - color, e.g. color123 The "default" color means that the terminal's default color will be used. The "color" color name can be used if your terminal support 256 colors (e.g. gnome-terminal, xterm with $TERM set to xterm-256color). Newsbeuter contains support for 256 color terminals since version 2.1. For a complete chart of colors and their corresponding numbers, please see http://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html[]. Optionally, you can also add one or more attributes. The following attributes are supported: - standout - underline - reverse - blink - dim - bold - protect - invis Currently, the following elements are supported: - *listnormal*: a normal list item - *listfocus*: the currently selected list item - *listnormal_unread*: an unread list item - *listfocus_unread*: the currently selected and unread list item - *info*: the info bars on top and bottom - *background*: the application background - *article*: the article text The default color configuration of newsbeuter looks like this: background white black listnormal white black listfocus yellow blue bold listnormal_unread magenta black listfocus_unread magenta blue bold info yellow blue bold article white black Migrating from other RSS Feed Readers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It is very likely that you have used other RSS feed readers before. In this case, it is practical to migrate the previous configuration to newsbeuter. The vast amount of RSS feed readers allows the export of subscriptions via OPML files. OPML is an XML file format that was designed to save outlines, and has found its primary use in the import and export of feed subscriptions between different RSS feed readers. The best thing to start with is to export your subscriptions from the old reader. Usually, RSS feed readers have appropriate menu items available to do so. Snownews provides a script to convert your current subscription file into an OPML file: snow2opml > ~/blogroll.opml This command creates from your Snownews configuration a file blogroll.opml in your home directory. To export the subscription list from raggle, the following command is necessary: raggle --export-opml ~/blogroll.opml When you have exported the subscriptions from your old RSS feed reader, you can import them into newsbeuter: newsbeuter -i ~/blogroll.opml Don't worry, newsbeuter won't destroy your existing configuration, or add subscriptions more than once: every URL that is added to the subscription list is checked before whether it is already in the list, and is only added if not. This makes it possible to merge several OPML files into your subscription list. If your old RSS feed reader was able to structure your subscriptions in hierarchies, and reflected this structure in the exported OPML file, newsbeuter doesn't throw away this information (although it doesn't support hierarchies), but generates tags from it. Tags are newsbeuter's way of organizing subscriptions in a non-hierarchical way. More information on the use of tags can be found below. Imagine the following folder hierarchy: |- News | |- Europe | `- International |- IT | |- Linux | |- Windows | `- Programming | |- C++ | |- Ruby | `- Erlang `- Private Subscriptions found in the folder "Private" will be tagged with "Private", subscriptions in the folder "International" will be tagged with "News" and "News/International", subscriptions in the folder "Erlang" will be tagged ith "IT", "IT/Programming" and "IT/Programming/Erlang", and so on. This means that when you select the tag "Programming" in newsbeuter, you will see all subscriptions that were in the "Programming" folder or one of its subfolders before. This means that you will lose virtually nothing of your previously configured structure. Advanced Features ----------------- Tagging ~~~~~~~ include::chapter-tagging.txt[] Scripts and Filters (Snownews Extensions) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include::chapter-snownews.txt[] Bookmarking ~~~~~~~~~~~ Since version 0.7, newsbeuter contains a plugin-based bookmarking system. When a user bookmarks a link (possible in the article list, in the article view, and in the URL view), he is asked for the URL to bookmark (already preset with the URL of the current selection), the bookmark title (in most cases preset with the title of the current selection) and the bookmark description. After the question for the description, an external program, configured via the configuration command "bookmark-cmd", is executed with 3 commandline parameters. The plugin itself implements the actual bookmark saving (e.g. writing the bookmark to an external file, or storing it to a del.icio.us account). When everything went OK, the plugin simply exits. In case something goes wrong while saving the bookmark, it writes out an error message as a single line. This error message is then presented to the user from within newsbeuter. Newsbeuter comes with an example plugin, which implements a simple tab-separated bookmark file. This example can be found in the "doc" subdirectory. Command Line ~~~~~~~~~~~~ include::chapter-cmdline.txt[] .Available Commandline Commands [frame="all", grid="all", format="dsv"] `20`20`40`20~~~~~~~~~~~~~~~~~~~ Command:Syntax:Description:Example ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ quit:quit:Quit newsbeuter.:quit save:save :Save the currently select article to disk. This works in the article list and in the article view.:save ~/important.txt set:set [=|&|!]:Set configuration variable to . If no value is specified, the current value is printed out. Specifying a '!' after the name of boolean configuration variables toggles their values, a '&' directly after the name of a configuration variable of any type resets its value to the documented default value.:set reload-time=15 tag:tag :Only display feeds with the tag .:tag news goto:goto :Go to the next feed whose name contains the case-insensitive substring.:goto foo source:source [...]:Load the specified configuration files. This allows it to load alternative configuration files or reload already loaded configuration files on-the-fly from the filesystem.:source ~/.newsbeuter/colors dumpconfig:dumpconfig :Save current internal state of configuration to file, so that it can be instantly reused as configuration file.:dumpconfig ~/.newsbeuter/config.saved dumpform:dumpform:Dump current dialog to text file. This is meant for debugging purposes only.:dumpform n/a::Jump to the entry with the index (usually seen at the left side of the list). This currently works for the feed list and the article list.:30 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Filter Language ~~~~~~~~~~~~~~~ Newsbeuter provides a powerful filter language that enables the user to filter the content of many dialogs, such as the feed list or the article list. The basic concept is that every feed and every article has a number of attributes which can then be compared with user-supplied values, and these comparisons and be logically AND'ed, OR'ed and grouped. Examples for simple filter expressions are: unread_count > 0 rssurl =~ "^https:" age between 0:10 Logically connecting and grouping such expressions looks like in the following examples: ( unread_count > 0 and unread_count < 10 ) or total_count > 100 ( author =~ "Frank" or author =~ "John" ) and ( title =~ "Linux" or title =~ "FreeBSD" ) The possibilities for combining such queries is endless, sky (actually: the available memory) is the limit. To filter your feeds, press "F" in the feed list, enter your filter expression, and press enter. To clear the filter, press Ctrl-F. To filter the articles in the article list, press "F", enter your expression, and press enter. Clearing the filter works the same as before. Be aware that only certain attributes work in both dialogs. The table below lists all available attributes and their context, i.e. an attribute that belongs to a feed can only be matched in the feed list, while an attribute that belongs to an article can only be matched in the article list. .Available Comparison Operators [frame="all", grid="all", format="dsv"] `30`70~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Operator:Meaning ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ =:test for equality ("==" works, too) !=:test for inequality; logical negation of = operator =~:test whether regular expression matches !~:logical negation of the =~ operator <:less than >:greater than <=:less than or equal >=:greater than or equal between:within a range of integer values, where the two integer values are separated by a colon (see above for an example) #:contains; this operator matches if a word is contained in a list of space-separated words (useful for matching tags, see below) !#:contains not; the negation of the # operator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .Available Attributes [frame="all", grid="all", format="dsv"] `30`30`40~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Attribute:Context:Meaning ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ title:article:article title link:article:article link author:article:article author content:article:article body date:article:publication date of the article guid:article:a unique identifier of the article unread:article:indicates whether the article has been read enclosure_url:article:the URL of a possible enclosure (e.g. podcast file) enclosure_type:article:the MIME type of the enclosure URL flags:article:The set of flags of the article age:article:Age of an article (in days) articleindex:article:Index of an article in an article list feedtitle:feed, article:title of the feed description:feed, article:feed description feedlink:feed, article:link to the feed feeddate:feed, article:publication date of the feed rssurl:feed, article:RSS URL of the feed unread_count:feed, article:number of unread articles in the feed total_count:feed, article:total number of articles in the feed tags:feed, article:all tags that are associated with the feed feedindex:feed, article:Index of a feed in the feed list ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Note that it's also possible to filter for feed attributes when you query for article attributes. This is because every article is internally linked to the feed from which it was downloaded. Killfiles ~~~~~~~~~ Sometimes, a user is confronted with certain content he doesn't want to read, e.g. on topics the user is not interested in or articles from certain people he doesn't want to read. In Usenet, such functionality within software is traditionally called a "killfile", i.e. based on the content of this "killfile", articles that match certain conditions do not get displayed and are not presented to the user at all. In newsbeuter, such a "killfile" can be implemented on a per-article basis via the configuration file. The most important configuration command for this is "ignore-article": ignore-article "*" "title =~ \"Gentoo\"" ignore-article "http://synflood.at/blog/index.php?/feeds/index.rss2" "title =~ \"newsbeuter\"" The basic format is that the user specifies an RSS feed for which the ignore shall be applied ("*" matches all RSS feeds), and then a filter expression (see previous section). If newsbeuter hits an article in the specified RSS feed that matches the specified filter expression, then this article is ignored and never presented to the user. The configuration itself can contain as many ignore-article commands as desired. Since newsbeuter 2.2, you can specify the way an article is ignored. There are two ways available: - During download: articles are ignored when a feed is downloaded and parsed, and thus won't be written to the local cache. - During display: articles are downloaded and written to the local cache, but are ignored when a feed is displayed. Both modes have their advantages and disadvantages: while the download ignore mode saves some storage, you cannot simply "undo" the ignore by removing it from the configuration file: if an ignored article has already vanished from a feed, it won't reappear. On the other hand, the display ignore mode requires some more space, but has the advantage that an ignore can be "undone" by removing the ignore-article configuration command from the configuration. The default ignore mode is "download". You can set the ignore mode in the configuration file: ignore-mode "display" Query Feeds ~~~~~~~~~~~ Query feeds are a mechanism of newsbeuter to define custom "meta feeds" by using newsbeuter's built-in filter language. A query feed is a feed that is aggregated from all currently downloaded articles of all feeds. To narrow down the set of articles, the user has to specify a filter. Only articles that match this filter are added to the query feed. A query feed is updated whenever it is entered in the feed list. When you change the unread flag of an article, this is reflected in the feed where the article was originally fetched. To define a query feed, the user has to add a line to the file ~/.newsbeuter/urls in the following format: query:: [ ...] The "query:" in the beginning tells newsbeuter that it's a query feed, "" specifies the name under which the query feed shall be displayed in the feed list, and "" is the filter expression that shall be used. Like every other feed, a query feed can be tagged to organize it like a regular feed. A good example for the user of this feature is a query feed that contains all unread articles: "query:Unread Articles:unread = \"yes\"" Note the quotes that are necessary around the complete query "URL" and the backslashes that are necessary the escape the quotes in the filter expression. If you want to combine several feeds to one single feed, a good solution is to tag the feeds that you want to combine with one certain tag, and then create a query feed that only displays articles from feeds with that certain tag: http://domain1.tld/feed.xml fun news tag1 http://domain2.tld/?feed.rss private jokes tag1 http://domain3.tld/feeds.rss news "query:tag1 Articles:tags # \"tag1\"" In this example, the feeds http://domain1.tld/feed.xml and http://domain2.tld/?feed.rss are aggregated into the query feed named "tag1 Articles", but the feed http://domain3.tld/feeds.rss is not. Basically, the possibility of what can be realized with query feeds is only limited by what can be queried from articles and feeds with the filter language and by your creativity. Google Reader Support ~~~~~~~~~~~~~~~~~~~~~ http://www.google.com/reader/[Google Reader] is Google's web-based feed aggregator. Newsbeuter provides functionality to use Google Reader as its backend: people can use Google Reader to manage their subscriptions, and in addition, use newsbeuter to download and read articles. Newsbeuter will keep the information which articles have already been read synchronized with Google Reader, so that users usually won't see articles more than once. In addition, it will only ever download unread articles from Google Reader. In order to use Google Reader support, you first need to configure the proper URL source: urls-source "googlereader" In addition, newsbeuter needs to know your Google Reader username and password so that it can authenticate with Google Reader: googlereader-login "your-googlereader-account" googlereader-password "your-password" After setting these configuration values, you can start newsbeuter, it will authenticate with Google Reader and download your subscription list. If you use "folders" in Google Reader to organize your feeds, newsbeuter will regard them and make them available via its "tags" capability: each feed is tagged with the name of the folder in which it resides. When you mark single items or complete feeds as read, newsbeuter will synchronize this information directly to Google Reader. This, of course, includes opening articles. Toggling read articles back to "unread" is also communicated to Google Reader. In addition, Google Reader provides the ability to "star" and to "share" articles. Starred articles are basically bookmarks, while shared articles are shown to people that follow your Google Reader account. Newsbeuter allows the use of this feature by mapping its powerful "flags" to the "star"/"unstar" resp. "share"/"unshare" operations. In order to use this mapping, all you need to do is to configure the flags that shall be used: googlereader-flag-share "a" googlereader-flag-star "b" After that, use these flags when you edit flags for an article, and these articles will be starred resp. shared. By default, newsbeuter also shows Google Reader "special feeds": - People you follow: articles shared by people that you follow. - Starred items: articles that you starred. - Shared items: articles that you shared. - Popular items: articles that are considered to be popular by Google's algorithms. You can disable these feeds by setting the following configuration variable: googlereader-show-special-feeds no Bloglines Synchronization ~~~~~~~~~~~~~~~~~~~~~~~~~ Up to and including version 2.3, newsbeuter contained support for synchronization with Bloglines. On October 1, 2010, Bloglines was discontinued, and newsbeuter's support for Bloglines was subsequently removed. Tiny Tiny RSS Synchronization ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Since version 2.5, newsbeuter can be used to synchronize with Tiny Tiny RSS installations. Tiny Tiny RSS is a web-based and (optionally) multi-user feed reader. By providing the ability to use Tiny Tiny RSS as its backend, it's possible for users to manage their subscriptions centrally within Tiny Tiny RSS while reading them wherever they are using newsbeuter. If you want to use Tiny Tiny RSS support, don't forget to activate the external API support in your preferences. To use Tiny Tiny RSS support, you need to configure a few things. First of all, newsbeuter needs to know that you want to use Tiny Tiny RSS and which installation exactly: urls-source "ttrss" ttrss-url "http://example.com/ttrss/" In addition, it requires username and password for authentication: ttrss-login "myusername" ttrss-password "mypassword" Tiny Tiny RSS provides two modes of usage, single-user mode and multi-user mode. newsbeuter needs to know about this, too: In single-user mode, authentication is done via Basic HTTP authentication, while in multi-user mode, authentication is done against Tiny Tiny RSS itself. ttrss-mode "single" # "multi" is default With these settings, newsbeuter should be able to connect to Tiny Tiny RSS and download your subscribed feeds. Articles or even complete feeds that you marked as read are synchronized directly to Tiny Tiny RSS. Tiny Tiny RSS provides the ability to "star" and to "publish" articles. Starred articles are basically bookmarks, while published articles can be retrieved via a pubic RSS feed. Newsbeuter allows the use of these features by mapping its flags to the "star" and "publish" operations. In order to use this mapping, you need to configure the flags that shall be used: ttrss-flag-star "s" ttrss-flag-publish "p" After that, use these flags when you edit flags for an article, and these articles will be starred resp. published. OPML Online Subscription Mode ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The OPML online subscription mode works similar to the Google Reader synchronization mode, except that no information about read articles is synchronized back. When enabled, all feeds that are listed in the feed list will be taken from one or more OPML files that are downloaded from a freely configurable URL. To enable this mode, the following configuration needs to be done: urls-source "opml" opml-url "" ["" ...] "opml" must be specified as source for the feed URLs, and the URLs of the OPML file needs to be specified, too. As with Google Reader synchronization mode, the offline mode via "newsbeuter -o" also works with OPML online subscription mode. Flagging Articles ~~~~~~~~~~~~~~~~~ To support custom categorization of articles by the user, it is possible to flag an article. A valid flag is any character from 'A' to 'Z' and from 'a' to 'z'. Every article can be flagged with up to 52 different flags, i.e. every letter from the Roman alphabet in upper and lower case. Flagging is easy: just select an article in the article list, or enter the article view, and press ^E. This will start the flag editor. By pressing enter, the new flags are saved. You can cancel by pressing the ESC key. The flags of an article can be used in every filter expression. The flags of an article are always ordered, and when new flags are added, ordering is immediately restored. This behaviour can also be relied upon when querying articles via the filter language. If an article contains one or more flags, it is marked with an "!" in the article list. In the article view, all flags (if available) are listed. Macro Support ~~~~~~~~~~~~~ In newsbeuter, it's possible to define macros to execute more than one command at once. A macro is configured using the "macro" configuration command. The first parameter to "macro" is the key, all parameters afterwards are operations (as listed in the "Available Operations" table above), optionally with parameters on their own, separated by the ";" character. Here's a simple example: macro k open ; reload ; quit macro o open-in-browser ; toggle-article-read "read" When the user presses the macro prefix ("," by default) and then the "k" key, the three operations "open", "reload" and "quit" will be executed subsequently. It is also possible to modify configuration variables within macros, which can e.g. be used to temporarily modify the browser configuration variable to do something else, such as running an image viewer from the URLs view: macro i set browser "feh %u"; open ; set browser "elinks %u" You can even use this feature to enqueue any of the URLs from the URLs view to podbeuter's download queue: macro E set browser "echo %u >> ~/.newsbeuter/queue" ; open ; set browser "elinks %u" Commandline Commands ~~~~~~~~~~~~~~~~~~~~ Newsbeuter comes with a -x option that indicates that commands added as arguments to the command line shall be executed. Currently, the following commands are available: - reload: this option reloads all feeds, and quits newsbeuter without printing any output. This is useful if a user wants to periodically reload all feeds without always having a running newsbeuter instance, e.g. from cron. - print-unread: this option prints the number of unread articles and quits newsbeuter. This is useful for users who want to integrate this number into some kind of monitoring system. Format Strings ~~~~~~~~~~~~~~ Newsbeuter contains a powerful format string system to make it possible for the user to configure the format of various aspects of the application, such as the format of entries in the feed list or in the article list. Format strings are similar to those that are found in the "printf" function in the C programming language. A format sequence begins with the '%' character, followed by optional alignment indication: positive numbers indicate that the text that is inserted for the sequence shall be padded right to a total width that is specified by the number, while negative number specify left padding. Followed by the padding indication comes the actual sequence identifier, which is usually a single letter. In addition, newsbeuter provides other, more powerful sequences, such as "%>[char]", which indicates that the text right to the sequence will be aligned right on the screen, and characters between the text on the left and the text on the right will be filled by "[char]". Another powerful format is the conditional sequence, "%?[char]?[format 1]&[format 2]?": if the text of the sequence identifier "[char]" is non-empty, then "[format 1]" will be evaluated and inserted, otherwise "[format 2]" will be evaluated and inserted. The "&" and "[format 2]" are optional, i.e. if the identifier's text is empty, then an empty string will be inserted. The following tables show what sequence identifiers are available for which format: .Available Identifiers for feedlist-format [frame="all", grid="all", format="dsv"] `30`60~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Identifier:Meaning ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ d:Feed description i:Feed index l:Feed link L:Feed RSS URL n:"unread" flag field S:download status t:Feed title T:First tag of a feed in the URLs file u:"unread/total" field U:"unread" field c:"total" field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ While a reload-all operation is running, the download status indicates the download status of a feed, which can be "to be downloaded" (indicated by "_"), "currently downloading" (indicated by "."), successfully downloaded (indicated by " ") and "download error" (indicated by "x"). .Available Identifiers for articlelist-format [frame="all", grid="all", format="dsv"] `30`60~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Identifier:Meaning ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ a:Article author D:Publication date f:Article flags i:Article index t:Article title T:If the article list displays articles from different feeds, then this identifier contains the title of the feed to which the article belongs. L:Article length ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .Available Identifiers for notify-format [frame="all", grid="all", format="dsv"] `30`60~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Identifier:Meaning ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ n:Number of unread articles f:Number of unread feeds d:Number of new unread articles (i.e. that were added through the last reload) D:Number of new unread feeds (i.e. that were added through the last reload) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Examples: feedlist-format "%4i %n %11u %t" articlelist-format "%4i %f %D %?T?|%-17T| ?%t" notify-format "%d new articles (%n unread articles, %f unread feeds)" Dialog Titles ^^^^^^^^^^^^^ Starting with newsbeuter 2.0, it is now officially supported to customize the title format of all available dialogs. Here is a list of dialogs with their respective title format configuration variables, and a list of available formats and their meaning. Please note taht the title formats are localized, so if you work on a different locale that is supported by newsbeuter, the actually displayed title text may vary unless you customize it. .Dialog Title Formats [frame="all", grid="all", format="dsv"] `20`30`50~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Dialog:Configuration Variable:Default Value ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Feed List:feedlist-title-format:%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&? Article List:articlelist-title-format:%N %V - Articles in feed '%T' (%u unread, %t total) - %U Search Result:searchresult-title-format:%N %V - Search result (%u unread, %t total) File Browser:filebrowser-title-format:%N %V - %?O?Open File&Save File? - %f Help:help-title-format:%N %V - Help Select Tag Dialog:selecttag-title-format:%N %V - Select Tag Select Filter Dialog:selectfilter-title-format:%N %V - Select Filter Article View:itemview-title-format:%N %V - Article '%T' (%u unread, %t total) URL View:urlview-title-format:%N %V - URLs Dialog List:dialogs-title-format:%N %V - Dialogs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .Common Title Format Identifiers [frame="all", grid="all", format="dsv"] `30`60~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Identifier:Meaning ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ N:Name of the program, i.e. "newsbeuter" V:Program version u:Number of unread articles (if applicable) t:Number of total articles (if applicable) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .Feed List Title Format Identifiers [frame="all", grid="all", format="dsv"] `30`60~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Identifier:Meaning ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ T:Currently selected tag (empty if none selected) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .Article List Title Format Identifiers [frame="all", grid="all", format="dsv"] `30`60~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Identifier:Meaning ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ T:Feed title U:Feed URL ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .File Browser Title Format Identifiers [frame="all", grid="all", format="dsv"] `30`60~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Identifier:Meaning ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ f:Filename O:Non-empty if file browser is in open mode, empty if in save mode ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .Article View Title Format Identifiers [frame="all", grid="all", format="dsv"] `30`60~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Identifier:Meaning ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ T:Article title ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Highlighting Text ~~~~~~~~~~~~~~~~~ Since version 1.0, newsbeuter supports the highlighting of text in the feed list, the article list and the article view, using regular expressions to describe patterns to be highlighted. The command syntax goes like this: highlight [ [ ...]] Valid values for are "feedlist", "articlelist", "article" and "all". When specifying "all", the matching will be done in all three views. The must be regular expression, which will be matched case-insensitive against the text. and specify the foreground color resp. the background color of the matches. You can also specify 0 or more attributes. You can find a list of valid colors and attributes in the "Configuring Colors" section. Examples for possible highlighting configurations are: highlight all "newsbeuter" red highlight article "^(Feed|Title|Author|Link|Date):" default default underline highlight feedlist "https?://[^ ]+" yellow red bold Highlighting Articles in the Article List ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In addition to generally highlighting text, there is also a specific way to highlight articles in the article list based on whether they match a certain filter expression. This means that you can highlight items in the article list based on their content. This is done using the "highlight-article" configuration command. The syntax is similar to the "highlight" configuration command, with the difference that there's no need to specify a target (since it only applies in the article list), and instead of a regular expression, a filter expression is used. After the filter expression, the colors and attributes are specified in the same way. Example: highlight-article "author =~ \"Andreas Krennmair\"" white red bold Advanced Dialog Management ~~~~~~~~~~~~~~~~~~~~~~~~~~ Since version 2.0, newsbeuter supports an advanced concept of dialogs. Previously, all dialogs (feed list, article list, article view) were internally laid out as a pure stack. In 2.0, this changed: all dialogs are managed in a list, and the user can jump to another, previously opened dialog from everywhere. This allows a user to open more than one article list, more than one article view, etc., and switch between them without closing them. The main dialog for this feature can be reached by pressing the "v" key. This opens the list of open dialogs. From there, the user can switch to another dialog by selecting the appropriate entry and pressing "ENTER", or can close open dialogs by selecting them and pressing Ctrl-X. XDG Base Directory Support ~~~~~~~~~~~~~~~~~~~~~~~~~~ Newsbeuter implements limited support for the http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html[XDG Base Directory Specification]. It needs to be set up manually by creating the following directories: ~/.local/share/newsbeuter/ ~/.config/newsbeuter/ If these directories exist or the environment variables $XDG_CONFIG_HOME and $XDG_DATA_HOME are set, newsbeuter will use these directories, otherwise it will default to ~/.newsbeuter as its configuration directory. Podcast Support ~~~~~~~~~~~~~~~ include::chapter-podcasts.txt[] .Podbeuter Configuration Commands [frame="all", grid="all",format="dsv",separator="|"] `10`15`15`40`20~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Configuration Command|Argument(s)|Default|Description|Example ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include::podbeuter-cmds.dsv[] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .Available Operations in Podbeuter [frame="all", grid="all", format="dsv"] `20`20`60~~~~~~~~~~~~~~~~~~~~~~~~ Operation:Default key:Description ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ quit:q:Quit the program. pb-download:d:Download the currently selected URL. pb-cancel:c:Cancel the currently selected download. pb-play:p:Start player with currently selected download. pb-delete:D:Delete the currently selected URL from the queue. pb-purge:P:Remove all finished and deleted downloads from the queue and load URLs that were newly added to the queue. pb-toggle-download-all:a:Toggle the "automatic download" feature where all queued URLs are downloaded one after the other. The "max-downloads" configuration option controls how many downloads are done in parallel. pb-increase-max-dls:+:Increase the "max-downloads" option by 1. pb-decrease-max-dls:-:Decrease the "max-downloads" option by 1. If the option is already 1, no further decrease is possible. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A usual "use case" is to configure newsbeuter to automatically enqueue newly found podcast download URLs. Then, the user reloads the podcast RSS feeds in newsbeuter, and after that, he/she uses podbeuter to view the current queue, and either selectively download certain files or automatically download them all together by pressing "a" within podbeuter. Using SQLite Triggers with newsbeuter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This section was kindly provided by mailto:elrond+newsbeuter(at)samba-tng.org[Elrond]. SQLite, the db used by newsbeuter, supports triggers. These are small snippets of SQL that get executed inside the database by the database engine. They're stored inside the db and the normal user (including newsbeuter itself) doesn't see them. Just the db seems to do some magic: Like changing some values when you change another value. So what is this good for when looking at newsbeuter? Well first of it's a hack. The real answer should be to use application logic (do it inside newsbeuter, not in the db). So: Don't use this, unless you know, what you're doing, and unless you have some sort of backup. Example ^^^^^^^ So after the "don't use it" you still want to know, what one can do? So here's an example. Suppose you have a strange feed where the articles become "new" by just changing their subject, and nothing else changes. The body is just empty, and the URL keeps the same. This feed really exists. It's the "updated software rss feed" of some major company and the title just contains the name of the driver and version number. And the URL points to the download page. newsbeuter considers articles only as new, when they have a new UniqueID (this is good). So those articles are never marked as new (unread) ever again. So what can we do? We do some magic: We let the db test if newsbeuter changes the subject and then let itself mark the article again as unread. 1. You need the sqlite3 command line tool (available via apt-get install sqlite3 on Debian) or some other tool to do direct sql on the sqlite database. 2. Start sqlite3 with the newsbeuter db: Rivendell:~/.newsbeuter% sqlite3 cache.db SQLite version 3.4.2 Enter ".help" for instructions sqlite> 3. Create the trigger: sqlite> create trigger update_item_title update of title on rss_item > for each row when old.title != new.title > begin > update rss_item set unread = 1 where rowid == new.rowid; > end; 4. Leave sqlite3 with or .quit. That's it. newsbeuter (well, its db) now marks articles as unread when their title changes. And nicely enough this works all inside newsbeuter, no need to restart it so that it rereads the cache, that magically modifies itself. It just works. Feedback -------- If you want to tell us something related to newsbeuter, don't hesitate to send an email: ak@newsbeuter.org Alternatively, you can reach the newsbeuter developers on IRC: channel #newsbeuter on irc.freenode.net. If you want to report newsbeuter bugs, please use this issue tracker: http://code.google.com/p/newsbeuter/issues/list[] License ------- MIT/X Consortium License (C)opyright 2006-2011 Andreas Krennmair Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. newsbeuter-2.7/doc/podbeuter-cmds.dsv000066400000000000000000000010341220711462700177450ustar00rootroot00000000000000download-path||~/|Specifies the directory where podbeuter shall download the files to. Optionally, the placeholders "%n" (for the podcast feed's name) and "%h" (for the podcast feed's hostname) can be used to place downloads in a directory structure.|download-path "~/Downloads/%h/%n" max-downloads||1|Specifies the maximum number of parallel downloads when automatic download is enabled.|max-downloads 3 player||""|Specifies the player that shall be used for playback of downloaded files.|player "mp3blaster" newsbeuter-2.7/doc/podbeuter.1000066400000000000000000000106531220711462700163740ustar00rootroot00000000000000'\" t .\" Title: podbeuter .\" Author: Andreas Krennmair .\" Generator: DocBook XSL Stylesheets v1.75.2 .\" Date: 08/27/2013 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" .TH "PODBEUTER" "1" "08/27/2013" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" podbeuter \- a podcast download manage for text terminals .SH "SYNOPSIS" .sp \fIpodbeuter\fR [\-C configfile] [\-q queuefile] [\-a] [\-h] .SH "DESCRIPTION" .sp \fIpodbeuter\fR is a podcast manager for text terminals\&. It is a helper program to \fInewsbeuter\fR which queues podcast downloads into a file\&. These queued downloads can then be download with \fInewsbeuter\fR\&. .SH "OPTIONS" .PP \-h .RS 4 Display help .RE .PP \-C configfile .RS 4 Use an alternative configuration file .RE .PP \-q queuefile .RS 4 Use an alternative queue file .RE .PP \-a .RS 4 Start automatic download of all queued files on startup .RE .SH "PODCAST SUPPORT" .sp A podcast is a media file distributed over the internet using syndication feeds such as RSS, for later playback on portable players or computers\&. Newsbeuter contains support for downloading and saving podcasts\&. This support differs a bit from other podcast aggregators or "podcatchers" in how it is done\&. .sp Podcast content is transported in RSS feeds via special tags called "enclosures"\&. Newsbeuter recognizes these enclosures and stores the relevant information for every podcast item it finds in an RSS feed\&. Since version 2\&.0, it also recognizes and handles the Yahoo Media RSS extensions\&. What the user then can do is to add the podcast download URL to a download queue\&. Alternatively, newsbeuter can be configured to automatically do that\&. This queue is stored in the file $HOME/\&.newsbeuter/queue\&. .sp The user can then use the download manager "podbeuter" to download these files to a directory on the local filesystem\&. Podbeuter comes with the newsbeuter package, and features a look and feel very close to the one of newsbeuter\&. It also shares the same configuration file\&. .sp Podcasts that have been downloaded but haven\(cqt been played yet remain in the queue but are marked as downloaded\&. You can remove them by purging them from the queue with the \fIP\fR key\&. After you\(cqve played a file and close podbeuter, it will be removed from the queue\&. The downloaded file remains on the filesystem\&. .SH "CONFIGURATION COMMANDS" .PP \fIdownload\-path\fR (parameters: ; default value: \fI~/\fR) .RS 4 Specifies the directory where podbeuter shall download the files to\&. Optionally, the placeholders "%n" (for the podcast feed\(cqs name) and "%h" (for the podcast feed\(cqs hostname) can be used to place downloads in a directory structure\&. (example: download\-path "~/Downloads/%h/%n") .RE .PP \fImax\-downloads\fR (parameters: ; default value: \fI1\fR) .RS 4 Specifies the maximum number of parallel downloads when automatic download is enabled\&. (example: max\-downloads 3) .RE .PP \fIplayer\fR (parameters: ; default value: \fI""\fR) .RS 4 Specifies the player that shall be used for playback of downloaded files\&. (example: player "mp3blaster") .RE .SH "FILES" .sp \fI$HOME/\&.newsbeuter/config\fR .sp \fI$HOME/\&.newsbeuter/queue\fR .SH "SEE ALSO" .sp newsbeuter(1)\&. The documentation that comes with newsbeuter is a good source about the general use and configuration of newsbeuter\(cqs podcast support\&. .SH "AUTHORS" .sp Andreas Krennmair , for contributors see AUTHORS file\&. .SH "AUTHOR" .PP \fBAndreas Krennmair\fR <\&ak@newsbeuter\&.org\&> .RS 4 Author. .RE newsbeuter-2.7/doc/xhtml/000077500000000000000000000000001220711462700154505ustar00rootroot00000000000000newsbeuter-2.7/doc/xhtml/docbook-xsl.css000066400000000000000000000131521220711462700204100ustar00rootroot00000000000000/* CSS stylesheet for XHTML produced by DocBook XSL stylesheets. */ body { font-family: Georgia,serif; } code, pre { font-family: "Courier New", Courier, monospace; } span.strong { font-weight: bold; } body blockquote { margin-top: .75em; line-height: 1.5; margin-bottom: .75em; } html body { margin: 1em 5% 1em 5%; line-height: 1.2; } body div { margin: 0; } h1, h2, h3, h4, h5, h6 { color: #527bbd; font-family: Arial,Helvetica,sans-serif; } div.toc p:first-child, div.list-of-figures p:first-child, div.list-of-tables p:first-child, div.list-of-examples p:first-child, div.example p.title, div.sidebar p.title { font-weight: bold; color: #527bbd; font-family: Arial,Helvetica,sans-serif; margin-bottom: 0.2em; } body h1 { margin: .0em 0 0 -4%; line-height: 1.3; border-bottom: 2px solid silver; } body h2 { margin: 0.5em 0 0 -4%; line-height: 1.3; border-bottom: 2px solid silver; } body h3 { margin: .8em 0 0 -3%; line-height: 1.3; } body h4 { margin: .8em 0 0 -3%; line-height: 1.3; } body h5 { margin: .8em 0 0 -2%; line-height: 1.3; } body h6 { margin: .8em 0 0 -1%; line-height: 1.3; } body hr { border: none; /* Broken on IE6 */ } div.footnotes hr { border: 1px solid silver; } div.navheader th, div.navheader td, div.navfooter td { font-family: Arial,Helvetica,sans-serif; font-size: 0.9em; font-weight: bold; color: #527bbd; } div.navheader img, div.navfooter img { border-style: none; } div.navheader a, div.navfooter a { font-weight: normal; } div.navfooter hr { border: 1px solid silver; } body td { line-height: 1.2 } body th { line-height: 1.2; } ol { line-height: 1.2; } ul, body dir, body menu { line-height: 1.2; } html { margin: 0; padding: 0; } body h1, body h2, body h3, body h4, body h5, body h6 { margin-left: 0 } body pre { margin: 0.5em 10% 0.5em 1em; line-height: 1.0; color: navy; } tt.literal, code.literal { color: navy; } .programlisting, .screen { border: 1px solid silver; background: #f4f4f4; margin: 0.5em 10% 0.5em 0; padding: 0.5em 1em; } div.sidebar { background: #ffffee; margin: 1.0em 10% 0.5em 0; padding: 0.5em 1em; border: 1px solid silver; } div.sidebar * { padding: 0; } div.sidebar div { margin: 0; } div.sidebar p.title { margin-top: 0.5em; margin-bottom: 0.2em; } div.bibliomixed { margin: 0.5em 5% 0.5em 1em; } div.glossary dt { font-weight: bold; } div.glossary dd p { margin-top: 0.2em; } dl { margin: .8em 0; line-height: 1.2; } dt { margin-top: 0.5em; } dt span.term { font-style: normal; color: navy; } div.variablelist dd p { margin-top: 0; } div.itemizedlist li, div.orderedlist li { margin-left: -0.8em; margin-top: 0.5em; } ul, ol { list-style-position: outside; } div.sidebar ul, div.sidebar ol { margin-left: 2.8em; } div.itemizedlist p.title, div.orderedlist p.title, div.variablelist p.title { margin-bottom: -0.8em; } div.revhistory table { border-collapse: collapse; border: none; } div.revhistory th { border: none; color: #527bbd; font-family: Arial,Helvetica,sans-serif; } div.revhistory td { border: 1px solid silver; } /* Keep TOC and index lines close together. */ div.toc dl, div.toc dt, div.list-of-figures dl, div.list-of-figures dt, div.list-of-tables dl, div.list-of-tables dt, div.indexdiv dl, div.indexdiv dt { line-height: normal; margin-top: 0; margin-bottom: 0; } /* Table styling does not work because of overriding attributes in generated HTML. */ div.table table, div.informaltable table { margin-left: 0; margin-right: 5%; margin-bottom: 0.8em; } div.informaltable table { margin-top: 0.4em } div.table thead, div.table tfoot, div.table tbody, div.informaltable thead, div.informaltable tfoot, div.informaltable tbody { /* No effect in IE6. */ border-top: 3px solid #527bbd; border-bottom: 3px solid #527bbd; } div.table thead, div.table tfoot, div.informaltable thead, div.informaltable tfoot { font-weight: bold; } div.mediaobject img { margin-bottom: 0.8em; } div.figure p.title, div.table p.title { margin-top: 1em; margin-bottom: 0.4em; } div.calloutlist p { margin-top: 0em; margin-bottom: 0.4em; } a img { border-style: none; } @media print { div.navheader, div.navfooter { display: none; } } span.aqua { color: aqua; } span.black { color: black; } span.blue { color: blue; } span.fuchsia { color: fuchsia; } span.gray { color: gray; } span.green { color: green; } span.lime { color: lime; } span.maroon { color: maroon; } span.navy { color: navy; } span.olive { color: olive; } span.purple { color: purple; } span.red { color: red; } span.silver { color: silver; } span.teal { color: teal; } span.white { color: white; } span.yellow { color: yellow; } span.aqua-background { background: aqua; } span.black-background { background: black; } span.blue-background { background: blue; } span.fuchsia-background { background: fuchsia; } span.gray-background { background: gray; } span.green-background { background: green; } span.lime-background { background: lime; } span.maroon-background { background: maroon; } span.navy-background { background: navy; } span.olive-background { background: olive; } span.purple-background { background: purple; } span.red-background { background: red; } span.silver-background { background: silver; } span.teal-background { background: teal; } span.white-background { background: white; } span.yellow-background { background: yellow; } span.big { font-size: 2em; } span.small { font-size: 0.6em; } span.underline { text-decoration: underline; } span.overline { text-decoration: overline; } span.line-through { text-decoration: line-through; } newsbeuter-2.7/doc/xhtml/newsbeuter.html000066400000000000000000005566001220711462700205350ustar00rootroot00000000000000 The Newsbeuter RSS Feedreader

    The Newsbeuter RSS Feedreader

    Andreas Krennmair


    1. Introduction

    Newsbeuter is an RSS feedreader. RSS is a number of widely-used XML formats to transmit, publish and syndicate articles, for example news or blog articles. Newsbeuter is designed to be used on text terminals on Unix or Unix-like systems such as Linux, FreeBSD or Mac OS X.

    1.1. Platforms

    Newsbeuter has been tested on Linux, FreeBSD and Mac OS X, and is available in the form of pre-built packages for many popular Linux distributions. For a current list of distributions with newsbeuter packages, consult this list on the newsbeuter website.

    OpenBSD is currently unsupported, as it lacks even the most basic support for internationalization and localization.

    NetBSD is currently not supported, due to technical limitations in the iconv() implementation.

    1.2. Why "Newsbeuter"?

    "Newsbeuter" is a pun on the German word "Wildbeuter", which means "hunter-gatherer". During the stone age, people hunted and gathered their food, and these days, they hunt and gather news and information. Credits for this idea goes to Clifford Wolf, who submitted it to a little competition that was started when I got aware that the original name would violate French and European registered trademarks.

    2. Installation

    This chapter describes how to compile and install newsbeuter from source.

    2.1. Downloading Newsbeuter

    Newsbeuter is available as source package. Simply go to http://www.newsbeuter.org/ and download the latest source package, which is usually in the .tar.gz file format. Alternatively, you can check out the latest development source tree from the newsbeuter Git repository (hosted on GitHub) by running the following command on the commandline:

    git clone git://github.com/akrennmair/newsbeuter.git

    2.2. Dependencies

    Newsbeuter depends on a number of libraries to function correctly. This table lists these dependencies. Please be aware that the list libraries may themselves depend on other libraries. These dependencies are not listed here. Please also be aware that you need a recent C++ compiler. Currently, newsbeuter has only been tested with GCC.

    If you intend to modify and regenerate the filter language parser, you will also need Coco/R for C++, which you can download from http://www.ssw.uni-linz.ac.at/coco/. The Coco/R binary must be installed as "cococpp" in your PATH. Debian users only need to install the package "coco-cpp". Use the "regenerate-parser" make target to regenerate the necessary files.

    2.3. Compiling and Installing

    After you’ve downloaded and installed the dependencies mentioned above, you can start compiling and installing newsbeuter. To compile newsbeuter, simply run "make" in the source tree. After a short time, this should complete successfully, and you can go on with installation by running "make install". By default, this will install the "newsbeuter" binary to the /usr/local/bin directory. You can provide an alternative installation path using the prefix parameter, e.g. running "make install prefix=/opt/newsbeuter" will install the binary to the directory /opt/newsbeuter/bin.

    3. First Steps

    After you’ve installed newsbeuter, you can run it for the first time by typing "newsbeuter" on your command prompt. This will bring you the following message:

    Error: no URLs configured. Please fill the file /home/ak/.newsbeuter/urls with RSS feed URLs or import an OPML file.
    newsbeuter 2.4
    usage: ./newsbeuter [-i <file>|-e] [-u <urlfile>] [-c <cachefile>] [-x <command> ...] [-h]
                    -e              export OPML feed to stdout
                    -r              refresh feeds on start
                    -i <file>       import OPML file
                    -u <urlfile>    read RSS feed URLs from <urlfile>
                    -c <cachefile>  use <cachefile> as cache file
                    -C <configfile> read configuration from <configfile>
                    -X              clean up cache thoroughly
                    -x <command>... execute list of commands
                    -o              activate offline mode (only applies to Google Reader synchronization mode)
                    -q              quiet startup
                    -v              get version information
                    -l <loglevel>   write a log with a certain loglevel (valid values: 1 to 6)
                    -d <logfile>    use <logfile> as output log file
                    -E <file>       export list of read articles to <file>
                    -I <file>       import list of read articles from <file>
                    -h              this help

    This means that newsbeuter can’t start without any configured feeds. To add feeds to newsbeuter, you can either add URLs to the configuration file $HOME/.newsbeuter/urls or you can import an OPML file by running "newsbeuter -i blogroll.opml". To manually add URLs, open the file with your favorite text editor and add the URLs, one per line:

    http://rss.cnn.com/rss/cnn_topstories.rss
    http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml

    If you need to add URLs that have restricted access via username/password, simply provide the username/password in the following way:

    http://username:password@hostname.domain.tld/feed.rss

    In order to protect username and password, make sure that $HOME/.newsbeuter/urls has the appropriate permissions. Newsbeuter also makes sure that usernames and passwords within URLs aren’t displayed in its user interface. In case there is a @ in the username, you need to write it as %40 instead so that it can be distinguished from the @ that separates the username/password part from the hostname part.

    You can also configure local files as feeds, by prefixing the local path with "file://" and adding it to the $HOME/.newsbeuter/urls file:

    file:///var/log/rss_eventlog.xml

    Now you can run newsbeuter again, and it will present you with a controllable list of the URLs that you configured previously. You can now start downloading the feeds, either by pressing "R" to download all feeds, or by pressing "r" to download the currently selected feed. You can then select a feed you want to read, and by pressing "Enter", you can go to the article list for this feed. This works even while the downloading is still in progress. You can now see the list of available articles by their title. A "N" on the left indicates that an article wasn’t read yet. Pressing Enter brings you to the content of the article. You can scroll through this text, and also run a browser (default: lynx) to view the complete article if the content is empty or just an abstract or a short description. Pressing "q" brings you back to the article list, and pressing "q" again brings you back to the feed list. Pressing "q" a third time then closes newsbeuter.

    Newsbeuter caches the article that it downloads. This means that when you start newsbeuter again and reload a feed, the old articles can still be read even if they aren’t in the current RSS feeds anymore. Optionally you can configure how many articles shall be preserved by feed so that the article backlog doesn’t grow endlessly (see "max-items" below).

    Newsbeuter also uses a number of measures to preserve the users' and feed providers' bandwidth, by trying to avoid unnecessary feed downloads through the use of conditional HTTP downloading. It saves every feed’s "Last-Modified" and "ETag" response header values (if present) and advises the feed’s HTTP server to only send data if the feed has been updated by modification date/time or "ETag" header. This doesn’t only make feed downloads for RSS feeds with no new updates faster, it also reduces the amount of transferred data per request. Conditional HTTP downloading can be optionally disabled per feed by using the "always-download" configuration command.

    Several aspects of newsbeuter’s behaviour can be configured via a configuration file, by default $HOME/.newsbeuter/config. This configuration file contains lines in the form "<config-command> <arg1> …". The configuration file can also contain comments, which start with the # character and go as far as the end of line. If you need to enter a configuration argument that contains spaces, use quotes (") around the whole argument. It’s even possible to integrate the output of external commands into the configuration. The text between two backticks ("`") is evaluated as shell command, and its output is put on its place instead. This works like backtick evaluation in Bourne-compatible shells and allows users to use external information from the system within the configuration.

    Searching for articles is possible in newsbeuter, too. Just press the "/" key, enter your search phrase, and the title and content of all articles are searched for it. When you do a search from the list of feeds, all articles of all feeds will be searched. When you do a search from the article list of a feed, only the articles of the currently viewed feed are searched. When opening an article from a search result dialog, the search phrase is highlighted.

    The history of all your searches is saved to the filesystem, to \~/.newsbeuter/history.search. By default, the last 100 search phrases are stored, but this limited can be influenced through the "history-limit" configuration variable. To disable search history saving, simply set the history-limit to 0.

    Table 1. Configuration Commands

    Configuration Command Argument(s) Default Description Example
    always-display-description [true/false] false If true, then the description will always displayed even if e.g. a content:encoded tag has been found. always-display-description true
    always-download <rssurl> [<rssurl>] n/a The parameters of this configuration command are one or more RSS URLs. These URLs will always get downloaded, regardless of their Last-Modified timestamp and ETag header. always-download "http://www.n-tv.de/23.rss"
    article-sort-order <sortfield>[-<direction>] date The sortfield specifies which article property shall be used for sorting (currently available: date, title, flags, author, link, guid). The optional direction specifies the sort direction ("asc" specifies ascending sorting, "desc" specifies descending sorting. for date, "desc" is default, for all others, "asc" is default). article-sort-order author-desc
    articlelist-format <format> "%4i %f %D %6L %?T?;%-17T; ?%t" This variable defines the format of entries in the article list. See the respective section in the documentation for more information on format strings (note that the semicolon should actually be a vertical bar; this is a limitation in AsciiDoc). articlelist-format "%4i %f %D %?T?;%-17T; ?%t"
    auto-reload [yes/no] no If enabled, all feeds will be automatically reloaded at start up and then continuously after a certain time has passed (see reload-time). auto-reload yes
    bind-key <key> <operation> [<dialog>] n/a Bind key <key> to <operation>. This means that whenever <key> is pressed, then <operation> is executed (if applicable in the current dialog). A list of available operations can be found below. Optionally, you can specify a dialog. If you specify one, the key binding will only be added to the specified dialog. Available dialogs are "all" (default if none is specified), "feedlist", "filebrowser", "help", "articlelist", "article", "tagselection", "filterselection", "urlview" and "podbeuter". bind-key ^R reload-all
    bookmark-cmd <bookmark-command> "" If set, then <bookmark-command> will be used as bookmarking plugin. See the documentation on bookmarking for further information. bookmark-cmd "~/bin/delicious-bookmark.sh"
    bookmark-interactive [yes/no] no If set to yes, then the configured bookmark command is an interactive program. bookmark-interactive yes
    bookmark-autopilot [yes/no] no If set to yes, the configured bookmark command is executed without any further input asked from user, uless the url or the title cannot be found/guessed. bookmark-autopilot yes
    browser <browser-command> lynx Set the browser command to use when opening an article in the browser. If <browser-command> contains %u, it will be used as complete commandline and %u will be replaced with the URL that shall be opened. browser "w3m %u"
    cache-file <path> "~/.newsbeuter/cache.db" This configuration option sets the cache file. This is especially useful if the filesystem of your home directory doesn’t support proper locking (e.g. NFS). cache-file "/tmp/testcache.db"
    cleanup-on-quit [yes/no] yes If yes, then the cache gets locked and superfluous feeds and items are removed, such as feeds that can’t be found in the urls configuration file anymore. cleanup-on-quit no
    color <element> <fgcolor> <bgcolor> [<attr> …] n/a Set the foreground color, background color and optional attributes for a certain element color background white black
    confirm-exit [yes/no] no If set to yes, then newsbeuter will ask for confirmation whether the user really wants to quit newsbeuter. confirm-exit yes
    cookie-cache <file> "" Set a cookie cache. If set, then cookies will be cached (i.e. read from and written to) in this file. cookie-cache "~/.newsbeuter/cookies.txt"
    datetime-format <date/time format> %b %d This format specifies the date/time format in the article list. For a detailed documentation on the allowed formats, consult the manpage of strftime(3). datetime-format "%D, %R"
    define-filter <name> <filter> n/a With this command, you can predefine filters, which can you later select from a list, and which are then applied after selection. This is especially useful for filters that you need often and you don’t want to enter them every time you need them. define-filter "all feeds with fun tag" "tags # \"fun\""
    delete-read-articles-on-quit [yes/no] "no" If set to "yes", then all read articles will be deleted when you quit newsbeuter. delete-read-articles-on-quit yes
    display-article-progress [yes/no] yes If set to yes, then a read progress (in percent) is displayed in the article view. Otherwise, no read progress is displayed. display-article-progress no
    download-retries <number retries> 1 How many times newsbeuter shall try to successfully download a feed before giving up. This is an option to improve the success of downloads on slow and shaky connections such as via a TOR proxy. download-retries 4
    download-full-page [yes/no] no If set to yes, then for all feed items with no content but with a link, the link is downloaded and the result used as content instead. This may significantly increase the download times of "empty" feeds. download-full-page yes
    download-timeout <seconds> 30 The number of seconds newsbeuter shall wait when downloading a feed before giving up. This is an option to improve the success of downloads on slow and shaky connections such as via a TOR proxy. download-timeout 60
    error-log <path> "" If set, then user errors (e.g. errors regarding defunct RSS feeds) will be logged to this file. error-log "~/.newsbeuter/error.log"
    external-url-viewer <command> "" If set, then "show-urls" will pipe the current article to a specific external tool instead of using the internal URL viewer. This can be used to integrate tools such as urlview. external-url-viewer "urlview"
    feed-sort-order <sortorder> none If set to "firsttag", the feeds in the feed list will be sorted by their first tag in the urls file. feed-sort-order firsttag
    feedlist-format <format> "%4i %n %11u %t" This variable defines the format of entries in the feed list. See the respective section in the documentation for more information on format strings. feedlist-format " %n %4i - %11u -%> %t"
    googlereader-flag-share <flag> "" If this is set and Google Reader support is used, then all articles that are flagged with the specified flag are being "shared" in Google Reader so that people that follow you can see it. googlereader-flag-share "a"
    googlereader-flag-star <flag> "" If this is set and Google Reader support is used, then all articles that are flagged with the specified flag are being "starred" in Google Reader and appear in the list of "Starred items". googlereader-flag-star "b"
    googlereader-login <login> "" This variable sets your Google Reader login for the Google Reader support. googlereader-login "your-login"
    googlereader-min-items <number> 20 This variable sets the number of articles that are loaded from Google Reader per feed. googlereader-min-items 100
    googlereader-password <password> "" This variable sets your Google Reader password for the Google Reader support. googlereader-password "your-password"
    googlereader-passwordfile <path-to-file "" A more secure alternative to the above, by storing your password elsewhere in your system. googlereader-passwordfile "path-to-file"
    googlereader-show-special-feeds [yes/no] yes If this is set, then "special feeds" like "People you follow" (articles shared by people you follow), "Starred items" (your starred articles), "Shared items" (your shared articles) and "Popular items" (articles considered to be popular by Google’s magic algorithms) appear in your subscription list. googlereader-show-special-feeds "no"
    goto-first-unread [yes/no] yes If set to yes (the default), then the first unread article will be selected whenever a feed is entered. goto-first-unread no
    goto-next-feed [yes/no] yes If set to yes, then the next-unread and prev-unread keys will search in other feeds for unread articles if all articles in the current feed are read. If set to no, then the next-unread and prev-unread keys will stop in the current feed. goto-next-feed no
    highlight <target> <regex> <fgcolor> [<bgcolor> [<attribute> …]] n/a With this command, you can highlight text parts in the feed list, the article list and the article view. For a detailed documentation, see the chapter on highlighting. highlight all "newsbeuter" red
    highlight-article <filterexpr> <fgcolor> <bgcolor> [<attribute> …] n/a With this command, you can highlight articles in the article list if they match a filter expression. For a detailed documentation, see the chapter on highlighting. highlight-article "author =~ \"Andreas Krennmair\"" white red bold
    history-limit <number> 100 Defines the maximum number of entries of commandline resp. search history to be saved. To disable history saving, set history-limit to 0. history-limit 0
    html-renderer <path> internal If set to "internal", then the internal HTML renderer will be used. Otherwise, the specified command will be executed, the HTML to be rendered will be written to the command’s stdin, and the program’s output will be displayed. This makes it possible to use other, external programs, such as w3m, links or lynx, to render HTML. html-renderer "w3m -dump -T text/html"
    http-auth-method <method> any Set HTTP authentication method. Allowed values: any, basic, digest, digest_ie (only available with libcurl 7.19.3 and newer), gssnegotiate, ntlm, anysafe. http-auth-method digest
    ignore-article <feed> <filterexpr> n/a If a downloaded article from <feed> matches <filterexpr>, then it is ignored and not presented to the user. This command is further explained in the "kill file" section below. ignore-article "*" "title =~ \"Windows\""
    ignore-mode [download/display] download This configuration option defines in what way an article is ignored (see ignore-article). If set to "download", then it is ignored in the download/parsing phase (which is the default) and thus never written to the cache, if it set to "display", it is ignored when displaying articles but is kept in the cache. ignore-mode "display"
    include <path> n/a With this command, you can include other files to be interpreted as configuration files. This is especially useful to separate your configuration into several files, e.g. key configuration, color configuration, … include "~/.newsbeuter/colors"
    keep-articles-days <days> 0 If set the a number greater than 0, only articles that are were published within the last <n> days are kept, and older articles are deleted. If set to 0 (default value), this option is not active. keep-articles-days 30
    macro <macro key> <command list> n/a With this command, you can define a macro key and specify a list of commands that shall be executed when the macro prefix and the macro key are pressed. macro k open ; reload ; quit
    mark-as-read-on-hover [yes/no] no If set to yes, then all articles that get selected in the article list are marked as read. mark-as-read-on-hover yes
    max-download-speed <number> 0 If set to a number great than 0, the download speed per download is set to that limit (in kB). max-download-speed 50
    max-items <number> 0 Set the number of articles to maximally keep per feed. If the number is set to 0, then all articles are kept. max-items 100
    notify-format <string> "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" Format string that is used for formatting notifications. See the chapter on format strings for more information. notify-format "%d new articles (%n unread articles, %f unread feeds)"
    notify-program <path> "" If set, then the configured program will be executed if new articles arrived (through a reload) or if notify-always is true. The first parameter of the called program contains the notification message. notify-program "~/bin/my-notifier"
    notify-always [yes/no] no If no, notifications will only be made when there are new feeds or articles. If yes, notifications will be made regardless. notify-always yes
    notify-screen [yes/no] no If yes, then a "privacy message" will be sent to the terminal, containing a notification message about new articles. This is especially useful if you use terminal emulations such as GNU screen which implement privacy messages. notify-screen yes
    notify-xterm [yes/no] no If yes, then the xterm window title will be set to a notification message about new articles. notify-xterm yes
    notify-beep [yes/no] no If yes, then the speaker beep on new articles. notify-beep yes
    opml-url <url> … "" If the OPML online subscription mode is enabled, then the list of feeds will be taken from the OPML file found on this location. Optionally, you can specify more than one URL. All the listed OPML URLs will then be taken into account when loading the feed list. opml-url "http://host.domain.tld/blogroll.opml" "http://example.com/anotheropmlfile.opml"
    pager [<path>/internal] internal If set to "internal", then the internal pager will be used. Otherwise, the article to be displayed will be rendered to be a temporary file and then displayed with the configured pager. If the pager path is set to an empty string, the content of the "PAGER" environment variable will be used. If the pager path contains a placeholder "%f", it will be replaced with the temporary filename. less %f
    podcast-auto-enqueue [yes/no] no If yes, then all podcast URLs that are found in articles are added to the podcast download queue. See the respective section in the documentation for more information on podcast support in newsbeuter. podcast-auto-enqueue yes
    prepopulate-query-feeds [yes/no] no If yes, then all query feeds are prepopulated with articles on startup. prepopulate-query-feeds yes
    proxy <server:port> n/a Set the proxy to use for downloading RSS feeds. proxy localhost:3128
    proxy-auth <auth> n/a Set the proxy authentication string. proxy-auth user:password
    proxy-auth-method <method> any Set proxy authentication method. Allowed values: any, basic, digest, digest_ie (only available with libcurl 7.19.3 and newer), gssnegotiate, ntlm, anysafe. proxy-auth-method ntlm
    proxy-type <type> http Set proxy type. Allowed values: http, socks4, socks4a, socks5. proxy-type socks5
    refresh-on-startup [yes/no] no If yes, then all feeds will be reloaded when newsbeuter starts up. This is equivalent to the -r commandline option. refresh-on-startup yes
    reload-only-visible-feeds [yes/no] no If yes, then manually reloading all feeds will only reload the currently visible feeds, e.g. if a filter or a tag is set. reload-only-visible-feeds yes
    reload-time <number> 60 The number of minutes between automatic reloads. reload-time 120
    reload-threads <number> 1 The number of parallel reload threads that shall be started when all feeds are reloaded. reload-threads 3
    reset-unread-on-update <url> … n/a With this configuration command, you can provide a list of RSS feed URLs for whose articles the unread flag will be reset if an article has been updated, i.e. its content has been changed. This is especially useful for RSS feeds where single articles are updated after publication, and you want to be notified of the updates. reset-unread-on-update "http://blog.fefe.de/rss.xml?html"
    save-path <path> ~/ The default path where articles shall be saved to. If an invalid path is specified, the current directory is used. save-path "~/Saved Articles"
    search-highlight-colors <fgcolor> <bgcolor> [<attribute> …] black yellow bold This configuration command specifies the highlighting colors when searching for text from the article view. search-highlight-colors white black bold
    show-keymap-hint [yes/no] yes If no, then the keymap hints on the bottom of screen will not be displayed. show-keymap-hint no
    show-read-feeds [yes/no] yes If yes, then all feeds, including those without unread articles, are listed. If no, then only feeds with one or more unread articles are list. show-read-feeds no
    show-read-articles [yes/no] yes If yes, then all articles of a feed are listed in the article list. If no, then only unread articles are listed. show-read-articles no
    suppress-first-reload [yes/no] no If yes, then the first automatic reload will be suppressed if auto-reload is set to yes. suppress-first-reload yes
    swap-title-and-hints [yes/no] no If yes, then the title at the top of screen and keymap hints at the bottom of screen will be swapped. swap-title-and-hints yes
    text-width <number> 0 If set to a number greater than 0, then all HTML will be rendered to this maximum line length. If set to 0, the terminal width will be used. text-width 72
    ttrss-flag-publish <character> "" If this is set and Tiny Tiny RSS support is used, then all articles that are flagged with the specified flag are being marked as "published" in Tiny Tiny RSS. ttrss-flag-publish "b"
    ttrss-flag-star <character> "" If this is set and Tiny Tiny RSS support is used, then all articles that are flagged with the specified flag are being "starred" in Tiny Tiny RSS. ttrss-flag-star "a"
    ttrss-login <username> "" Sets the username for use with Tiny Tiny RSS. ttrss-login "admin"
    ttrss-mode [multi/single] multi Configures the mode in which Tiny Tiny RSS is used. In single-user mode, login and password are used for HTTP authentication, while in multi-user mode, they are used for authenticating with Tiny Tiny RSS. ttrss-mode "single"
    ttrss-password <password> "" Configures the password for use with Tiny Tiny RSS. ttrss-password "mypassword"
    ttrss-url <url> "" Configures the URL where the Tiny Tiny RSS installation you want to use resides. ttrss-url "http://example.com/ttrss/"
    unbind-key <key> [<dialog>] n/a Unbind key <key>. This means that no operation is called when <key> is pressed. Optionally, you can specify a dialog (for a list of available dialogs, see "bind-key" above). If you specify one, the key binding will only be unbound for the specified dialog. unbind-key R
    urls-source <source> "local" This configuration command sets the source where URLs shall be retrieved from. By default, this is ~/.newsbeuter/urls. Alternatively, you can set it to "opml", which enables newsbeuter’s OPML online subscription mode, to "ttrss" which enables newsbeuter’s Tiny Tiny RSS support, or to "googlereader", which enables newsbeuter’s Google Reader support. In order to make Google Reader support work correctly, you also need to set googlereader-login and googlereader-password, while the Tiny Tiny RSS support requires login, password and URL of the Tiny Tiny RSS installation to use (see above). urls-source "googlereader"
    use-proxy [yes/no] no If yes, then the configured proxy will be used for downloading the RSS feeds. use-proxy yes
    user-agent <user agent string> "" If set to a non-zero-length string, this value will be used as HTTP User-Agent header for all HTTP requests. user-agent "Lynx/2.8.5rel.1 libwww-FM/2.14"

    Table 2. Available Operations

    Operation Default key Description
    open ENTER Open the currently selected feed or article.
    quit q Quit the program or return to the previous dialog (depending on the context).
    reload r Reload the currently selected feed.
    reload-all R Reload all feeds.
    mark-feed-read A Mark all articles in the currently selected feed read.
    mark-all-feeds-read C Mark articles in all feeds read.
    save s Save the currently selected article to a file.
    next-unread n Jump to the next unread article.
    prev-unread p Jump to the previous unread article.
    next J Jump to next article.
    prev K Jump to previous article.
    random-unread ^K Jump to a random unread article.
    open-in-browser o Opens the URL associated with the current article.
    open-in-browser-and-mark-read O Opens the URL associated with the current article and marks the article as read.
    help ? Runs the help screen.
    toggle-source-view ^U Toggles between the HTML view and the source view in the article view.
    toggle-article-read N Toggle the read flag for the currently selected article.
    toggle-show-read-feeds l Toggle whether read feeds should be shown in the feed list.
    show-urls u Show all URLs in the article in a list (similar to urlview).
    clear-tag ^T Clear current tag.
    set-tag t Select tag.
    open-search / Opens the search dialog. When a search is done in the article list, then the search operation only applies to the articles of the current feed, otherwise to all articles.
    goto-url # Open the URL dialog and then opens specified URL.
    enqueue e Add the podcast download URL of the current article (if any is found) to the podcast download queue (see the respective section in the documentation for more information on podcast support).
    edit-urls E Edit the list of subscribed URLs. newsbeuter will start the editor configured through the $VISUAL environment variable (if unset, $EDITOR is used; fallback
    reload-urls ^R Reload the URLs configuration file.
    redraw ^L Redraw the screen.
    cmdline <colon> Open the command line.
    set-filter F Set a filter.
    select-filter f Select a predefined filter.
    clear-filter ^F Clear currently set filter.
    bookmark ^B Bookmark currently selected article or URL.
    edit-flags ^E Edit the flags of the currently selected article.
    next-unread-feed ^N Go to the next feed with unread articles. This only works from the article list.
    prev-unread-feed ^P Go to the previous feed with unread articles. This only works from the article list.
    next-feed j Go to the next feed. This only works from the article list.
    prev-feed k Go to the previous feed. This only works from the article list.
    delete-article D Delete the currently selected article.
    purge-deleted $ Purge all article that are marked as deleted from the article list.
    view-dialogs v View list of open dialogs.
    close-dialog ^X Close currently selected dialog.
    next-dialog ^V Go to next dialog.
    prev-dialog ^G Go to previous dialog.
    pipe-to | Pipe article to command.
    sort g Sort feeds/articles by interactively choosing the sort method.
    revsort G Sort feeds/articles by interactively choosing the sort method (reversed).
    up UP Goes up one item in the list.
    down DOWN Goes down one item in the list.
    pageup PPAGE Goes up one page in the list.
    pagedown NPAGE Goes down one page in the list.

    Keys, as used in the bind-key configuration command, use a special syntax. Lowercase keys, uppercase keys and special characters are written literally. The Enter key is written as "ENTER", while the Esc key is written as "ESC". The function keys F1 to F12 are written as "F1" to "F12". The Space key is written as "SPACE". Key combinations with the Ctrl key, such as Ctrl-R, are written as ^R. Please be aware that all Ctrl-related key combinations need to be written in uppercase. The following identifiers for keys are supported:

    • ENTER (Enter key)
    • BACKSPACE (backspace key)
    • LEFT (left cursor)
    • RIGHT (right cursor)
    • UP (up cursor)
    • PPAGE (page up cursor)
    • NPAGE (page down cursor)
    • DOWN (down cursor)
    • ESC (Esc key)

    The "Tab" key can’t be bound due to technical limitations of STFL.

    3.1. Example Configuration

    # a comment
    max-items        100 # such comments are possible, too
    browser          links
    show-read-feeds  no
    unbind-key       R
    bind-key         ^R    reload-all

    3.2. Configuring Colors

    It is possible to configure custom color settings in newsbeuter. The basic configuration syntax is:

    color <element> <foreground color> <background color> [<attribute> ...]

    This means that if you configure colors for a certain element, you need to provide a foreground color and a background color as a minimum. The following colors are supported:

    • black
    • red
    • green
    • yellow
    • blue
    • magenta
    • cyan
    • white
    • default
    • color<n>, e.g. color123

    The "default" color means that the terminal’s default color will be used. The "color<n>" color name can be used if your terminal support 256 colors (e.g. gnome-terminal, xterm with $TERM set to xterm-256color). Newsbeuter contains support for 256 color terminals since version 2.1. For a complete chart of colors and their corresponding numbers, please see http://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html.

    Optionally, you can also add one or more attributes. The following attributes are supported:

    • standout
    • underline
    • reverse
    • blink
    • dim
    • bold
    • protect
    • invis

    Currently, the following elements are supported:

    • listnormal: a normal list item
    • listfocus: the currently selected list item
    • listnormal_unread: an unread list item
    • listfocus_unread: the currently selected and unread list item
    • info: the info bars on top and bottom
    • background: the application background
    • article: the article text

    The default color configuration of newsbeuter looks like this:

    background          white   black
    listnormal          white   black
    listfocus           yellow  blue   bold
    listnormal_unread   magenta black
    listfocus_unread    magenta blue   bold
    info                yellow  blue   bold
    article             white   black

    3.3. Migrating from other RSS Feed Readers

    It is very likely that you have used other RSS feed readers before. In this case, it is practical to migrate the previous configuration to newsbeuter. The vast amount of RSS feed readers allows the export of subscriptions via OPML files. OPML is an XML file format that was designed to save outlines, and has found its primary use in the import and export of feed subscriptions between different RSS feed readers.

    The best thing to start with is to export your subscriptions from the old reader. Usually, RSS feed readers have appropriate menu items available to do so.

    Snownews provides a script to convert your current subscription file into an OPML file:

    snow2opml > ~/blogroll.opml

    This command creates from your Snownews configuration a file blogroll.opml in your home directory. To export the subscription list from raggle, the following command is necessary:

    raggle --export-opml ~/blogroll.opml

    When you have exported the subscriptions from your old RSS feed reader, you can import them into newsbeuter:

    newsbeuter -i ~/blogroll.opml

    Don’t worry, newsbeuter won’t destroy your existing configuration, or add subscriptions more than once: every URL that is added to the subscription list is checked before whether it is already in the list, and is only added if not. This makes it possible to merge several OPML files into your subscription list.

    If your old RSS feed reader was able to structure your subscriptions in hierarchies, and reflected this structure in the exported OPML file, newsbeuter doesn’t throw away this information (although it doesn’t support hierarchies), but generates tags from it. Tags are newsbeuter’s way of organizing subscriptions in a non-hierarchical way. More information on the use of tags can be found below.

    Imagine the following folder hierarchy:

    |- News
    | |- Europe
    | `- International
    |- IT
    | |- Linux
    | |- Windows
    | `- Programming
    |   |- C++
    |   |- Ruby
    |   `- Erlang
    `- Private

    Subscriptions found in the folder "Private" will be tagged with "Private", subscriptions in the folder "International" will be tagged with "News" and "News/International", subscriptions in the folder "Erlang" will be tagged ith "IT", "IT/Programming" and "IT/Programming/Erlang", and so on. This means that when you select the tag "Programming" in newsbeuter, you will see all subscriptions that were in the "Programming" folder or one of its subfolders before. This means that you will lose virtually nothing of your previously configured structure.

    4. Advanced Features

    4.1. Tagging

    Newsbeuter comes with the possibility to categorize or "tag", as we call it, RSS feeds. Every RSS feed can be assigned 0 or more tags. Within newsbeuter, you can then select to only show RSS feeds that match a certain tag. That makes it easy to categorize your feeds in a flexible and powerful way.

    Usually, the ~/.newsbeuter/urls file contains one RSS feed URL per line. To assign a tag to an RSS feed, simply attach it as a single word, separated by blanks such as space or tab. If the tag needs to contain spaces, you must use quotes (") around the tag (see example below). An example \~/.newsbeuter/urls file may look like this:

    http://blog.fefe.de/rss.xml?html interesting conspiracy news "cool stuff"
    http://rss.orf.at/news.xml news orf
    http://www.heise.de/newsticker/heise.rdf news interesting

    When you now start newsbeuter with this configuration, you can press "t" to select a tag. When you select the tag "news", you will see all three RSS feeds. Pressing "t" again and e.g. selecting the "conspiracy" tag, you will only see the http://blog.fefe.de/rss.xml?html RSS feed. Pressing "^T" clears the current tag, and again shows all RSS feeds, regardless of their assigned tags.

    A special type of tag are tags that start with the tilde character ("~"). When such a tag is found, the feed title is set to the tag name (excluding the \~ character). With this feature, you can give feeds any title you want in your feed list:

    http://rss.orf.at/news.xml "~ORF News"

    Another special type of tag are tags that start with the exclamation mark. When such a tag is found, the feed is hidden from the regular list of feeds and its content can only be found through a query feed.

    http://rss.orf.at/news.xml "!ORF News (hidden)"

    4.2. Scripts and Filters (Snownews Extensions)

    From version 0.4 on, newsbeuter contains support for Snownews extensions. The RSS feed readers Snownews and Liferea share a common way of extending the readers with custom scripts. Two mechanisms, namely "execurl" and "filter" type scripts, are available and supported by newsbeuter.

    An "execurl" script can be any program that gets executed and whose output is interpreted as RSS feed, while "filter" scripts are fed with the content of a configured URL and whose output is interpreted as RSS feed.

    The configuration is simple and straight-forward. Just add to your ~/.newsbeuter/urls file configuration lines like the following ones:

    exec:~/bin/execurl-script
    filter:~/bin/filter-script:http://some.test/url

    The first line shows how to add an execurl script to your configuration: start the line with "exec:" and then immediately append the path of the script that shall be executed. If this script requires additional parameters, simply use quotes:

    "exec:~/bin/execurl-script param1 param2"

    The second line shows how to add a filter script to your configuration: start the line with "filter:", then immediately append the path of the script, then append a colon (":"), and then append the URL of the file that shall be fed to the script. Again, if the script requires any parameters, simply quote:

    "filter:~/bin/filter-script param1 param2:http://url/foobar"

    In both cases, the tagging feature as described above is still available:

    exec:~/bin/execurl-script tag1 tag2 "quoted tag"
    filter:~/bin/filter-script:http://some.test/url tag3 tag4 tag5

    A collection of such extension scripts can be found on this website: http://kiza.kcore.de/software/snownews/snowscripts/extensions

    If you want to write your own extensions, refer to this website for further instructions: http://kiza.kcore.de/software/snownews/snowscripts/writing

    4.3. Bookmarking

    Since version 0.7, newsbeuter contains a plugin-based bookmarking system. When a user bookmarks a link (possible in the article list, in the article view, and in the URL view), he is asked for the URL to bookmark (already preset with the URL of the current selection), the bookmark title (in most cases preset with the title of the current selection) and the bookmark description. After the question for the description, an external program, configured via the configuration command "bookmark-cmd", is executed with 3 commandline parameters. The plugin itself implements the actual bookmark saving (e.g. writing the bookmark to an external file, or storing it to a del.icio.us account). When everything went OK, the plugin simply exits. In case something goes wrong while saving the bookmark, it writes out an error message as a single line. This error message is then presented to the user from within newsbeuter.

    Newsbeuter comes with an example plugin, which implements a simple tab-separated bookmark file. This example can be found in the "doc" subdirectory.

    4.4. Command Line

    Like other text-oriented software, newsbeuter contains an internal commandline to modify configuration variables ad hoc and to run own commands. It provides a flexible access to the functionality of newsbeuter which is especially useful for advanced users.

    To start the commandline, type ":". You will see a ":" prompt at the bottom of the screen, similar to tools like vi(m) or mutt. You can now enter commands. Pressing the return key executes the command (possibly giving feedback to the user) and closes the commandline. You can cancel entering commands by pressing the ESC key. The history of all the commands that you enter will be saved to \~/.newsbeuter/history.cmdline. The backlog is limited to 100 entries by default, but can be influenced by setting the "history-limit" configuration variable. To disable history saving, set the history-limit to 0.

    Starting with newsbeuter 2.0, the commandline provides you with some help if you can’t remember the full names of commandline commands. By pressing the TAB key, newsbeuter will try to automatically complete your command. If there is more than one possible completion, you can subsequently press the TAB key to cycle through all results. If no match is found, no suggestion will be inserted into the commandline. For the "set" command, the completion also works for configuration variable names.

    In addition, some common key combination such as Ctrl-G (to cancel input), Ctrl-K (to delete text from the cursor position to the end of line), Ctrl-U (to clear the whole line) and Ctrl-W (to delete the word before the current cursor position) were added.

    Please be aware that the input history of both the command line and the search functions are saved to the filesystems, to the files ~/.newsbeuter/history.cmdline resp. \~/.newsbeuter/history.search. By default, the last 100 entries are saved, but this can be configured (configuration variable history-limit) and also totally disabled (by setting said variable to 0).

    Currently, the following command line commands are available:

    Table 3. Available Commandline Commands

    Command Syntax Description Example
    quit quit Quit newsbeuter. quit
    save save <filename> Save the currently select article to disk. This works in the article list and in the article view. save ~/important.txt
    set set <variable>[=<value>|&|!] Set configuration variable <variable> to <value>. If no value is specified, the current value is printed out. Specifying a ! after the name of boolean configuration variables toggles their values, a & directly after the name of a configuration variable of any type resets its value to the documented default value. set reload-time=15
    tag tag <tagname> Only display feeds with the tag <tagname>. tag news
    goto goto <case-insensitive substring> Go to the next feed whose name contains the case-insensitive substring. goto foo
    source source <filename> […] Load the specified configuration files. This allows it to load alternative configuration files or reload already loaded configuration files on-the-fly from the filesystem. source ~/.newsbeuter/colors
    dumpconfig dumpconfig <filename> Save current internal state of configuration to file, so that it can be instantly reused as configuration file. dumpconfig ~/.newsbeuter/config.saved
    dumpform dumpform Dump current dialog to text file. This is meant for debugging purposes only. dumpform
    n/a <number> Jump to the entry with the index <number> (usually seen at the left side of the list). This currently works for the feed list and the article list. 30

    4.5. Filter Language

    Newsbeuter provides a powerful filter language that enables the user to filter the content of many dialogs, such as the feed list or the article list. The basic concept is that every feed and every article has a number of attributes which can then be compared with user-supplied values, and these comparisons and be logically AND’ed, OR’ed and grouped.

    Examples for simple filter expressions are:

    unread_count > 0
    rssurl =~ "^https:"
    age between 0:10

    Logically connecting and grouping such expressions looks like in the following examples:

    ( unread_count > 0 and unread_count < 10 ) or total_count > 100
    ( author =~ "Frank" or author =~ "John" ) and ( title =~ "Linux" or title =~ "FreeBSD" )

    The possibilities for combining such queries is endless, sky (actually: the available memory) is the limit.

    To filter your feeds, press "F" in the feed list, enter your filter expression, and press enter. To clear the filter, press Ctrl-F. To filter the articles in the article list, press "F", enter your expression, and press enter. Clearing the filter works the same as before. Be aware that only certain attributes work in both dialogs. The table below lists all available attributes and their context, i.e. an attribute that belongs to a feed can only be matched in the feed list, while an attribute that belongs to an article can only be matched in the article list.

    Table 4. Available Comparison Operators

    Operator Meaning
    = test for equality ("==" works, too)
    != test for inequality; logical negation of = operator
    =~ test whether regular expression matches
    !~ logical negation of the =~ operator
    < less than
    > greater than
    less than or equal
    >= greater than or equal
    between within a range of integer values, where the two integer values are separated by a colon (see above for an example)
    # contains; this operator matches if a word is contained in a list of space-separated words (useful for matching tags, see below)
    !# contains not; the negation of the # operator

    Table 5. Available Attributes

    Attribute Context Meaning
    title article article title
    link article article link
    author article article author
    content article article body
    date article publication date of the article
    guid article a unique identifier of the article
    unread article indicates whether the article has been read
    enclosure_url article the URL of a possible enclosure (e.g. podcast file)
    enclosure_type article the MIME type of the enclosure URL
    flags article The set of flags of the article
    age article Age of an article (in days)
    articleindex article Index of an article in an article list
    feedtitle feed, article title of the feed
    description feed, article feed description
    feedlink feed, article link to the feed
    feeddate feed, article publication date of the feed
    rssurl feed, article RSS URL of the feed
    unread_count feed, article number of unread articles in the feed
    total_count feed, article total number of articles in the feed
    tags feed, article all tags that are associated with the feed
    feedindex feed, article Index of a feed in the feed list

    Note that it’s also possible to filter for feed attributes when you query for article attributes. This is because every article is internally linked to the feed from which it was downloaded.

    4.6. Killfiles

    Sometimes, a user is confronted with certain content he doesn’t want to read, e.g. on topics the user is not interested in or articles from certain people he doesn’t want to read. In Usenet, such functionality within software is traditionally called a "killfile", i.e. based on the content of this "killfile", articles that match certain conditions do not get displayed and are not presented to the user at all.

    In newsbeuter, such a "killfile" can be implemented on a per-article basis via the configuration file. The most important configuration command for this is "ignore-article":

    ignore-article "*" "title =~ \"Gentoo\""
    ignore-article "http://synflood.at/blog/index.php?/feeds/index.rss2" "title =~ \"newsbeuter\""

    The basic format is that the user specifies an RSS feed for which the ignore shall be applied ("*" matches all RSS feeds), and then a filter expression (see previous section). If newsbeuter hits an article in the specified RSS feed that matches the specified filter expression, then this article is ignored and never presented to the user. The configuration itself can contain as many ignore-article commands as desired.

    Since newsbeuter 2.2, you can specify the way an article is ignored. There are two ways available:

    • During download: articles are ignored when a feed is downloaded and parsed, and thus won’t be written to the local cache.
    • During display: articles are downloaded and written to the local cache, but are ignored when a feed is displayed.

    Both modes have their advantages and disadvantages: while the download ignore mode saves some storage, you cannot simply "undo" the ignore by removing it from the configuration file: if an ignored article has already vanished from a feed, it won’t reappear. On the other hand, the display ignore mode requires some more space, but has the advantage that an ignore can be "undone" by removing the ignore-article configuration command from the configuration.

    The default ignore mode is "download". You can set the ignore mode in the configuration file:

    ignore-mode "display"

    4.7. Query Feeds

    Query feeds are a mechanism of newsbeuter to define custom "meta feeds" by using newsbeuter’s built-in filter language. A query feed is a feed that is aggregated from all currently downloaded articles of all feeds. To narrow down the set of articles, the user has to specify a filter. Only articles that match this filter are added to the query feed. A query feed is updated whenever it is entered in the feed list. When you change the unread flag of an article, this is reflected in the feed where the article was originally fetched.

    To define a query feed, the user has to add a line to the file ~/.newsbeuter/urls in the following format:

    query:<name of feed>:<filter expression> [<tag> ...]

    The "query:" in the beginning tells newsbeuter that it’s a query feed, "<name of feed>" specifies the name under which the query feed shall be displayed in the feed list, and "<filter expression>" is the filter expression that shall be used. Like every other feed, a query feed can be tagged to organize it like a regular feed.

    A good example for the user of this feature is a query feed that contains all unread articles:

    "query:Unread Articles:unread = \"yes\""

    Note the quotes that are necessary around the complete query "URL" and the backslashes that are necessary the escape the quotes in the filter expression.

    If you want to combine several feeds to one single feed, a good solution is to tag the feeds that you want to combine with one certain tag, and then create a query feed that only displays articles from feeds with that certain tag:

    http://domain1.tld/feed.xml fun news tag1
    http://domain2.tld/?feed.rss private jokes tag1
    http://domain3.tld/feeds.rss news
    "query:tag1 Articles:tags # \"tag1\""

    In this example, the feeds http://domain1.tld/feed.xml and http://domain2.tld/?feed.rss are aggregated into the query feed named "tag1 Articles", but the feed http://domain3.tld/feeds.rss is not.

    Basically, the possibility of what can be realized with query feeds is only limited by what can be queried from articles and feeds with the filter language and by your creativity.

    4.8. Google Reader Support

    Google Reader is Google’s web-based feed aggregator. Newsbeuter provides functionality to use Google Reader as its backend: people can use Google Reader to manage their subscriptions, and in addition, use newsbeuter to download and read articles. Newsbeuter will keep the information which articles have already been read synchronized with Google Reader, so that users usually won’t see articles more than once. In addition, it will only ever download unread articles from Google Reader.

    In order to use Google Reader support, you first need to configure the proper URL source:

    urls-source "googlereader"

    In addition, newsbeuter needs to know your Google Reader username and password so that it can authenticate with Google Reader:

    googlereader-login "your-googlereader-account"
    googlereader-password "your-password"

    After setting these configuration values, you can start newsbeuter, it will authenticate with Google Reader and download your subscription list. If you use "folders" in Google Reader to organize your feeds, newsbeuter will regard them and make them available via its "tags" capability: each feed is tagged with the name of the folder in which it resides.

    When you mark single items or complete feeds as read, newsbeuter will synchronize this information directly to Google Reader. This, of course, includes opening articles. Toggling read articles back to "unread" is also communicated to Google Reader.

    In addition, Google Reader provides the ability to "star" and to "share" articles. Starred articles are basically bookmarks, while shared articles are shown to people that follow your Google Reader account. Newsbeuter allows the use of this feature by mapping its powerful "flags" to the "star"/"unstar" resp. "share"/"unshare" operations.

    In order to use this mapping, all you need to do is to configure the flags that shall be used:

    googlereader-flag-share "a"
    googlereader-flag-star "b"

    After that, use these flags when you edit flags for an article, and these articles will be starred resp. shared.

    By default, newsbeuter also shows Google Reader "special feeds": - People you follow: articles shared by people that you follow. - Starred items: articles that you starred. - Shared items: articles that you shared. - Popular items: articles that are considered to be popular by Google’s algorithms.

    You can disable these feeds by setting the following configuration variable:

    googlereader-show-special-feeds no

    4.9. Bloglines Synchronization

    Up to and including version 2.3, newsbeuter contained support for synchronization with Bloglines. On October 1, 2010, Bloglines was discontinued, and newsbeuter’s support for Bloglines was subsequently removed.

    4.10. Tiny Tiny RSS Synchronization

    Since version 2.5, newsbeuter can be used to synchronize with Tiny Tiny RSS installations. Tiny Tiny RSS is a web-based and (optionally) multi-user feed reader. By providing the ability to use Tiny Tiny RSS as its backend, it’s possible for users to manage their subscriptions centrally within Tiny Tiny RSS while reading them wherever they are using newsbeuter.

    If you want to use Tiny Tiny RSS support, don’t forget to activate the external API support in your preferences.

    To use Tiny Tiny RSS support, you need to configure a few things. First of all, newsbeuter needs to know that you want to use Tiny Tiny RSS and which installation exactly:

    urls-source "ttrss"
    ttrss-url "http://example.com/ttrss/"

    In addition, it requires username and password for authentication:

    ttrss-login "myusername"
    ttrss-password "mypassword"

    Tiny Tiny RSS provides two modes of usage, single-user mode and multi-user mode. newsbeuter needs to know about this, too: In single-user mode, authentication is done via Basic HTTP authentication, while in multi-user mode, authentication is done against Tiny Tiny RSS itself.

    ttrss-mode "single"             # "multi" is default

    With these settings, newsbeuter should be able to connect to Tiny Tiny RSS and download your subscribed feeds. Articles or even complete feeds that you marked as read are synchronized directly to Tiny Tiny RSS.

    Tiny Tiny RSS provides the ability to "star" and to "publish" articles. Starred articles are basically bookmarks, while published articles can be retrieved via a pubic RSS feed. Newsbeuter allows the use of these features by mapping its flags to the "star" and "publish" operations.

    In order to use this mapping, you need to configure the flags that shall be used:

    ttrss-flag-star "s"
    ttrss-flag-publish "p"

    After that, use these flags when you edit flags for an article, and these articles will be starred resp. published.

    4.11. OPML Online Subscription Mode

    The OPML online subscription mode works similar to the Google Reader synchronization mode, except that no information about read articles is synchronized back. When enabled, all feeds that are listed in the feed list will be taken from one or more OPML files that are downloaded from a freely configurable URL.

    To enable this mode, the following configuration needs to be done:

    urls-source "opml"
    opml-url "<opml url>" ["<opml url>" ...]

    "opml" must be specified as source for the feed URLs, and the URLs of the OPML file needs to be specified, too. As with Google Reader synchronization mode, the offline mode via "newsbeuter -o" also works with OPML online subscription mode.

    4.12. Flagging Articles

    To support custom categorization of articles by the user, it is possible to flag an article. A valid flag is any character from A to Z and from a to z. Every article can be flagged with up to 52 different flags, i.e. every letter from the Roman alphabet in upper and lower case. Flagging is easy: just select an article in the article list, or enter the article view, and press ^E. This will start the flag editor. By pressing enter, the new flags are saved. You can cancel by pressing the ESC key.

    The flags of an article can be used in every filter expression. The flags of an article are always ordered, and when new flags are added, ordering is immediately restored. This behaviour can also be relied upon when querying articles via the filter language.

    If an article contains one or more flags, it is marked with an "!" in the article list. In the article view, all flags (if available) are listed.

    4.13. Macro Support

    In newsbeuter, it’s possible to define macros to execute more than one command at once. A macro is configured using the "macro" configuration command. The first parameter to "macro" is the key, all parameters afterwards are operations (as listed in the "Available Operations" table above), optionally with parameters on their own, separated by the ";" character. Here’s a simple example:

    macro k open ; reload ; quit
    macro o open-in-browser ; toggle-article-read "read"

    When the user presses the macro prefix ("," by default) and then the "k" key, the three operations "open", "reload" and "quit" will be executed subsequently.

    It is also possible to modify configuration variables within macros, which can e.g. be used to temporarily modify the browser configuration variable to do something else, such as running an image viewer from the URLs view:

    macro i set browser "feh %u"; open ; set browser "elinks %u"

    You can even use this feature to enqueue any of the URLs from the URLs view to podbeuter’s download queue:

    macro E set browser "echo %u >> ~/.newsbeuter/queue" ; open ; set browser "elinks %u"

    4.14. Commandline Commands

    Newsbeuter comes with a -x option that indicates that commands added as arguments to the command line shall be executed. Currently, the following commands are available:

    • reload: this option reloads all feeds, and quits newsbeuter without printing any output. This is useful if a user wants to periodically reload all feeds without always having a running newsbeuter instance, e.g. from cron.
    • print-unread: this option prints the number of unread articles and quits newsbeuter. This is useful for users who want to integrate this number into some kind of monitoring system.

    4.15. Format Strings

    Newsbeuter contains a powerful format string system to make it possible for the user to configure the format of various aspects of the application, such as the format of entries in the feed list or in the article list.

    Format strings are similar to those that are found in the "printf" function in the C programming language. A format sequence begins with the % character, followed by optional alignment indication: positive numbers indicate that the text that is inserted for the sequence shall be padded right to a total width that is specified by the number, while negative number specify left padding. Followed by the padding indication comes the actual sequence identifier, which is usually a single letter.

    In addition, newsbeuter provides other, more powerful sequences, such as "%>[char]", which indicates that the text right to the sequence will be aligned right on the screen, and characters between the text on the left and the text on the right will be filled by "[char]". Another powerful format is the conditional sequence, "%?[char]?[format 1]&[format 2]?": if the text of the sequence identifier "[char]" is non-empty, then "[format 1]" will be evaluated and inserted, otherwise "[format 2]" will be evaluated and inserted. The "&" and "[format 2]" are optional, i.e. if the identifier’s text is empty, then an empty string will be inserted.

    The following tables show what sequence identifiers are available for which format:

    Table 6. Available Identifiers for feedlist-format

    Identifier Meaning
    d Feed description
    i Feed index
    l Feed link
    L Feed RSS URL
    n "unread" flag field
    S download status
    t Feed title
    T First tag of a feed in the URLs file
    u "unread/total" field
    U "unread" field
    c "total" field

    While a reload-all operation is running, the download status indicates the download status of a feed, which can be "to be downloaded" (indicated by "_"), "currently downloading" (indicated by "."), successfully downloaded (indicated by " ") and "download error" (indicated by "x").

    Table 7. Available Identifiers for articlelist-format

    Identifier Meaning
    a Article author
    D Publication date
    f Article flags
    i Article index
    t Article title
    T If the article list displays articles from different feeds, then this identifier contains the title of the feed to which the article belongs.
    L Article length

    Table 8. Available Identifiers for notify-format

    Identifier Meaning
    n Number of unread articles
    f Number of unread feeds
    d Number of new unread articles (i.e. that were added through the last reload)
    D Number of new unread feeds (i.e. that were added through the last reload)

    Examples:

    feedlist-format     "%4i %n %11u %t"
    articlelist-format  "%4i %f %D   %?T?|%-17T|  ?%t"
    notify-format       "%d new articles (%n unread articles, %f unread feeds)"

    Dialog Titles

    Starting with newsbeuter 2.0, it is now officially supported to customize the title format of all available dialogs. Here is a list of dialogs with their respective title format configuration variables, and a list of available formats and their meaning. Please note taht the title formats are localized, so if you work on a different locale that is supported by newsbeuter, the actually displayed title text may vary unless you customize it.

    Table 9. Dialog Title Formats

    Dialog Configuration Variable Default Value
    Feed List feedlist-title-format %N %V - Your feeds (%u unread, %t total)%?T? - tag ‘%T’&?
    Article List articlelist-title-format %N %V - Articles in feed %T (%u unread, %t total) - %U
    Search Result searchresult-title-format %N %V - Search result (%u unread, %t total)
    File Browser filebrowser-title-format %N %V - %?O?Open File&Save File? - %f
    Help help-title-format %N %V - Help
    Select Tag Dialog selecttag-title-format %N %V - Select Tag
    Select Filter Dialog selectfilter-title-format %N %V - Select Filter
    Article View itemview-title-format %N %V - Article %T (%u unread, %t total)
    URL View urlview-title-format %N %V - URLs
    Dialog List dialogs-title-format %N %V - Dialogs

    Table 10. Common Title Format Identifiers

    Identifier Meaning
    N Name of the program, i.e. "newsbeuter"
    V Program version
    u Number of unread articles (if applicable)
    t Number of total articles (if applicable)

    Table 11. Feed List Title Format Identifiers

    Identifier Meaning
    T Currently selected tag (empty if none selected)

    Table 12. Article List Title Format Identifiers

    Identifier Meaning
    T Feed title
    U Feed URL

    Table 13. File Browser Title Format Identifiers

    Identifier Meaning
    f Filename
    O Non-empty if file browser is in open mode, empty if in save mode

    Table 14. Article View Title Format Identifiers

    Identifier Meaning
    T Article title

    4.16. Highlighting Text

    Since version 1.0, newsbeuter supports the highlighting of text in the feed list, the article list and the article view, using regular expressions to describe patterns to be highlighted. The command syntax goes like this:

    highlight <target> <regex> <fgcolor> [<bgcolor> [<attribute> ...]]

    Valid values for <target> are "feedlist", "articlelist", "article" and "all". When specifying "all", the matching will be done in all three views. The <regex> must be regular expression, which will be matched case-insensitive against the text. <fgcolor> and <bgcolor> specify the foreground color resp. the background color of the matches. You can also specify 0 or more attributes. You can find a list of valid colors and attributes in the "Configuring Colors" section.

    Examples for possible highlighting configurations are:

    highlight all "newsbeuter" red
    highlight article "^(Feed|Title|Author|Link|Date):" default default underline
    highlight feedlist "https?://[^ ]+" yellow red bold

    Highlighting Articles in the Article List

    In addition to generally highlighting text, there is also a specific way to highlight articles in the article list based on whether they match a certain filter expression. This means that you can highlight items in the article list based on their content. This is done using the "highlight-article" configuration command.

    The syntax is similar to the "highlight" configuration command, with the difference that there’s no need to specify a target (since it only applies in the article list), and instead of a regular expression, a filter expression is used. After the filter expression, the colors and attributes are specified in the same way.

    Example:

    highlight-article "author =~ \"Andreas Krennmair\"" white red bold

    4.17. Advanced Dialog Management

    Since version 2.0, newsbeuter supports an advanced concept of dialogs. Previously, all dialogs (feed list, article list, article view) were internally laid out as a pure stack. In 2.0, this changed: all dialogs are managed in a list, and the user can jump to another, previously opened dialog from everywhere. This allows a user to open more than one article list, more than one article view, etc., and switch between them without closing them.

    The main dialog for this feature can be reached by pressing the "v" key. This opens the list of open dialogs. From there, the user can switch to another dialog by selecting the appropriate entry and pressing "ENTER", or can close open dialogs by selecting them and pressing Ctrl-X.

    4.18. XDG Base Directory Support

    Newsbeuter implements limited support for the XDG Base Directory Specification. It needs to be set up manually by creating the following directories:

    ~/.local/share/newsbeuter/
    ~/.config/newsbeuter/

    If these directories exist or the environment variables $XDG_CONFIG_HOME and $XDG_DATA_HOME are set, newsbeuter will use these directories, otherwise it will default to ~/.newsbeuter as its configuration directory.

    4.19. Podcast Support

    A podcast is a media file distributed over the internet using syndication feeds such as RSS, for later playback on portable players or computers. Newsbeuter contains support for downloading and saving podcasts. This support differs a bit from other podcast aggregators or "podcatchers" in how it is done.

    Podcast content is transported in RSS feeds via special tags called "enclosures". Newsbeuter recognizes these enclosures and stores the relevant information for every podcast item it finds in an RSS feed. Since version 2.0, it also recognizes and handles the Yahoo Media RSS extensions. What the user then can do is to add the podcast download URL to a download queue. Alternatively, newsbeuter can be configured to automatically do that. This queue is stored in the file $HOME/.newsbeuter/queue.

    The user can then use the download manager "podbeuter" to download these files to a directory on the local filesystem. Podbeuter comes with the newsbeuter package, and features a look and feel very close to the one of newsbeuter. It also shares the same configuration file.

    Podcasts that have been downloaded but haven’t been played yet remain in the queue but are marked as downloaded. You can remove them by purging them from the queue with the P key. After you’ve played a file and close podbeuter, it will be removed from the queue. The downloaded file remains on the filesystem.

    Table 15. Podbeuter Configuration Commands

    Configuration Command Argument(s) Default Description Example
    download-path <path> ~/ Specifies the directory where podbeuter shall download the files to. Optionally, the placeholders "%n" (for the podcast feed’s name) and "%h" (for the podcast feed’s hostname) can be used to place downloads in a directory structure. download-path "~/Downloads/%h/%n"
    max-downloads <number> 1 Specifies the maximum number of parallel downloads when automatic download is enabled. max-downloads 3
    player <player command> "" Specifies the player that shall be used for playback of downloaded files. player "mp3blaster"

    Table 16. Available Operations in Podbeuter

    Operation Default key Description
    quit q Quit the program.
    pb-download d Download the currently selected URL.
    pb-cancel c Cancel the currently selected download.
    pb-play p Start player with currently selected download.
    pb-delete D Delete the currently selected URL from the queue.
    pb-purge P Remove all finished and deleted downloads from the queue and load URLs that were newly added to the queue.
    pb-toggle-download-all a Toggle the "automatic download" feature where all queued URLs are downloaded one after the other. The "max-downloads" configuration option controls how many downloads are done in parallel.
    pb-increase-max-dls + Increase the "max-downloads" option by 1.
    pb-decrease-max-dls - Decrease the "max-downloads" option by 1. If the option is already 1, no further decrease is possible.

    A usual "use case" is to configure newsbeuter to automatically enqueue newly found podcast download URLs. Then, the user reloads the podcast RSS feeds in newsbeuter, and after that, he/she uses podbeuter to view the current queue, and either selectively download certain files or automatically download them all together by pressing "a" within podbeuter.

    4.20. Using SQLite Triggers with newsbeuter

    This section was kindly provided by Elrond.

    SQLite, the db used by newsbeuter, supports triggers. These are small snippets of SQL that get executed inside the database by the database engine. They’re stored inside the db and the normal user (including newsbeuter itself) doesn’t see them. Just the db seems to do some magic: Like changing some values when you change another value.

    So what is this good for when looking at newsbeuter? Well first of it’s a hack. The real answer should be to use application logic (do it inside newsbeuter, not in the db). So: Don’t use this, unless you know, what you’re doing, and unless you have some sort of backup.

    Example

    So after the "don’t use it" you still want to know, what one can do? So here’s an example.

    Suppose you have a strange feed where the articles become "new" by just changing their subject, and nothing else changes. The body is just empty, and the URL keeps the same. This feed really exists. It’s the "updated software rss feed" of some major company and the title just contains the name of the driver and version number. And the URL points to the download page. newsbeuter considers articles only as new, when they have a new UniqueID (this is good). So those articles are never marked as new (unread) ever again.

    So what can we do? We do some magic: We let the db test if newsbeuter changes the subject and then let itself mark the article again as unread.

    1. You need the sqlite3 command line tool (available via apt-get install sqlite3 on Debian) or some other tool to do direct sql on the sqlite database.
    2. Start sqlite3 with the newsbeuter db:

      Rivendell:~/.newsbeuter% sqlite3 cache.db
      SQLite version 3.4.2
      Enter ".help" for instructions
      sqlite>
    3. Create the trigger:

      sqlite> create trigger update_item_title update of title on rss_item
                > for each row when old.title != new.title
                > begin
                >   update rss_item set unread = 1 where rowid == new.rowid;
                > end;
    4. Leave sqlite3 with <Ctrl-D> or .quit.

    That’s it. newsbeuter (well, its db) now marks articles as unread when their title changes. And nicely enough this works all inside newsbeuter, no need to restart it so that it rereads the cache, that magically modifies itself. It just works.

    5. Feedback

    If you want to tell us something related to newsbeuter, don’t hesitate to send an email: ak@newsbeuter.org

    Alternatively, you can reach the newsbeuter developers on IRC: channel #newsbeuter on irc.freenode.net.

    If you want to report newsbeuter bugs, please use this issue tracker: http://code.google.com/p/newsbeuter/issues/list

    6. License

    MIT/X Consortium License

    ©opyright 2006-2011 Andreas Krennmair <ak@newsbeuter.org>

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

    newsbeuter-2.7/filter/000077500000000000000000000000001220711462700150345ustar00rootroot00000000000000newsbeuter-2.7/filter/FilterParser.cpp000066400000000000000000000055021220711462700201440ustar00rootroot00000000000000#include "logger.h" #include "FilterParser.h" #include "Parser.h" #include using namespace newsbeuter; FilterParser::FilterParser() : root(0), curpos(0), next_must_descend_right(false) { } FilterParser::~FilterParser() { cleanup(); } FilterParser::FilterParser(const FilterParser& p) { LOG(LOG_DEBUG,"FilterParser: copy constructor called!"); parse_string(p.strexpr); } FilterParser& FilterParser::operator=(FilterParser& p) { LOG(LOG_DEBUG,"FilterParser: operator= called!"); if (this != &p) { cleanup(); parse_string(p.strexpr); } return *this; } void FilterParser::add_logop(int op) { //fprintf(stderr,"add_logop: op = %d\n", op); expression * expr = new expression(op); if (!root) { printf("error: there can't be a logical expression w/o a prior expression!"); // TODO: add proper error handling } else { if (curpos != root) { expr->l = curpos; curpos->parent->r = expr; expr->parent = curpos->parent; curpos = expr; } else { expr->l = root; curpos = root = expr; } } // printf("logop: %d\n", op); } void FilterParser::add_matchexpr(char * name, int op, char * lit) { //fprintf(stderr,"add_matchexpr: name = %s op = %d lit = %s\n", name, op, lit); expression * expr = new expression(name, lit, op); if (next_must_descend_right) { next_must_descend_right = false; if (!curpos) { curpos = root = expr; } else { expr->parent = curpos; curpos->r = expr; curpos = expr; } } else { if (!curpos) { curpos = root = expr; } else { expr->parent = curpos; curpos->r = expr; } } coco_string_delete(name); coco_string_delete(lit); // printf("matchexpr: %ls lit = %ls op = %d\n", name, lit, op); } void FilterParser::open_block() { //fprintf(stderr,"open_block\n"); next_must_descend_right = true; } void FilterParser::close_block() { //fprintf(stderr,"close_block\n"); if (curpos != root) { curpos = curpos->parent; } } bool FilterParser::parse_string(const std::string& str) { cleanup(); strexpr = str; std::istringstream is(str); Scanner s(is); Parser p(&s); p.gen = this; p.Parse(); if (0 == p.errors->count) { return true; } errmsg = p.errors->errors[0]; cleanup(); return false; } void FilterParser::cleanup() { cleanup_r(root); root = curpos = NULL; } void FilterParser::cleanup_r(expression * e) { if (e) { LOG(LOG_DEBUG,"cleanup_r: e = %p", e); cleanup_r(e->l); cleanup_r(e->r); delete e; } } expression::expression(const std::string& n, const std::string& lit, int o) : name(n), literal(lit), op(o), l(NULL), r(NULL), parent(NULL), regex(NULL) { if (literal[0] == '"' && literal[literal.length()-1] == '"') { literal = literal.substr(1,literal.length()-2); } } expression::expression(int o) : op(o), l(NULL), r(NULL), parent(NULL), regex(NULL) { } expression::~expression() { if (regex) regfree(regex); delete regex; } newsbeuter-2.7/filter/FilterParser.h000066400000000000000000000023521220711462700176110ustar00rootroot00000000000000#ifndef FILTER_PARSER__H #define FILTER_PARSER__H #include #include #include enum { LOGOP_INVALID = 0, LOGOP_AND = 1, LOGOP_OR, MATCHOP_EQ, MATCHOP_NE, MATCHOP_RXEQ, MATCHOP_RXNE, MATCHOP_LT, MATCHOP_GT, MATCHOP_LE, MATCHOP_GE, MATCHOP_CONTAINS, MATCHOP_CONTAINSNOT, MATCHOP_BETWEEN }; struct expression { expression(const std::string& n, const std::string& lit, int o); expression(int o = LOGOP_INVALID); ~expression(); std::string name; std::string literal; int op; expression * l, * r; expression * parent; regex_t * regex; }; class FilterParser { public: FilterParser(); FilterParser(const FilterParser& p); ~FilterParser(); void add_logop(int op); void add_matchexpr(char * name, int op, char * lit); void open_block(); void close_block(); bool parse_string(const std::string& str); void cleanup(); inline expression * get_root() { return root; } FilterParser& operator=(FilterParser& p); const std::wstring& get_error() { return errmsg; } private: void print_tree_r(expression * e, unsigned int depth); void cleanup_r(expression * e); expression * root; expression * curpos; bool next_must_descend_right; std::string strexpr; std::wstring errmsg; }; #endif newsbeuter-2.7/filter/Parser.cpp000066400000000000000000000131651220711462700170020ustar00rootroot00000000000000 #include #include "Parser.h" #include "Scanner.h" void Parser::SynErr(int n) { if (errDist >= minErrDist) errors->SynErr(n); errDist = 0; } void Parser::SemErr(wchar_t* msg) { msg = msg; if (errDist >= minErrDist) errors->Error(); errDist = 0; } void Parser::Get() { for (;;) { t = la; la = scanner->Scan(); if (la->kind <= maxT) { ++errDist; break; } if (dummyToken != t) { dummyToken->kind = t->kind; dummyToken->pos = t->pos; dummyToken->col = t->col; dummyToken->line = t->line; dummyToken->next = NULL; coco_string_delete(dummyToken->val); dummyToken->val = coco_string_create(t->val); t = dummyToken; } la = t; } } void Parser::Expect(int n) { if (la->kind==n) Get(); else { SynErr(n); } } void Parser::ExpectWeak(int n, int follow) { if (la->kind == n) Get(); else { SynErr(n); while (!StartOf(follow)) Get(); } } bool Parser::WeakSeparator(int n, int syFol, int repFol) { if (la->kind == n) {Get(); return true;} else if (StartOf(repFol)) {return false;} else { SynErr(n); while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) { Get(); } return StartOf(syFol); } } void Parser::stringlit(char* &lit) { if (la->kind == 4) { Get(); } else if (la->kind == 5) { Get(); } else if (la->kind == 6) { Get(); } else SynErr(22); lit = coco_string_create_char(t->val); } void Parser::matchattrib(char* &name) { Expect(3); name = coco_string_create_char(t->val); } void Parser::matchop(int &op) { switch (la->kind) { case 7: { Get(); op = MATCHOP_EQ; break; } case 8: { Get(); op = MATCHOP_EQ; break; } case 9: { Get(); op = MATCHOP_NE; break; } case 10: { Get(); op = MATCHOP_RXEQ; break; } case 11: { Get(); op = MATCHOP_RXNE; break; } case 12: { Get(); op = MATCHOP_LT; break; } case 13: { Get(); op = MATCHOP_GT; break; } case 14: { Get(); op = MATCHOP_LE; break; } case 15: { Get(); op = MATCHOP_GE; break; } case 16: { Get(); op = MATCHOP_CONTAINS; break; } case 17: { Get(); op = MATCHOP_CONTAINSNOT; break; } case 18: { Get(); op = MATCHOP_BETWEEN; break; } default: SynErr(23); break; } } void Parser::logop(int &lop) { if (la->kind == 19) { Get(); lop = LOGOP_AND; } else if (la->kind == 20) { Get(); lop = LOGOP_OR; } else SynErr(24); } void Parser::matchexpr() { char * name, * lit; int op; matchattrib(name); matchop(op); stringlit(lit); gen->add_matchexpr(name, op, lit); } void Parser::blockexpr() { Expect(1); gen->open_block(); expr(); Expect(2); gen->close_block(); } void Parser::expr() { int lop; if (la->kind == 3) { matchexpr(); } else if (la->kind == 1) { blockexpr(); } else SynErr(25); while (la->kind == 19 || la->kind == 20) { logop(lop); gen->add_logop(lop); if (la->kind == 3) { matchexpr(); } else if (la->kind == 1) { blockexpr(); } else SynErr(26); } } void Parser::Filter() { expr(); } void Parser::Parse() { t = NULL; la = dummyToken = new Token(); la->val = coco_string_create(L"Dummy Token"); Get(); Filter(); Expect(0); } Parser::Parser(Scanner *scanner) { maxT = 21; minErrDist = 2; errDist = minErrDist; this->scanner = scanner; errors = new Errors(); } bool Parser::StartOf(int s) { const bool T = true; const bool x = false; static bool set[1][23] = { {T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x} }; return set[s][la->kind]; } Parser::~Parser() { delete errors; delete dummyToken; } Errors::Errors() { count = 0; } void Errors::SynErr(int n) { wchar_t* s; switch (n) { case 0: s = coco_string_create(L"EOF expected"); break; case 1: s = coco_string_create(L"openblock expected"); break; case 2: s = coco_string_create(L"closeblock expected"); break; case 3: s = coco_string_create(L"ident expected"); break; case 4: s = coco_string_create(L"stringliteral expected"); break; case 5: s = coco_string_create(L"numliteral expected"); break; case 6: s = coco_string_create(L"rangeliteral expected"); break; case 7: s = coco_string_create(L"\"==\" expected"); break; case 8: s = coco_string_create(L"\"=\" expected"); break; case 9: s = coco_string_create(L"\"!=\" expected"); break; case 10: s = coco_string_create(L"\"=~\" expected"); break; case 11: s = coco_string_create(L"\"!~\" expected"); break; case 12: s = coco_string_create(L"\"<\" expected"); break; case 13: s = coco_string_create(L"\">\" expected"); break; case 14: s = coco_string_create(L"\"<=\" expected"); break; case 15: s = coco_string_create(L"\">=\" expected"); break; case 16: s = coco_string_create(L"\"#\" expected"); break; case 17: s = coco_string_create(L"\"!#\" expected"); break; case 18: s = coco_string_create(L"\"between\" expected"); break; case 19: s = coco_string_create(L"\"and\" expected"); break; case 20: s = coco_string_create(L"\"or\" expected"); break; case 21: s = coco_string_create(L"??? expected"); break; case 22: s = coco_string_create(L"invalid stringlit"); break; case 23: s = coco_string_create(L"invalid matchop"); break; case 24: s = coco_string_create(L"invalid logop"); break; case 25: s = coco_string_create(L"invalid expr"); break; case 26: s = coco_string_create(L"invalid expr"); break; default: { wchar_t format[20]; coco_swprintf(format, 20, L"error %d", n); s = coco_string_create(format); } break; } errors.push_back(std::wstring(s)); coco_string_delete(s); count++; } void Errors::Error() { count++; } void Errors::Warning() { } void Errors::Exception() { } newsbeuter-2.7/filter/Parser.frame000066400000000000000000000131241220711462700173050ustar00rootroot00000000000000/*------------------------------------------------------------------------- Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported to C++ by Csaba Balazs, University of Szeged with improvements by Pat Terry, Rhodes University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 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. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. -------------------------------------------------------------------------*/ -->begin #if !defined(COCO_PARSER_H__) #define COCO_PARSER_H__ #include #include -->headerdef #include "Scanner.h" -->namespace_open class Errors { public: int count; // number of errors detected std::vector errors; Errors(); void SynErr(int n); void Error(); void Warning(); void Exception(); }; // Errors class Parser { private: -->constantsheader Token *dummyToken; int errDist; int minErrDist; void SynErr(int n); void Get(); void Expect(int n); bool StartOf(int s); void ExpectWeak(int n, int follow); bool WeakSeparator(int n, int syFol, int repFol); public: Scanner *scanner; Errors *errors; Token *t; // last recognized token Token *la; // lookahead token -->declarations Parser(Scanner *scanner); ~Parser(); void SemErr(wchar_t* msg); -->productionsheader void Parse(); }; // end Parser -->namespace_close #endif // !defined(COCO_PARSER_H__) -->implementation /*---------------------------------------------------------------------- Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported to C++ by Csaba Balazs, University of Szeged with improvements by Pat Terry, Rhodes University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 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. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. -----------------------------------------------------------------------*/ -->begin #include #include "Parser.h" #include "Scanner.h" -->namespace_open void Parser::SynErr(int n) { if (errDist >= minErrDist) errors->SynErr(n); errDist = 0; } void Parser::SemErr(wchar_t* msg) { msg = msg; if (errDist >= minErrDist) errors->Error(); errDist = 0; } void Parser::Get() { for (;;) { t = la; la = scanner->Scan(); if (la->kind <= maxT) { ++errDist; break; } -->pragmas if (dummyToken != t) { dummyToken->kind = t->kind; dummyToken->pos = t->pos; dummyToken->col = t->col; dummyToken->line = t->line; dummyToken->next = NULL; coco_string_delete(dummyToken->val); dummyToken->val = coco_string_create(t->val); t = dummyToken; } la = t; } } void Parser::Expect(int n) { if (la->kind==n) Get(); else { SynErr(n); } } void Parser::ExpectWeak(int n, int follow) { if (la->kind == n) Get(); else { SynErr(n); while (!StartOf(follow)) Get(); } } bool Parser::WeakSeparator(int n, int syFol, int repFol) { if (la->kind == n) {Get(); return true;} else if (StartOf(repFol)) {return false;} else { SynErr(n); while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) { Get(); } return StartOf(syFol); } } -->productions void Parser::Parse() { t = NULL; la = dummyToken = new Token(); la->val = coco_string_create(L"Dummy Token"); Get(); -->parseRoot Expect(0); } Parser::Parser(Scanner *scanner) { -->constants minErrDist = 2; errDist = minErrDist; this->scanner = scanner; errors = new Errors(); } bool Parser::StartOf(int s) { const bool T = true; const bool x = false; -->initialization return set[s][la->kind]; } Parser::~Parser() { delete errors; delete dummyToken; } Errors::Errors() { count = 0; } void Errors::SynErr(int n) { wchar_t* s; switch (n) { -->errors default: { wchar_t format[20]; coco_swprintf(format, 20, L"error %d", n); s = coco_string_create(format); } break; } errors.push_back(std::wstring(s)); coco_string_delete(s); count++; } void Errors::Error() { count++; } void Errors::Warning() { } void Errors::Exception() { } -->namespace_close $$$ newsbeuter-2.7/filter/Parser.h000066400000000000000000000022361220711462700164440ustar00rootroot00000000000000 #if !defined(COCO_PARSER_H__) #define COCO_PARSER_H__ #include #include #include "FilterParser.h" #include "Scanner.h" class Errors { public: int count; // number of errors detected std::vector errors; Errors(); void SynErr(int n); void Error(); void Warning(); void Exception(); }; // Errors class Parser { private: enum { _EOF=0, _openblock=1, _closeblock=2, _ident=3, _stringliteral=4, _numliteral=5, _rangeliteral=6, }; int maxT; Token *dummyToken; int errDist; int minErrDist; void SynErr(int n); void Get(); void Expect(int n); bool StartOf(int s); void ExpectWeak(int n, int follow); bool WeakSeparator(int n, int syFol, int repFol); public: Scanner *scanner; Errors *errors; Token *t; // last recognized token Token *la; // lookahead token FilterParser * gen; Parser(Scanner *scanner); ~Parser(); void SemErr(wchar_t* msg); void stringlit(char* &lit); void matchattrib(char* &name); void matchop(int &op); void logop(int &lop); void matchexpr(); void blockexpr(); void expr(); void Filter(); void Parse(); }; // end Parser #endif // !defined(COCO_PARSER_H__) newsbeuter-2.7/filter/Scanner.cpp000066400000000000000000000331261220711462700171360ustar00rootroot00000000000000 #include #include #include "Scanner.h" // string handling, wide character wchar_t* coco_string_create(const wchar_t* value) { wchar_t* data; int len = 0; if (value) { len = wcslen(value); } data = new wchar_t[len + 1]; wcsncpy(data, value, len); data[len] = 0; return data; } wchar_t* coco_string_create(const wchar_t *value , int startIndex, int length) { int len = 0; wchar_t* data; if (value) { len = length; } data = new wchar_t[len + 1]; wcsncpy(data, &(value[startIndex]), len); data[len] = 0; return data; } wchar_t* coco_string_create_upper(wchar_t* data) { if (!data) { return NULL; } int dataLen = 0; if (data) { dataLen = wcslen(data); } wchar_t *newData = new wchar_t[dataLen + 1]; for (int i = 0; i <= dataLen; i++) { if ((L'a' <= data[i]) && (data[i] <= L'z')) { newData[i] = data[i] + (L'A' - L'a'); } else { newData[i] = data[i]; } } newData[dataLen] = L'\0'; return newData; } wchar_t* coco_string_create_lower(wchar_t* data) { if (!data) { return NULL; } int dataLen = 0; if (data) { dataLen = wcslen(data); } wchar_t* newData = new wchar_t[dataLen + 1]; for (int i = 0; i <= dataLen; i++) { if ((L'A' <= data[i]) && (data[i] <= L'Z')) { newData[i] = data[i] - (L'A'- L'a'); } else { newData[i] = data[i]; } } newData[dataLen] = L'\0'; return newData; } wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2) { wchar_t* data; int data1Len = 0; int data2Len = 0; if (data1) { data1Len = wcslen(data1); } if (data2) {data2Len = wcslen(data2); } data = new wchar_t[data1Len + data2Len + 1]; if (data1) { wcscpy(data, data1); } if (data2) { wcscpy(data + data1Len, data2); } data[data1Len + data2Len] = 0; return data; } wchar_t* coco_string_create_append(const wchar_t *target, const wchar_t appendix) { int targetLen = coco_string_length(target); wchar_t* data = new wchar_t[targetLen + 2]; wcsncpy(data, target, targetLen); data[targetLen] = appendix; data[targetLen + 1] = 0; return data; } void coco_string_delete(wchar_t* &data) { delete [] data; data = NULL; } int coco_string_length(const wchar_t* data) { if (data) { return wcslen(data); } return 0; } bool coco_string_endswith(wchar_t* data, wchar_t *end) { int dataLen = wcslen(data); int endLen = wcslen(end); return (endLen <= dataLen) && (wcscmp(data + dataLen - endLen, end) == 0); } int coco_string_indexof(wchar_t* data, wchar_t value) { wchar_t* chr = wcschr(data, value); if (chr) { return (chr-data); } return -1; } int coco_string_lastindexof(wchar_t* data, wchar_t value) { wchar_t* chr = wcsrchr(data, value); if (chr) { return (chr-data); } return -1; } void coco_string_merge(wchar_t* &target, wchar_t* appendix) { if (!appendix) { return; } wchar_t* data = coco_string_create_append(target, appendix); delete [] target; target = data; } bool coco_string_equal(wchar_t* data1, wchar_t* data2) { return wcscmp( data1, data2 ) == 0; } int coco_string_compareto(wchar_t* data1, wchar_t* data2) { return wcscmp(data1, data2); } int coco_string_hash(const wchar_t *data) { int h = 0; if (!data) { return 0; } while (*data != 0) { h = (h * 7) ^ *data; ++data; } if (h < 0) { h = -h; } return h; } // string handling, ascii character wchar_t* coco_string_create(const char* value) { int len = 0; if (value) { len = strlen(value); } wchar_t* data = new wchar_t[len + 1]; for (int i = 0; i < len; ++i) { data[i] = (wchar_t) value[i]; } data[len] = 0; return data; } char* coco_string_create_char(const wchar_t *value) { int len = coco_string_length(value); char *res = new char[len + 1]; for (int i = 0; i < len; ++i) { res[i] = (char) value[i]; } res[len] = 0; return res; } void coco_string_delete(char* &data) { delete [] data; data = NULL; } Token::Token() { kind = 0; pos = 0; col = 0; line = 0; val = NULL; next = NULL; } Token::~Token() { coco_string_delete(val); } Buffer::Buffer(std::istream* s, bool isUserStream) { stream = s; this->isUserStream = isUserStream; s->seekg(0, std::ios_base::end); fileLen = bufLen = s->tellg(); s->seekg(0, std::ios_base::beg); buf = new char[MAX_BUFFER_LENGTH]; bufStart = INT_MAX; // nothing in the buffer so far SetPos(0); // setup buffer to position 0 (start) if (bufLen == fileLen) Close(); } Buffer::Buffer(Buffer *b) { buf = b->buf; b->buf = NULL; bufStart = b->bufStart; bufLen = b->bufLen; fileLen = b->fileLen; pos = b->pos; stream = b->stream; b->stream = NULL; isUserStream = b->isUserStream; } Buffer::~Buffer() { Close(); if (buf != NULL) { delete [] buf; buf = NULL; } } void Buffer::Close() { if (!isUserStream && stream != NULL) { std::ifstream * ifs = dynamic_cast(stream); if (ifs) { ifs->close(); delete ifs; } stream = NULL; } } int Buffer::Read() { if (pos < bufLen) { return buf[pos++]; } else if (GetPos() < fileLen) { SetPos(GetPos()); // shift buffer start to Pos return buf[pos++]; } else { return EoF; } } int Buffer::Peek() { int curPos = GetPos(); int ch = Read(); SetPos(curPos); return ch; } char* Buffer::GetString(int beg, int end) { int len = end - beg; char *buf = new char[len]; int oldPos = GetPos(); SetPos(beg); for (int i = 0; i < len; ++i) buf[i] = (char) Read(); SetPos(oldPos); return buf; } int Buffer::GetPos() { return pos + bufStart; } void Buffer::SetPos(int value) { if (value < 0) value = 0; else if (value > fileLen) value = fileLen; if (value >= bufStart && value < bufStart + bufLen) { // already in buffer pos = value - bufStart; } else if (stream != NULL) { // must be swapped in stream->seekg(0, std::ios_base::beg); stream->get(buf, MAX_BUFFER_LENGTH); bufLen = stream->gcount(); bufStart = value; pos = 0; } else { pos = fileLen - bufStart; // make Pos return fileLen } } int UTF8Buffer::Read() { int ch; do { ch = Buffer::Read(); // until we find a uft8 start (0xxxxxxx or 11xxxxxx) } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EOF)); if (ch < 128 || ch == EOF) { // nothing to do, first 127 chars are the same in ascii and utf8 // 0xxxxxxx or end of file character } else if ((ch & 0xF0) == 0xF0) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx int c1 = ch & 0x07; ch = Buffer::Read(); int c2 = ch & 0x3F; ch = Buffer::Read(); int c3 = ch & 0x3F; ch = Buffer::Read(); int c4 = ch & 0x3F; ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4; } else if ((ch & 0xE0) == 0xE0) { // 1110xxxx 10xxxxxx 10xxxxxx int c1 = ch & 0x0F; ch = Buffer::Read(); int c2 = ch & 0x3F; ch = Buffer::Read(); int c3 = ch & 0x3F; ch = (((c1 << 6) | c2) << 6) | c3; } else if ((ch & 0xC0) == 0xC0) { // 110xxxxx 10xxxxxx int c1 = ch & 0x1F; ch = Buffer::Read(); int c2 = ch & 0x3F; ch = (c1 << 6) | c2; } return ch; } Scanner::Scanner(const wchar_t* fileName) { char *chFileName = coco_string_create_char(fileName); std::ifstream* ifs = new std::ifstream(chFileName); if (!ifs || !ifs->is_open()) { wprintf(L"--- Cannot open file %ls\n", fileName); exit(1); } coco_string_delete(chFileName); buffer = new Buffer(ifs, false); Init(); } Scanner::Scanner(std::istream& s) { buffer = new Buffer(&s, true); Init(); } Scanner::~Scanner() { char* cur = (char*) firstHeap; while(cur != NULL) { cur = *(char**) (cur + HEAP_BLOCK_SIZE); free(firstHeap); firstHeap = cur; } delete [] tval; delete buffer; } void Scanner::Init() { EOL = '\n'; eofSym = 0; maxT = 21; noSym = 21; int i; for (i = 46; i <= 46; ++i) start.set(i, 3); for (i = 65; i <= 90; ++i) start.set(i, 3); for (i = 95; i <= 95; ++i) start.set(i, 3); for (i = 97; i <= 122; ++i) start.set(i, 3); for (i = 48; i <= 57; ++i) start.set(i, 9); start.set(40, 1); start.set(41, 2); start.set(34, 4); start.set(45, 10); start.set(61, 19); start.set(33, 20); start.set(60, 21); start.set(62, 22); start.set(35, 17); start.set(Buffer::EoF, -1); keywords.set(L"between", 18); keywords.set(L"and", 19); keywords.set(L"or", 20); tvalLength = 128; tval = new wchar_t[tvalLength]; // text of current token // HEAP_BLOCK_SIZE byte heap + pointer to next heap block heap = malloc(HEAP_BLOCK_SIZE + sizeof(void*)); firstHeap = heap; heapEnd = (void**) (((char*) heap) + HEAP_BLOCK_SIZE); *heapEnd = 0; heapTop = heap; if (sizeof(Token) > HEAP_BLOCK_SIZE) { wprintf(L"--- Too small HEAP_BLOCK_SIZE\n"); exit(1); } pos = -1; line = 1; col = 0; oldEols = 0; NextCh(); if (ch == 0xEF) { // check optional byte order mark for UTF-8 NextCh(); int ch1 = ch; NextCh(); int ch2 = ch; if (ch1 != 0xBB || ch2 != 0xBF) { wprintf(L"Illegal byte order mark at start of file"); exit(1); } Buffer *oldBuf = buffer; buffer = new UTF8Buffer(buffer); col = 0; delete oldBuf; oldBuf = NULL; NextCh(); } pt = tokens = CreateToken(); // first token is a dummy } void Scanner::NextCh() { if (oldEols > 0) { ch = EOL; oldEols--; } else { pos = buffer->GetPos(); ch = buffer->Read(); col++; // replace isolated '\r' by '\n' in order to make // eol handling uniform across Windows, Unix and Mac if (ch == L'\r' && buffer->Peek() != L'\n') ch = EOL; if (ch == EOL) { line++; col = 0; } } } void Scanner::AddCh() { if (tlen >= tvalLength) { tvalLength *= 2; wchar_t *newBuf = new wchar_t[tvalLength]; memcpy(newBuf, tval, tlen*sizeof(wchar_t)); delete tval; tval = newBuf; } tval[tlen++] = ch; NextCh(); } void Scanner::CreateHeapBlock() { void* newHeap; char* cur = (char*) firstHeap; while(((char*) tokens < cur) || ((char*) tokens > (cur + HEAP_BLOCK_SIZE))) { cur = *((char**) (cur + HEAP_BLOCK_SIZE)); free(firstHeap); firstHeap = cur; } // HEAP_BLOCK_SIZE byte heap + pointer to next heap block newHeap = malloc(HEAP_BLOCK_SIZE + sizeof(void*)); *heapEnd = newHeap; heapEnd = (void**) (((char*) newHeap) + HEAP_BLOCK_SIZE); *heapEnd = 0; heap = newHeap; heapTop = heap; } Token* Scanner::CreateToken() { Token *t; if (((char*) heapTop + (int) sizeof(Token)) >= (char*) heapEnd) { CreateHeapBlock(); } t = (Token*) heapTop; heapTop = (void*) ((char*) heapTop + sizeof(Token)); t->val = NULL; t->next = NULL; return t; } void Scanner::AppendVal(Token *t) { int reqMem = (tlen + 1) * sizeof(wchar_t); if (((char*) heapTop + reqMem) >= (char*) heapEnd) { if (reqMem > HEAP_BLOCK_SIZE) { wprintf(L"--- Too long token value\n"); exit(1); } CreateHeapBlock(); } t->val = (wchar_t*) heapTop; heapTop = (void*) ((char*) heapTop + reqMem); wcsncpy(t->val, tval, tlen); t->val[tlen] = L'\0'; } Token* Scanner::NextToken() { while (ch == ' ' || false ) NextCh(); t = CreateToken(); t->pos = pos; t->col = col; t->line = line; int state = start.state(ch); tlen = 0; AddCh(); switch (state) { case -1: { t->kind = eofSym; break; } // NextCh already done case 0: { t->kind = noSym; break; } // NextCh already done case 1: {t->kind = 1; break;} case 2: {t->kind = 2; break;} case 3: case_3: if ((ch >= L'-' && ch <= L'.') || (ch >= L'A' && ch <= L'Z') || ch == L'_' || (ch >= L'a' && ch <= L'z')) {AddCh(); goto case_3;} else {t->kind = 3; wchar_t *literal = coco_string_create(tval, 0, tlen); t->kind = keywords.get(literal, t->kind); coco_string_delete(literal); break;} case 4: case_4: if (ch <= L'!' || (ch >= L'#' && ch <= 65535)) {AddCh(); goto case_4;} else if (ch == L'"') {AddCh(); goto case_5;} else {t->kind = noSym; break;} case 5: case_5: {t->kind = 4; break;} case 6: case_6: if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_6;} else {t->kind = 5; break;} case 7: case_7: if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_8;} else {t->kind = noSym; break;} case 8: case_8: if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_8;} else {t->kind = 6; break;} case 9: case_9: if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_9;} else if (ch == L':') {AddCh(); goto case_7;} else {t->kind = 5; break;} case 10: if ((ch >= L'-' && ch <= L'.') || (ch >= L'A' && ch <= L'Z') || ch == L'_' || (ch >= L'a' && ch <= L'z')) {AddCh(); goto case_3;} else if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_6;} else {t->kind = 3; wchar_t *literal = coco_string_create(tval, 0, tlen); t->kind = keywords.get(literal, t->kind); coco_string_delete(literal); break;} case 11: case_11: {t->kind = 7; break;} case 12: case_12: {t->kind = 9; break;} case 13: case_13: {t->kind = 10; break;} case 14: case_14: {t->kind = 11; break;} case 15: case_15: {t->kind = 14; break;} case 16: case_16: {t->kind = 15; break;} case 17: {t->kind = 16; break;} case 18: case_18: {t->kind = 17; break;} case 19: if (ch == L'=') {AddCh(); goto case_11;} else if (ch == L'~') {AddCh(); goto case_13;} else {t->kind = 8; break;} case 20: if (ch == L'=') {AddCh(); goto case_12;} else if (ch == L'~') {AddCh(); goto case_14;} else if (ch == L'#') {AddCh(); goto case_18;} else {t->kind = noSym; break;} case 21: if (ch == L'=') {AddCh(); goto case_15;} else {t->kind = 12; break;} case 22: if (ch == L'=') {AddCh(); goto case_16;} else {t->kind = 13; break;} } AppendVal(t); return t; } // get the next token (possibly a token already seen during peeking) Token* Scanner::Scan() { if (tokens->next == NULL) { return pt = tokens = NextToken(); } else { pt = tokens = tokens->next; return tokens; } } // peek for the next token, ignore pragmas Token* Scanner::Peek() { if (pt->next == NULL) { do { pt = pt->next = NextToken(); } while (pt->kind > maxT); // skip pragmas } else { do { pt = pt->next; } while (pt->kind > maxT); } return pt; } // make sure that peeking starts at the current scan position void Scanner::ResetPeek() { pt = tokens; } newsbeuter-2.7/filter/Scanner.frame000066400000000000000000000466231220711462700174540ustar00rootroot00000000000000/*---------------------------------------------------------------------- Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported to C++ by Csaba Balazs, University of Szeged with improvements by Pat Terry, Rhodes University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 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. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. -----------------------------------------------------------------------*/ -->begin #if !defined(COCO_SCANNER_H__) #define COCO_SCANNER_H__ #include #include #include #include #include #if _MSC_VER >= 1400 #define coco_swprintf swprintf_s #elif _MSC_VER >= 1300 #define coco_swprintf _snwprintf #elif defined __GNUC__ #define coco_swprintf swprintf #else #error unknown compiler! #endif #include #include #define COCO_WCHAR_MAX 65535 #define MAX_BUFFER_LENGTH (64*1024) #define HEAP_BLOCK_SIZE (64*1024) // string handling, wide character wchar_t* coco_string_create(const wchar_t *value); wchar_t* coco_string_create(const wchar_t *value , int startIndex, int length); wchar_t* coco_string_create_upper(wchar_t* data); wchar_t* coco_string_create_lower(wchar_t* data); wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2); wchar_t* coco_string_create_append(const wchar_t* data, const wchar_t value); void coco_string_delete(wchar_t* &data); int coco_string_length(const wchar_t* data); bool coco_string_endswith(wchar_t* data, wchar_t *value); int coco_string_indexof(wchar_t* data, wchar_t value); int coco_string_lastindexof(wchar_t* data, wchar_t value); void coco_string_merge(wchar_t* &data, wchar_t* value); bool coco_string_equal(wchar_t* data1, wchar_t* data2); int coco_string_compareto(wchar_t* data1, wchar_t* data2); int coco_string_hash(const wchar_t* data); // string handling, ascii character wchar_t* coco_string_create(const char *value); char* coco_string_create_char(const wchar_t *value); void coco_string_delete(char* &data); -->namespace_open class Token { public: int kind; // token kind int pos; // token position in the source text (starting at 0) int col; // token column (starting at 1) int line; // token line (starting at 1) wchar_t* val; // token value Token *next; // ML 2005-03-11 Peek tokens are kept in linked list Token(); ~Token(); }; class Buffer { private: char *buf; // input buffer int bufStart; // position of first byte in buffer relative to input stream int bufLen; // length of buffer int fileLen; // length of input stream int pos; // current position in buffer std::istream* stream; // input stream (seekable) bool isUserStream; // was the stream opened by the user? public: static const int EoF = COCO_WCHAR_MAX + 1; Buffer(std::istream* s, bool isUserStream); Buffer(Buffer *b); virtual ~Buffer(); virtual void Close(); virtual int Read(); virtual int Peek(); virtual char* GetString(int beg, int end); virtual int GetPos(); virtual void SetPos(int value); }; class UTF8Buffer : public Buffer { public: UTF8Buffer(Buffer *b) : Buffer(b) {}; virtual int Read(); }; //----------------------------------------------------------------------------------- // StartStates -- maps charactes to start states of tokens //----------------------------------------------------------------------------------- class StartStates { private: class Elem { public: int key, val; Elem *next; Elem(int key, int val) { this->key = key; this->val = val; next = NULL; } }; Elem **tab; public: StartStates() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); } virtual ~StartStates() { for (int i = 0; i < 128; ++i) { Elem *e = tab[i]; while (e != NULL) { Elem *next = e->next; delete e; e = next; } } delete [] tab; } void set(int key, int val) { Elem *e = new Elem(key, val); int k = key % 128; e->next = tab[k]; tab[k] = e; } int state(int key) { Elem *e = tab[key % 128]; while (e != NULL && e->key != key) e = e->next; return e == NULL ? 0 : e->val; } }; //------------------------------------------------------------------------------------------- // KeywordMap -- maps strings to integers (identifiers to keyword kinds) //------------------------------------------------------------------------------------------- class KeywordMap { private: class Elem { public: wchar_t *key; int val; Elem *next; Elem(const wchar_t *key, int val) { this->key = coco_string_create(key); this->val = val; next = NULL; } virtual ~Elem() { coco_string_delete(key); } }; Elem **tab; public: KeywordMap() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); } virtual ~KeywordMap() { for (int i = 0; i < 128; ++i) { Elem *e = tab[i]; while (e != NULL) { Elem *next = e->next; delete e; e = next; } } delete [] tab; } void set(const wchar_t *key, int val) { Elem *e = new Elem(key, val); int k = coco_string_hash(key) % 128; e->next = tab[k]; tab[k] = e; } int get(wchar_t *key, int defaultVal) { Elem *e = tab[coco_string_hash(key) % 128]; while (e != NULL && !coco_string_equal(e->key, key)) e = e->next; return e == NULL ? defaultVal : e->val; } }; class Scanner { private: void *firstHeap; void *heap; void *heapTop; void **heapEnd; char EOL; int eofSym; int noSym; int maxT; int charSetSize; StartStates start; KeywordMap keywords; Token *t; // current token wchar_t *tval; // text of current token int tvalLength; // length of text of current token int tlen; // length of current token Token *tokens; // list of tokens already peeked (first token is a dummy) Token *pt; // current peek token int ch; // current input character -->casing0 int pos; // byte position of current character int line; // line number of current character int col; // column number of current character int oldEols; // EOLs that appeared in a comment; void CreateHeapBlock(); Token* CreateToken(); void AppendVal(Token *t); void Init(); void NextCh(); void AddCh(); -->commentsheader Token* NextToken(); public: Buffer *buffer; // scanner buffer Scanner(const wchar_t* fileName); Scanner(std::istream& s); ~Scanner(); Token* Scan(); Token* Peek(); void ResetPeek(); }; // end Scanner -->namespace_close #endif // !defined(COCO_SCANNER_H__) -->implementation /*------------------------------------------------------------------------- Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported to C++ by Csaba Balazs, University of Szeged with improvements by Pat Terry, Rhodes University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 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. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. -------------------------------------------------------------------------*/ -->begin #include #include #include "Scanner.h" // string handling, wide character wchar_t* coco_string_create(const wchar_t* value) { wchar_t* data; int len = 0; if (value) { len = wcslen(value); } data = new wchar_t[len + 1]; wcsncpy(data, value, len); data[len] = 0; return data; } wchar_t* coco_string_create(const wchar_t *value , int startIndex, int length) { int len = 0; wchar_t* data; if (value) { len = length; } data = new wchar_t[len + 1]; wcsncpy(data, &(value[startIndex]), len); data[len] = 0; return data; } wchar_t* coco_string_create_upper(wchar_t* data) { if (!data) { return NULL; } int dataLen = 0; if (data) { dataLen = wcslen(data); } wchar_t *newData = new wchar_t[dataLen + 1]; for (int i = 0; i <= dataLen; i++) { if ((L'a' <= data[i]) && (data[i] <= L'z')) { newData[i] = data[i] + (L'A' - L'a'); } else { newData[i] = data[i]; } } newData[dataLen] = L'\0'; return newData; } wchar_t* coco_string_create_lower(wchar_t* data) { if (!data) { return NULL; } int dataLen = 0; if (data) { dataLen = wcslen(data); } wchar_t* newData = new wchar_t[dataLen + 1]; for (int i = 0; i <= dataLen; i++) { if ((L'A' <= data[i]) && (data[i] <= L'Z')) { newData[i] = data[i] - (L'A'- L'a'); } else { newData[i] = data[i]; } } newData[dataLen] = L'\0'; return newData; } wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2) { wchar_t* data; int data1Len = 0; int data2Len = 0; if (data1) { data1Len = wcslen(data1); } if (data2) {data2Len = wcslen(data2); } data = new wchar_t[data1Len + data2Len + 1]; if (data1) { wcscpy(data, data1); } if (data2) { wcscpy(data + data1Len, data2); } data[data1Len + data2Len] = 0; return data; } wchar_t* coco_string_create_append(const wchar_t *target, const wchar_t appendix) { int targetLen = coco_string_length(target); wchar_t* data = new wchar_t[targetLen + 2]; wcsncpy(data, target, targetLen); data[targetLen] = appendix; data[targetLen + 1] = 0; return data; } void coco_string_delete(wchar_t* &data) { delete [] data; data = NULL; } int coco_string_length(const wchar_t* data) { if (data) { return wcslen(data); } return 0; } bool coco_string_endswith(wchar_t* data, wchar_t *end) { int dataLen = wcslen(data); int endLen = wcslen(end); return (endLen <= dataLen) && (wcscmp(data + dataLen - endLen, end) == 0); } int coco_string_indexof(wchar_t* data, wchar_t value) { wchar_t* chr = wcschr(data, value); if (chr) { return (chr-data); } return -1; } int coco_string_lastindexof(wchar_t* data, wchar_t value) { wchar_t* chr = wcsrchr(data, value); if (chr) { return (chr-data); } return -1; } void coco_string_merge(wchar_t* &target, wchar_t* appendix) { if (!appendix) { return; } wchar_t* data = coco_string_create_append(target, appendix); delete [] target; target = data; } bool coco_string_equal(wchar_t* data1, wchar_t* data2) { return wcscmp( data1, data2 ) == 0; } int coco_string_compareto(wchar_t* data1, wchar_t* data2) { return wcscmp(data1, data2); } int coco_string_hash(const wchar_t *data) { int h = 0; if (!data) { return 0; } while (*data != 0) { h = (h * 7) ^ *data; ++data; } if (h < 0) { h = -h; } return h; } // string handling, ascii character wchar_t* coco_string_create(const char* value) { int len = 0; if (value) { len = strlen(value); } wchar_t* data = new wchar_t[len + 1]; for (int i = 0; i < len; ++i) { data[i] = (wchar_t) value[i]; } data[len] = 0; return data; } char* coco_string_create_char(const wchar_t *value) { int len = coco_string_length(value); char *res = new char[len + 1]; for (int i = 0; i < len; ++i) { res[i] = (char) value[i]; } res[len] = 0; return res; } void coco_string_delete(char* &data) { delete [] data; data = NULL; } -->namespace_open Token::Token() { kind = 0; pos = 0; col = 0; line = 0; val = NULL; next = NULL; } Token::~Token() { coco_string_delete(val); } Buffer::Buffer(std::istream* s, bool isUserStream) { stream = s; this->isUserStream = isUserStream; s->seekg(0, std::ios_base::end); fileLen = bufLen = s->tellg(); s->seekg(0, std::ios_base::beg); buf = new char[MAX_BUFFER_LENGTH]; bufStart = INT_MAX; // nothing in the buffer so far SetPos(0); // setup buffer to position 0 (start) if (bufLen == fileLen) Close(); } Buffer::Buffer(Buffer *b) { buf = b->buf; b->buf = NULL; bufStart = b->bufStart; bufLen = b->bufLen; fileLen = b->fileLen; pos = b->pos; stream = b->stream; b->stream = NULL; isUserStream = b->isUserStream; } Buffer::~Buffer() { Close(); if (buf != NULL) { delete [] buf; buf = NULL; } } void Buffer::Close() { if (!isUserStream && stream != NULL) { std::ifstream * ifs = dynamic_cast(stream); if (ifs) { ifs->close(); delete ifs; } stream = NULL; } } int Buffer::Read() { if (pos < bufLen) { return buf[pos++]; } else if (GetPos() < fileLen) { SetPos(GetPos()); // shift buffer start to Pos return buf[pos++]; } else { return EoF; } } int Buffer::Peek() { int curPos = GetPos(); int ch = Read(); SetPos(curPos); return ch; } char* Buffer::GetString(int beg, int end) { int len = end - beg; char *buf = new char[len]; int oldPos = GetPos(); SetPos(beg); for (int i = 0; i < len; ++i) buf[i] = (char) Read(); SetPos(oldPos); return buf; } int Buffer::GetPos() { return pos + bufStart; } void Buffer::SetPos(int value) { if (value < 0) value = 0; else if (value > fileLen) value = fileLen; if (value >= bufStart && value < bufStart + bufLen) { // already in buffer pos = value - bufStart; } else if (stream != NULL) { // must be swapped in stream->seekg(0, std::ios_base::beg); stream->get(buf, MAX_BUFFER_LENGTH); bufLen = stream->gcount(); bufStart = value; pos = 0; } else { pos = fileLen - bufStart; // make Pos return fileLen } } int UTF8Buffer::Read() { int ch; do { ch = Buffer::Read(); // until we find a uft8 start (0xxxxxxx or 11xxxxxx) } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EOF)); if (ch < 128 || ch == EOF) { // nothing to do, first 127 chars are the same in ascii and utf8 // 0xxxxxxx or end of file character } else if ((ch & 0xF0) == 0xF0) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx int c1 = ch & 0x07; ch = Buffer::Read(); int c2 = ch & 0x3F; ch = Buffer::Read(); int c3 = ch & 0x3F; ch = Buffer::Read(); int c4 = ch & 0x3F; ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4; } else if ((ch & 0xE0) == 0xE0) { // 1110xxxx 10xxxxxx 10xxxxxx int c1 = ch & 0x0F; ch = Buffer::Read(); int c2 = ch & 0x3F; ch = Buffer::Read(); int c3 = ch & 0x3F; ch = (((c1 << 6) | c2) << 6) | c3; } else if ((ch & 0xC0) == 0xC0) { // 110xxxxx 10xxxxxx int c1 = ch & 0x1F; ch = Buffer::Read(); int c2 = ch & 0x3F; ch = (c1 << 6) | c2; } return ch; } Scanner::Scanner(const wchar_t* fileName) { char *chFileName = coco_string_create_char(fileName); std::ifstream* ifs = new std::ifstream(chFileName); if (!ifs || !ifs->is_open()) { wprintf(L"--- Cannot open file %ls\n", fileName); exit(1); } coco_string_delete(chFileName); buffer = new Buffer(ifs, false); Init(); } Scanner::Scanner(std::istream& s) { buffer = new Buffer(&s, true); Init(); } Scanner::~Scanner() { char* cur = (char*) firstHeap; while(cur != NULL) { cur = *(char**) (cur + HEAP_BLOCK_SIZE); free(firstHeap); firstHeap = cur; } delete [] tval; delete buffer; } void Scanner::Init() { EOL = '\n'; eofSym = 0; -->declarations tvalLength = 128; tval = new wchar_t[tvalLength]; // text of current token // HEAP_BLOCK_SIZE byte heap + pointer to next heap block heap = malloc(HEAP_BLOCK_SIZE + sizeof(void*)); firstHeap = heap; heapEnd = (void**) (((char*) heap) + HEAP_BLOCK_SIZE); *heapEnd = 0; heapTop = heap; if (sizeof(Token) > HEAP_BLOCK_SIZE) { wprintf(L"--- Too small HEAP_BLOCK_SIZE\n"); exit(1); } pos = -1; line = 1; col = 0; oldEols = 0; NextCh(); if (ch == 0xEF) { // check optional byte order mark for UTF-8 NextCh(); int ch1 = ch; NextCh(); int ch2 = ch; if (ch1 != 0xBB || ch2 != 0xBF) { wprintf(L"Illegal byte order mark at start of file"); exit(1); } Buffer *oldBuf = buffer; buffer = new UTF8Buffer(buffer); col = 0; delete oldBuf; oldBuf = NULL; NextCh(); } -->initialization pt = tokens = CreateToken(); // first token is a dummy } void Scanner::NextCh() { if (oldEols > 0) { ch = EOL; oldEols--; } else { pos = buffer->GetPos(); ch = buffer->Read(); col++; // replace isolated '\r' by '\n' in order to make // eol handling uniform across Windows, Unix and Mac if (ch == L'\r' && buffer->Peek() != L'\n') ch = EOL; if (ch == EOL) { line++; col = 0; } } -->casing1 } void Scanner::AddCh() { if (tlen >= tvalLength) { tvalLength *= 2; wchar_t *newBuf = new wchar_t[tvalLength]; memcpy(newBuf, tval, tlen*sizeof(wchar_t)); delete tval; tval = newBuf; } -->casing2 NextCh(); } -->comments void Scanner::CreateHeapBlock() { void* newHeap; char* cur = (char*) firstHeap; while(((char*) tokens < cur) || ((char*) tokens > (cur + HEAP_BLOCK_SIZE))) { cur = *((char**) (cur + HEAP_BLOCK_SIZE)); free(firstHeap); firstHeap = cur; } // HEAP_BLOCK_SIZE byte heap + pointer to next heap block newHeap = malloc(HEAP_BLOCK_SIZE + sizeof(void*)); *heapEnd = newHeap; heapEnd = (void**) (((char*) newHeap) + HEAP_BLOCK_SIZE); *heapEnd = 0; heap = newHeap; heapTop = heap; } Token* Scanner::CreateToken() { Token *t; if (((char*) heapTop + (int) sizeof(Token)) >= (char*) heapEnd) { CreateHeapBlock(); } t = (Token*) heapTop; heapTop = (void*) ((char*) heapTop + sizeof(Token)); t->val = NULL; t->next = NULL; return t; } void Scanner::AppendVal(Token *t) { int reqMem = (tlen + 1) * sizeof(wchar_t); if (((char*) heapTop + reqMem) >= (char*) heapEnd) { if (reqMem > HEAP_BLOCK_SIZE) { wprintf(L"--- Too long token value\n"); exit(1); } CreateHeapBlock(); } t->val = (wchar_t*) heapTop; heapTop = (void*) ((char*) heapTop + reqMem); wcsncpy(t->val, tval, tlen); t->val[tlen] = L'\0'; } Token* Scanner::NextToken() { while (ch == ' ' || -->scan1 ) NextCh(); -->scan2 t = CreateToken(); t->pos = pos; t->col = col; t->line = line; int state = start.state(ch); tlen = 0; AddCh(); switch (state) { case -1: { t->kind = eofSym; break; } // NextCh already done case 0: { t->kind = noSym; break; } // NextCh already done -->scan3 } AppendVal(t); return t; } // get the next token (possibly a token already seen during peeking) Token* Scanner::Scan() { if (tokens->next == NULL) { return pt = tokens = NextToken(); } else { pt = tokens = tokens->next; return tokens; } } // peek for the next token, ignore pragmas Token* Scanner::Peek() { if (pt->next == NULL) { do { pt = pt->next = NextToken(); } while (pt->kind > maxT); // skip pragmas } else { do { pt = pt->next; } while (pt->kind > maxT); } return pt; } // make sure that peeking starts at the current scan position void Scanner::ResetPeek() { pt = tokens; } -->namespace_close $$$ newsbeuter-2.7/filter/Scanner.h000066400000000000000000000135421220711462700166030ustar00rootroot00000000000000 #if !defined(COCO_SCANNER_H__) #define COCO_SCANNER_H__ #include #include #include #include #include #if _MSC_VER >= 1400 #define coco_swprintf swprintf_s #elif _MSC_VER >= 1300 #define coco_swprintf _snwprintf #elif defined __GNUC__ #define coco_swprintf swprintf #else #error unknown compiler! #endif #include #include #define COCO_WCHAR_MAX 65535 #define MAX_BUFFER_LENGTH (64*1024) #define HEAP_BLOCK_SIZE (64*1024) // string handling, wide character wchar_t* coco_string_create(const wchar_t *value); wchar_t* coco_string_create(const wchar_t *value , int startIndex, int length); wchar_t* coco_string_create_upper(wchar_t* data); wchar_t* coco_string_create_lower(wchar_t* data); wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2); wchar_t* coco_string_create_append(const wchar_t* data, const wchar_t value); void coco_string_delete(wchar_t* &data); int coco_string_length(const wchar_t* data); bool coco_string_endswith(wchar_t* data, wchar_t *value); int coco_string_indexof(wchar_t* data, wchar_t value); int coco_string_lastindexof(wchar_t* data, wchar_t value); void coco_string_merge(wchar_t* &data, wchar_t* value); bool coco_string_equal(wchar_t* data1, wchar_t* data2); int coco_string_compareto(wchar_t* data1, wchar_t* data2); int coco_string_hash(const wchar_t* data); // string handling, ascii character wchar_t* coco_string_create(const char *value); char* coco_string_create_char(const wchar_t *value); void coco_string_delete(char* &data); class Token { public: int kind; // token kind int pos; // token position in the source text (starting at 0) int col; // token column (starting at 1) int line; // token line (starting at 1) wchar_t* val; // token value Token *next; // ML 2005-03-11 Peek tokens are kept in linked list Token(); ~Token(); }; class Buffer { private: char *buf; // input buffer int bufStart; // position of first byte in buffer relative to input stream int bufLen; // length of buffer int fileLen; // length of input stream int pos; // current position in buffer std::istream* stream; // input stream (seekable) bool isUserStream; // was the stream opened by the user? public: static const int EoF = COCO_WCHAR_MAX + 1; Buffer(std::istream* s, bool isUserStream); Buffer(Buffer *b); virtual ~Buffer(); virtual void Close(); virtual int Read(); virtual int Peek(); virtual char* GetString(int beg, int end); virtual int GetPos(); virtual void SetPos(int value); }; class UTF8Buffer : public Buffer { public: UTF8Buffer(Buffer *b) : Buffer(b) {}; virtual int Read(); }; //----------------------------------------------------------------------------------- // StartStates -- maps charactes to start states of tokens //----------------------------------------------------------------------------------- class StartStates { private: class Elem { public: int key, val; Elem *next; Elem(int key, int val) { this->key = key; this->val = val; next = NULL; } }; Elem **tab; public: StartStates() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); } virtual ~StartStates() { for (int i = 0; i < 128; ++i) { Elem *e = tab[i]; while (e != NULL) { Elem *next = e->next; delete e; e = next; } } delete [] tab; } void set(int key, int val) { Elem *e = new Elem(key, val); int k = key % 128; e->next = tab[k]; tab[k] = e; } int state(int key) { Elem *e = tab[key % 128]; while (e != NULL && e->key != key) e = e->next; return e == NULL ? 0 : e->val; } }; //------------------------------------------------------------------------------------------- // KeywordMap -- maps strings to integers (identifiers to keyword kinds) //------------------------------------------------------------------------------------------- class KeywordMap { private: class Elem { public: wchar_t *key; int val; Elem *next; Elem(const wchar_t *key, int val) { this->key = coco_string_create(key); this->val = val; next = NULL; } virtual ~Elem() { coco_string_delete(key); } }; Elem **tab; public: KeywordMap() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); } virtual ~KeywordMap() { for (int i = 0; i < 128; ++i) { Elem *e = tab[i]; while (e != NULL) { Elem *next = e->next; delete e; e = next; } } delete [] tab; } void set(const wchar_t *key, int val) { Elem *e = new Elem(key, val); int k = coco_string_hash(key) % 128; e->next = tab[k]; tab[k] = e; } int get(wchar_t *key, int defaultVal) { Elem *e = tab[coco_string_hash(key) % 128]; while (e != NULL && !coco_string_equal(e->key, key)) e = e->next; return e == NULL ? defaultVal : e->val; } }; class Scanner { private: void *firstHeap; void *heap; void *heapTop; void **heapEnd; char EOL; int eofSym; int noSym; int maxT; int charSetSize; StartStates start; KeywordMap keywords; Token *t; // current token wchar_t *tval; // text of current token int tvalLength; // length of text of current token int tlen; // length of current token Token *tokens; // list of tokens already peeked (first token is a dummy) Token *pt; // current peek token int ch; // current input character int pos; // byte position of current character int line; // line number of current character int col; // column number of current character int oldEols; // EOLs that appeared in a comment; void CreateHeapBlock(); Token* CreateToken(); void AppendVal(Token *t); void Init(); void NextCh(); void AddCh(); Token* NextToken(); public: Buffer *buffer; // scanner buffer Scanner(const wchar_t* fileName); Scanner(std::istream& s); ~Scanner(); Token* Scan(); Token* Peek(); void ResetPeek(); }; // end Scanner #endif // !defined(COCO_SCANNER_H__) newsbeuter-2.7/filter/filter.atg000066400000000000000000000034111220711462700170150ustar00rootroot00000000000000/* * parser for newsbeuter filter language */ #include "FilterParser.h" COMPILER Filter FilterParser * gen; CHARACTERS identchar = 'A'..'Z' + 'a'..'z' + "_-.". digit = "0123456789". nonquote = ANY - '"'. TOKENS openblock = '('. closeblock = ')'. ident = identchar { identchar }. stringliteral = '"' { nonquote } '"'. numliteral = ['-'] digit { digit }. rangeliteral = digit { digit } ':' digit { digit }. PRODUCTIONS stringlit = ( stringliteral | numliteral | rangeliteral ) (. lit = coco_string_create_char(t->val); .) . matchattrib = ident (. name = coco_string_create_char(t->val); .) . matchop = "==" (. op = MATCHOP_EQ; .) | "=" (. op = MATCHOP_EQ; .) | "!=" (. op = MATCHOP_NE; .) | "=~" (. op = MATCHOP_RXEQ; .) | "!~" (. op = MATCHOP_RXNE; .) | "<" (. op = MATCHOP_LT; .) | ">" (. op = MATCHOP_GT; .) | "<=" (. op = MATCHOP_LE; .) | ">=" (. op = MATCHOP_GE; .) | "#" (. op = MATCHOP_CONTAINS; .) | "!#" (. op = MATCHOP_CONTAINSNOT; .) | "between" (. op = MATCHOP_BETWEEN; .) . logop = "and" (. lop = LOGOP_AND; .) | "or" (. lop = LOGOP_OR; .) . matchexpr (. char * name, * lit; int op; .) = matchattrib matchop stringlit (. gen->add_matchexpr(name, op, lit); .) . blockexpr = openblock (. gen->open_block(); .) expr closeblock (. gen->close_block(); .) . expr (. int lop; .) = ( matchexpr | blockexpr ) { logop (. gen->add_logop(lop); .) ( matchexpr | blockexpr ) } . Filter = expr. END Filter. newsbeuter-2.7/include/000077500000000000000000000000001220711462700151725ustar00rootroot00000000000000newsbeuter-2.7/include/cache.h000066400000000000000000000043611220711462700164120ustar00rootroot00000000000000#ifndef NEWSBEUTER_CACHE__H #define NEWSBEUTER_CACHE__H #include #include #include #include namespace newsbeuter { typedef std::pair google_replay_pair; enum { GOOGLE_MARK_READ = 1, GOOGLE_MARK_UNREAD = 2 }; class cache { public: cache(const std::string& cachefile, configcontainer * c); ~cache(); void externalize_rssfeed(std::tr1::shared_ptr feed, bool reset_unread); void internalize_rssfeed(std::tr1::shared_ptr feed, rss_ignores * ign); void update_rssitem_unread_and_enqueued(std::tr1::shared_ptr item, const std::string& feedurl); void update_rssitem_unread_and_enqueued(rss_item* item, const std::string& feedurl); void cleanup_cache(std::vector >& feeds); void do_vacuum(); std::vector > search_for_items(const std::string& querystr, const std::string& feedurl); void catchup_all(const std::string& feedurl = ""); void catchup_all(std::tr1::shared_ptr feed); void update_rssitem_flags(rss_item* item); std::vector get_feed_urls(); void fetch_lastmodified(const std::string& uri, time_t& t, std::string& etag); void update_lastmodified(const std::string& uri, time_t t, const std::string& etag); unsigned int get_unread_count(); void mark_item_deleted(const std::string& guid, bool b); void remove_old_deleted_items(const std::string& rssurl, const std::vector& guids); void mark_items_read_by_guid(const std::vector& guids); std::vector get_read_item_guids(); void fetch_descriptions(rss_feed * feed); void record_google_replay(const std::string& guid, unsigned int state); std::vector get_google_replay(); void delete_google_replay_by_guid(const std::vector& guids); private: void populate_tables(); void set_pragmas(); void delete_item(const std::tr1::shared_ptr item); void clean_old_articles(); void update_rssitem_unlocked(std::tr1::shared_ptr item, const std::string& feedurl, bool reset_unread); std::string prepare_query(const char * format, ...); sqlite3 * db; configcontainer * cfg; mutex mtx; }; } #endif newsbeuter-2.7/include/colormanager.h000066400000000000000000000020561220711462700200170ustar00rootroot00000000000000#ifndef COLORMANAGER_H_ #define COLORMANAGER_H_ #include #include #include namespace podbeuter { class pb_view; } class view; namespace newsbeuter { class colormanager : public config_action_handler { public: colormanager(); ~colormanager(); void register_commands(configparser& cfgparser); virtual void handle_action(const std::string& action, const std::vector& params); virtual void dump_config(std::vector& config_output); inline bool colors_loaded() { return colors_loaded_; } void set_pb_colors(podbeuter::pb_view * v); inline std::map& get_fgcolors() { return fg_colors; } inline std::map& get_bgcolors() { return bg_colors; } inline std::map >& get_attributes() { return attributes; } private: bool colors_loaded_; std::map fg_colors; std::map bg_colors; std::map > attributes; }; } #endif newsbeuter-2.7/include/configcontainer.h000066400000000000000000000026501220711462700205160ustar00rootroot00000000000000#ifndef CONFIGCONTAINER_H_ #define CONFIGCONTAINER_H_ #include namespace newsbeuter { struct configdata { enum configdata_type { INVALID, BOOL, INT, STR, PATH, ALIAS, ENUM }; configdata(const std::string& v = "", configdata_type t = INVALID, bool m = false) : value(v), default_value(v), type(t), multi_option(m) { } configdata(const std::string& v, ...); std::string value; std::string default_value; configdata_type type; std::set enum_values; bool multi_option; }; class configcontainer : public config_action_handler { public: configcontainer(); virtual ~configcontainer(); void register_commands(configparser& cfgparser); virtual void handle_action(const std::string& action, const std::vector& params); virtual void dump_config(std::vector& config_output); bool get_configvalue_as_bool(const std::string& key); int get_configvalue_as_int(const std::string& key); std::string get_configvalue(const std::string& key); void set_configvalue(const std::string& key, const std::string& value); void reset_to_default(const std::string& key); void toggle(const std::string& key); std::vector get_suggestions(const std::string& fragment); private: std::map config_data; bool is_bool(const std::string& s); bool is_int(const std::string& s); std::string lookup_alias(const std::string& s); }; } #endif /*CONFIGCONTAINER_H_*/ newsbeuter-2.7/include/configparser.h000066400000000000000000000033761220711462700200360ustar00rootroot00000000000000#ifndef NEWSBEUTER_CONFIGPARSER__H #define NEWSBEUTER_CONFIGPARSER__H #include #include #include #include namespace newsbeuter { enum action_handler_status { AHS_OK = 0, AHS_INVALID_PARAMS, AHS_TOO_FEW_PARAMS, AHS_INVALID_COMMAND, AHS_FILENOTFOUND }; struct config_action_handler { virtual void handle_action(const std::string& action, const std::vector& params) = 0; virtual void dump_config(std::vector& config_output) = 0; config_action_handler() { } virtual ~config_action_handler() { } }; class configparser : public config_action_handler { public: configparser(); virtual ~configparser(); void register_handler(const std::string& cmd, config_action_handler * handler); void unregister_handler(const std::string& cmd); virtual void handle_action(const std::string& action, const std::vector& params); virtual void dump_config(std::vector& ) { /* nothing because configparser itself only handles include */ } bool parse(const std::string& filename, bool double_include = true); static std::string evaluate_backticks(std::string token); private: void evaluate_backticks(std::vector& tokens); static std::string evaluate_cmd(const std::string& cmd); std::vector > parsed_content; std::map action_handlers; std::set included_files; }; class null_config_action_handler : public config_action_handler { public: null_config_action_handler() { } virtual ~null_config_action_handler() { } virtual void handle_action(const std::string& , const std::vector& ) { } virtual void dump_config(std::vector& ) { } }; } #endif newsbeuter-2.7/include/controller.h000066400000000000000000000110561220711462700175310ustar00rootroot00000000000000#ifndef NEWSBEUTER_CONTROLLER__H #define NEWSBEUTER_CONTROLLER__H #include #include #include #include #include #include #include #include #include namespace newsbeuter { extern int ctrl_c_hit; extern std::string lock_file; class view; class curl_handle; class controller { public: controller(); ~controller(); void set_view(view * vv); view * get_view() { return v; } void run(int argc = 0, char * argv[] = NULL); void reload(unsigned int pos, unsigned int max = 0, bool unattended = false, curl_handle *easyhandle = 0); void reload_all(bool unattended = false); void reload_indexes(const std::vector& indexes, bool unattended = false); void reload_range(unsigned int start, unsigned int end, unsigned int size, bool unattended = false); void start_reload_all_thread(std::vector * indexes = 0); std::tr1::shared_ptr get_feed(unsigned int pos); std::tr1::shared_ptr get_feed_by_url(const std::string& feedurl); std::vector > search_for_items(const std::string& query, const std::string& feedurl); inline unsigned int get_feedcount() { return feeds.size(); } inline void unlock_reload_mutex() { reload_mutex.unlock(); } bool trylock_reload_mutex(); void update_feedlist(); void update_visible_feeds(); void mark_all_read(unsigned int pos); void mark_article_read(const std::string& guid, bool read); void record_google_replay(const std::string& guid, bool read); void catchup_all(); inline void catchup_all(std::tr1::shared_ptr feed) { rsscache->catchup_all(feed); } inline bool get_refresh_on_start() const { return refresh_on_start; } bool is_valid_podcast_type(const std::string& mimetype); void enqueue_url(const std::string& url, std::tr1::shared_ptr feed); void notify(const std::string& msg); unsigned int get_pos_of_next_unread(unsigned int pos); void reload_urls_file(); void edit_urls_file(); std::vector > get_all_feeds(); std::vector > get_all_feeds_unlocked(); inline filtercontainer& get_filters() { return filters; } std::string bookmark(const std::string& url, const std::string& title, const std::string& description); inline cache * get_cache() { return rsscache; } inline configcontainer * get_cfg() { return &cfg; } void write_item(std::tr1::shared_ptr item, const std::string& filename); void write_item(std::tr1::shared_ptr item, std::ostream& ostr); std::string write_temporary_item(std::tr1::shared_ptr item); void mark_deleted(const std::string& guid, bool b); void update_config(); void load_configfile(const std::string& filename); void dump_config(const std::string& filename); void sort_feeds(); void update_flags(std::tr1::shared_ptr item); unsigned int get_feed_count_per_tag(const std::string& tag); private: void usage(char * argv0); bool setup_dirs_xdg(const char *env_home, bool silent); void setup_dirs(bool silent); void version_information(const char * argv0, unsigned int level); void import_opml(const char * filename); void export_opml(); void rec_find_rss_outlines(xmlNode * node, std::string tag); void compute_unread_numbers(unsigned int&, unsigned int& ); void execute_commands(char ** argv, unsigned int i); std::string prepare_message(unsigned int pos, unsigned int max); void save_feed(std::tr1::shared_ptr feed, unsigned int pos); void enqueue_items(std::tr1::shared_ptr feed); std::string generate_enqueue_filename(const std::string& url, std::tr1::shared_ptr feed); std::string get_hostname_from_url(const std::string& url); void import_read_information(const std::string& readinfofile); void export_read_information(const std::string& readinfofile); view * v; urlreader * urlcfg; cache * rsscache; std::vector > feeds; std::string config_dir; std::string url_file; std::string cache_file; std::string config_file; std::string queue_file; std::string searchfile; std::string cmdlinefile; bool refresh_on_start; configcontainer cfg; rss_ignores ign; filtercontainer filters; mutex reload_mutex; configparser cfgparser; colormanager colorman; regexmanager rxman; remote_api * api; mutex feeds_mutex; bool offline_mode; }; } #endif newsbeuter-2.7/include/dialogs_formaction.h000066400000000000000000000012341220711462700212060ustar00rootroot00000000000000#ifndef NEWSBEUTER_DIALOGS_FORMACTION__H #define NEWSBEUTER_DIALOGS_FORMACTION__H #include namespace newsbeuter { class dialogs_formaction : public formaction { public: dialogs_formaction(view *, std::string formstr); virtual ~dialogs_formaction(); virtual void prepare(); virtual void init(); virtual keymap_hint_entry * get_keymap_hint(); virtual std::string id() const { return "dialogs"; } virtual std::string title(); virtual void handle_cmdline(const std::string& cmd); private: virtual void process_operation(operation op, bool automatic = false, std::vector * args = NULL); bool update_list; }; } #endif newsbeuter-2.7/include/download.h000066400000000000000000000020701220711462700171510ustar00rootroot00000000000000#ifndef PODBEUTER_DOWNLOAD__H #define PODBEUTER_DOWNLOAD__H #include namespace podbeuter { enum dlstatus_t { DL_QUEUED = 0, DL_DOWNLOADING, DL_CANCELLED, DL_DELETED, DL_FINISHED, DL_FAILED, DL_ALREADY_DOWNLOADED, DL_READY, DL_PLAYED }; class pb_controller; class download { public: download(pb_controller * c = 0); ~download(); double percents_finished(); const char * status_text(); inline dlstatus_t status() const { return dlstatus; } const char * filename(); const char * url(); void set_filename(const std::string& str); void set_url(const std::string& url); void set_progress(double cur, double max); void set_status(dlstatus_t dls); void set_kbps(double kbps); double kbps(); void set_offset(unsigned long offset); inline double current_size() const { return cursize + offs; } inline double total_size() const { return totalsize + offs; } private: std::string fn; std::string url_; dlstatus_t dlstatus; float cursize; float totalsize; double curkbps; unsigned long offs; pb_controller * ctrl; }; } #endif newsbeuter-2.7/include/downloadthread.h000066400000000000000000000012251220711462700203420ustar00rootroot00000000000000#ifndef DOWNLOADTHREAD_H_ #define DOWNLOADTHREAD_H_ #include #include namespace newsbeuter { class controller; class downloadthread : public thread { public: downloadthread(controller * c, std::vector * idxs = 0); virtual ~downloadthread(); protected: virtual void run(); private: controller * ctrl; std::vector indexes; }; class reloadrangethread : public thread { public: reloadrangethread(controller * c, unsigned int start, unsigned int end, unsigned int size, bool unattended); protected: virtual void run(); private: controller * ctrl; unsigned int s, e, ss; bool u; }; } #endif /*DOWNLOADTHREAD_H_*/ newsbeuter-2.7/include/exception.h000066400000000000000000000004671220711462700173500ustar00rootroot00000000000000#ifndef AK_EXCEPTION__H #define AK_EXCEPTION__H #include namespace newsbeuter { class exception : public std::exception { public: exception(unsigned int error_code = 0); ~exception() throw(); virtual const char* what() const throw(); private: unsigned int ecode; }; } #endif newsbeuter-2.7/include/exceptions.h000066400000000000000000000033601220711462700175260ustar00rootroot00000000000000#ifndef EXCEPTIONS_H_ #define EXCEPTIONS_H_ #include #include #include #include namespace newsbeuter { class xmlexception : public std::exception { public: xmlexception(const std::string& errmsg) : msg(errmsg) { } virtual ~xmlexception() throw() { } virtual const char * what() const throw() { return msg.c_str(); } private: std::string msg; }; class configexception : public std::exception { public: configexception(const std::string& errmsg) : msg(errmsg) { } virtual ~configexception() throw() { } virtual const char * what() const throw() { return msg.c_str(); } private: std::string msg; }; class confighandlerexception : public std::exception { public: confighandlerexception(const std::string& emsg) { msg = emsg; } confighandlerexception(action_handler_status e); virtual ~confighandlerexception() throw() { } virtual const char * what() const throw() { return msg.c_str(); } int status() { return 0; } private: const char * get_errmsg(action_handler_status e); std::string msg; }; class dbexception : public std::exception { public: dbexception(sqlite3 * h) : msg(sqlite3_errmsg(h)) { } virtual ~dbexception() throw() { } virtual const char * what() const throw() { return msg.c_str(); } private: std::string msg; }; class matcherexception : public std::exception { public: enum errortype_t { ATTRIB_UNAVAIL, INVALID_REGEX }; matcherexception(errortype_t et, const std::string& info, const std::string& info2 = "") : type(et), addinfo(info), addinfo2(info2) { } virtual ~matcherexception() throw() { } virtual const char * what() const throw(); private: errortype_t type; std::string addinfo; std::string addinfo2; }; } #endif /*EXCEPTIONS_H_*/ newsbeuter-2.7/include/feedlist_formaction.h000066400000000000000000000047731220711462700213760ustar00rootroot00000000000000#ifndef NEWSBEUTER_FEEDLIST_FORMACTION__H #define NEWSBEUTER_FEEDLIST_FORMACTION__H #include #include #include #include #include namespace newsbeuter { typedef std::pair, unsigned int> feedptr_pos_pair; class feedlist_formaction : public formaction { public: feedlist_formaction(view *, std::string formstr); virtual ~feedlist_formaction(); virtual void prepare(); virtual void init(); void set_feedlist(std::vector >& feeds); void update_visible_feeds(std::vector >& feeds); void set_tags(const std::vector& t); virtual keymap_hint_entry * get_keymap_hint(); std::tr1::shared_ptr get_feed(); virtual void set_redraw(bool b) { formaction::set_redraw(b); apply_filter = !(v->get_cfg()->get_configvalue_as_bool("show-read-feeds")); } virtual std::string id() const { return "feedlist"; } virtual std::string title(); bool jump_to_next_unread_feed(unsigned int& feedpos); bool jump_to_previous_unread_feed(unsigned int& feedpos); bool jump_to_next_feed(unsigned int& feedpos); bool jump_to_previous_feed(unsigned int& feedpos); bool jump_to_random_unread_feed(unsigned int& feedpos); virtual void handle_cmdline(const std::string& cmd); virtual void finished_qna(operation op); void mark_pos_if_visible(unsigned int pos); void set_regexmanager(regexmanager * r); private: int get_pos(unsigned int realidx); virtual void process_operation(operation op, bool automatic = false, std::vector * args = NULL); void goto_feed(const std::string& str); void save_filterpos(); void op_end_setfilter(); void op_start_search(); void handle_cmdline_num(unsigned int idx); void set_pos(); std::string get_title(std::tr1::shared_ptr feed); std::string format_line(const std::string& feedlist_format, std::tr1::shared_ptr feed, unsigned int pos, unsigned int width); bool zero_feedpos; unsigned int feeds_shown; bool auto_open; bool quit; std::vector visible_feeds; std::string tag; std::vector tags; matcher m; bool apply_filter; history filterhistory; std::tr1::shared_ptr search_dummy_feed; unsigned int filterpos; bool set_filterpos; regexmanager * rxman; unsigned int old_width; unsigned int unread_feeds; unsigned int total_feeds; std::string old_sort_order; }; } #endif newsbeuter-2.7/include/filebrowser_formaction.h000066400000000000000000000021201220711462700221020ustar00rootroot00000000000000#ifndef NEWSBEUTER_FILEBROWSER_FORMACTION__H #define NEWSBEUTER_FILEBROWSER_FORMACTION__H #include namespace newsbeuter { class filebrowser_formaction : public formaction { public: filebrowser_formaction(view *, std::string formstr); virtual ~filebrowser_formaction(); virtual void prepare(); virtual void init(); virtual keymap_hint_entry * get_keymap_hint(); inline void set_dir(const std::string& d) { dir = d; } inline void set_default_filename(const std::string& fn) { default_filename = fn; } virtual std::string id() const { return "filebrowser"; } virtual std::string title(); private: virtual void process_operation(operation op, bool automatic = false, std::vector * args = NULL); std::string add_file(std::string filename); std::string get_filename_suggestion(const std::string& s); std::string get_rwx(unsigned short val); char get_filetype(mode_t mode); std::string get_owner(uid_t uid); std::string get_group(gid_t gid); bool quit; std::string cwd; std::string dir; std::string default_filename; }; } #endif newsbeuter-2.7/include/filtercontainer.h000066400000000000000000000012601220711462700205320ustar00rootroot00000000000000#ifndef NEWSBEUTER_FILTERCONTAINER__H #define NEWSBEUTER_FILTERCONTAINER__H #include namespace newsbeuter { typedef std::pair filter_name_expr_pair; class filtercontainer : public config_action_handler { public: filtercontainer() { } virtual ~filtercontainer(); virtual void handle_action(const std::string& action, const std::vector& params); virtual void dump_config(std::vector& config_output); inline std::vector& get_filters() { return filters; } inline unsigned int size() { return filters.size(); } private: std::vector filters; }; } #endif newsbeuter-2.7/include/formaction.h000066400000000000000000000050251220711462700175060ustar00rootroot00000000000000#ifndef NEWSBEUTER_FORMACTION__H #define NEWSBEUTER_FORMACTION__H #include #include #include #include #include #include namespace newsbeuter { class view; struct keymap_hint_entry { operation op; char * text; }; typedef std::pair qna_pair; class formaction { public: formaction(view *, std::string formstr); virtual ~formaction(); virtual void prepare() = 0; virtual void init() = 0; std::tr1::shared_ptr get_form(); virtual void set_redraw(bool b) { do_redraw = b; } virtual keymap_hint_entry * get_keymap_hint() = 0; virtual std::string id() const = 0; virtual std::string get_value(const std::string& value); virtual void handle_cmdline(const std::string& cmd); void process_op(operation op, bool automatic = false, std::vector * args = NULL); virtual void finished_qna(operation op); void start_cmdline(); virtual void recalculate_form(); inline std::string get_qna_response(unsigned int i) { return (qna_responses.size() >= (i + 1)) ? qna_responses[i] : ""; } void start_qna(const std::vector& prompts, operation finish_op, history * h = NULL); inline void set_parent_formaction(std::tr1::shared_ptr fa) { parent_formaction = fa; } inline std::tr1::shared_ptr get_parent_formaction() const { return parent_formaction; } virtual std::string title() = 0; virtual std::vector get_suggestions(const std::string& fragment); static void load_histories(const std::string& searchfile, const std::string& cmdlinefile); static void save_histories(const std::string& searchfile, const std::string& cmdlinefile, unsigned int limit); protected: virtual void process_operation(operation op, bool automatic = false, std::vector * args = NULL) = 0; virtual void set_keymap_hints(); void start_bookmark_qna(const std::string& default_title, const std::string& default_url, const std::string& default_desc); view * v; std::tr1::shared_ptr f; bool do_redraw; std::vector qna_responses; static history searchhistory; static history cmdlinehistory; std::vector valid_cmds; private: std::string prepare_keymap_hint(keymap_hint_entry * hints); void start_next_question(); std::string make_title(const std::string& url); std::vector qna_prompts; operation finish_operation; history * qna_history; std::tr1::shared_ptr parent_formaction; }; } #endif newsbeuter-2.7/include/formatstring.h000066400000000000000000000007061220711462700200650ustar00rootroot00000000000000#ifndef NEWSBEUTER_FORMATSTRING__H #define NEWSBEUTER_FORMATSTRING__H #include #include namespace newsbeuter { class fmtstr_formatter { public: fmtstr_formatter() { } void register_fmt(char f, const std::string& value); std::string do_format(const std::string& fmt, unsigned int width = 0); std::wstring do_wformat(const std::wstring& fmt, unsigned int width = 0); private: std::map fmts; }; } #endif newsbeuter-2.7/include/google_api.h000066400000000000000000000030631220711462700174520ustar00rootroot00000000000000#ifndef NEWSBEUTER_GOOGLE_API__H #define NEWSBEUTER_GOOGLE_API__H #include #include #include namespace newsbeuter { class googlereader_api : public remote_api { public: googlereader_api(configcontainer * c); virtual ~googlereader_api(); virtual bool authenticate(); virtual std::vector get_subscribed_urls(); virtual void configure_handle(CURL * handle); virtual bool mark_all_read(const std::string& feedurl); virtual bool mark_article_read(const std::string& guid, bool read); virtual bool update_article_flags(const std::string& oldflags, const std::string& newflags, const std::string& guid); std::vector bulk_mark_articles_read(const std::vector& actions); private: std::vector get_tags(xmlNode * node); std::string get_new_token(); std::string retrieve_auth(); std::string post_content(const std::string& url, const std::string& postdata); bool star_article(const std::string& guid, bool star); bool share_article(const std::string& guid, bool share); bool mark_article_read_with_token(const std::string& guid, bool read, const std::string& token); std::string auth; }; class googlereader_urlreader : public urlreader { public: googlereader_urlreader(configcontainer * c, const std::string& url_file, remote_api * a); virtual ~googlereader_urlreader(); virtual void write_config(); virtual void reload(); virtual std::string get_source(); private: configcontainer * cfg; std::string file; remote_api * api; }; } #endif newsbeuter-2.7/include/help_formaction.h000066400000000000000000000014641220711462700205210ustar00rootroot00000000000000#ifndef NEWSBEUTER_HELP_FORMACTION__H #define NEWSBEUTER_HELP_FORMACTION__H #include namespace newsbeuter { class help_formaction : public formaction { public: help_formaction(view *, std::string formstr); virtual ~help_formaction(); virtual void prepare(); virtual void init(); virtual keymap_hint_entry * get_keymap_hint(); virtual std::string id() const { return "help"; } virtual std::string title(); virtual void finished_qna(operation op); void set_context(const std::string& ctx); private: virtual void process_operation(operation op, bool automatic = false, std::vector * args = NULL); std::string make_colorstring(const std::vector& colors); bool quit; bool apply_search; std::string searchphrase; std::string context; }; } #endif newsbeuter-2.7/include/history.h000066400000000000000000000007211220711462700170440ustar00rootroot00000000000000#ifndef NEWSBEUTER_HISTORY__H #define NEWSBEUTER_HISTORY__H #include #include namespace newsbeuter { class history { public: history(); ~history(); void add_line(const std::string& line); std::string prev(); std::string next(); void load_from_file(const std::string& file); void save_to_file(const std::string& file, unsigned int limit); private: std::vector lines; unsigned int idx; }; } #endif newsbeuter-2.7/include/htmlrenderer.h000066400000000000000000000062311220711462700200400ustar00rootroot00000000000000#ifndef NEWSBEUTER_HTMLRENDERER__H #define NEWSBEUTER_HTMLRENDERER__H #include #include #include #include namespace newsbeuter { enum link_type { LINK_HREF, LINK_IMG, LINK_EMBED }; enum htmltag { TAG_A = 1, TAG_EMBED, TAG_BR, TAG_PRE, TAG_ITUNESHACK, TAG_IMG, TAG_BLOCKQUOTE, TAG_H1, TAG_H2, TAG_H3, TAG_H4, TAG_P, TAG_OL, TAG_UL, TAG_LI, TAG_DT, TAG_DD, TAG_DL, TAG_SUP, TAG_SUB, TAG_HR, TAG_STRONG, TAG_UNDERLINE, TAG_QUOTATION, TAG_SCRIPT, TAG_STYLE, TAG_TABLE, TAG_TH, TAG_TR, TAG_TD }; typedef std::pair linkpair; class htmlrenderer { public: htmlrenderer(unsigned int width = 80, bool raw = false); void render(const std::string&, std::vector& lines, std::vector& links, const std::string& url); void render(std::istream &, std::vector& lines, std::vector& links, const std::string& url); // only public for unit testing purposes: std::string format_ol_count(unsigned int count, char type); struct TableCell { TableCell(size_t s) : span(s) { } size_t span; std::vector text; // multiline cell text }; struct TableRow { TableRow() : inside(false) { } void add_text(const std::string& str); void start_cell(size_t span); void complete_cell(); bool inside; // inside a cell std::vector cells; }; struct Table { Table(bool b) : inside(false), border(b) { } void add_text(const std::string& str); void start_row(); void complete_row(); void start_cell(size_t span); void complete_cell(); bool inside; // inside a row bool border; std::vector rows; }; private: unsigned int w; void prepare_newline(std::string& line, int indent_level); bool line_is_nonempty(const std::string& line); unsigned int add_link(std::vector& links, const std::string& link, link_type type); std::string quote_for_stfl(std::string str); std::string absolute_url(const std::string& url, const std::string& link); std::string type2str(link_type type); std::map tags; void render_table(const Table& table, std::vector& lines); void add_nonempty_line(const std::string& curline, std::vector& tables, std::vector& lines); void add_line(const std::string& curline, std::vector
    & tables, std::vector& lines); std::string get_char_numbering(unsigned int count); std::string get_roman_numbering(unsigned int count); bool raw_; }; } #endif newsbeuter-2.7/include/itemlist_formaction.h000066400000000000000000000055061220711462700214240ustar00rootroot00000000000000#ifndef NEWSBEUTER_ITEMLIST_FORMACTION__H #define NEWSBEUTER_ITEMLIST_FORMACTION__H #include #include #include #include #include namespace newsbeuter { typedef std::pair, unsigned int> itemptr_pos_pair; class itemlist_formaction : public formaction { public: itemlist_formaction(view *, std::string formstr); virtual ~itemlist_formaction(); virtual void prepare(); virtual void init(); virtual void set_redraw(bool b) { formaction::set_redraw(b); apply_filter = !(v->get_cfg()->get_configvalue_as_bool("show-read-articles")); update_visible_items = true; } void set_feed(std::tr1::shared_ptr fd); virtual std::string id() const { return "articlelist"; } virtual std::string title(); inline std::tr1::shared_ptr get_feed() { return feed; } inline void set_pos(unsigned int p) { pos = p; } std::string get_guid(); virtual keymap_hint_entry * get_keymap_hint(); bool jump_to_next_unread_item(bool start_with_first); bool jump_to_previous_unread_item(bool start_with_last); bool jump_to_next_item(bool start_with_first); bool jump_to_previous_item(bool start_with_last); bool jump_to_random_unread_item(); virtual void handle_cmdline(const std::string& cmd); inline void set_update_visible_items(bool b) { update_visible_items = b; } void do_update_visible_items(); virtual void finished_qna(operation op); inline void set_show_searchresult(bool b) { show_searchresult = b; } inline void set_searchphrase(const std::string& s) { searchphrase = s; } virtual void recalculate_form(); void set_regexmanager(regexmanager * r); private: virtual void process_operation(operation op, bool automatic = false, std::vector * args = NULL); void set_head(const std::string& s, unsigned int unread, unsigned int total, const std::string &url); int get_pos(unsigned int idx); void save_article(const std::string& filename, std::tr1::shared_ptr item); void save_filterpos(); void qna_end_setfilter(); void qna_end_editflags(); void qna_start_search(); void handle_cmdline_num(unsigned int idx); std::string gen_flags(std::tr1::shared_ptr item); std::string gen_datestr(time_t t, const char * datetimeformat); void prepare_set_filterpos(); unsigned int pos; std::tr1::shared_ptr feed; bool rebuild_list; bool apply_filter; matcher m; std::vector visible_items; bool update_visible_items; bool show_searchresult; std::string searchphrase; history filterhistory; std::tr1::shared_ptr search_dummy_feed; mutex redraw_mtx; bool set_filterpos; unsigned int filterpos; regexmanager * rxman; unsigned int old_width; int old_itempos; std::string old_sort_order; }; } #endif newsbeuter-2.7/include/itemview_formaction.h000066400000000000000000000033241220711462700214170ustar00rootroot00000000000000#ifndef NEWSBEUTER_ITEMVIEW_FORMACTION__H #define NEWSBEUTER_ITEMVIEW_FORMACTION__H #include #include #include #include namespace newsbeuter { class itemlist_formaction; class itemview_formaction : public formaction { public: itemview_formaction(view *, std::tr1::shared_ptr il, std::string formstr); virtual ~itemview_formaction(); virtual void prepare(); virtual void init(); inline void set_guid(const std::string& guid_) { guid = guid_; } inline void set_feed(std::tr1::shared_ptr fd) { feed = fd; } void set_highlightphrase(const std::string& text); keymap_hint_entry * get_keymap_hint(); virtual void handle_cmdline(const std::string& cmd); virtual std::string id() const { return "article"; } virtual std::string title(); virtual void finished_qna(operation op); std::vector render_html(const std::string& source, std::vector& links, const std::string& feedurl, unsigned int render_width); void set_regexmanager(regexmanager * r); void update_percent(); private: virtual void process_operation(operation op, bool automatic = false, std::vector * args = NULL); void set_head(const std::string& s, unsigned int unread, unsigned int total); void highlight_text(const std::string& searchphrase); void render_source(std::vector& lines, std::string desc, unsigned int width); void do_search(); std::string guid; std::tr1::shared_ptr feed; bool show_source; std::vector links; bool quit; regexmanager * rxman; unsigned int num_lines; std::tr1::shared_ptr itemlist; bool in_search; }; } #endif newsbeuter-2.7/include/keymap.h000066400000000000000000000100201220711462700166220ustar00rootroot00000000000000#ifndef NEWSBEUTER_KEYMAP__H #define NEWSBEUTER_KEYMAP__H #include #include #include #include #include // in configuration: bind-key enum { KM_FEEDLIST = 1<<0, KM_FILEBROWSER = 1<<1, KM_HELP = 1<<2, KM_ARTICLELIST = 1<<3, KM_ARTICLE = 1<<4, KM_TAGSELECT = 1<<5, KM_FILTERSELECT = 1<<6, KM_URLVIEW = 1<<7, KM_PODBEUTER = 1<<8, KM_SYSKEYS = 1<<9, KM_INTERNAL = 1<<10, KM_DIALOGS = 1<<11, KM_NEWSBEUTER = KM_FEEDLIST | KM_FILEBROWSER | KM_HELP | KM_ARTICLELIST | KM_ARTICLE | KM_TAGSELECT | KM_FILTERSELECT | KM_URLVIEW | KM_DIALOGS, KM_BOTH = KM_NEWSBEUTER | KM_PODBEUTER }; namespace newsbeuter { enum operation { OP_NIL = 0, // general and newsbeuter-specific operations: OP_NB_MIN, OP_QUIT, OP_HARDQUIT, OP_RELOAD, OP_RELOADALL, OP_MARKFEEDREAD, OP_MARKALLFEEDSREAD, OP_OPEN, OP_SAVE, OP_NEXTUNREAD, OP_PREVUNREAD, OP_NEXT, OP_PREV, OP_OPENINBROWSER, OP_OPENBROWSER_AND_MARK, OP_HELP, OP_TOGGLESOURCEVIEW, OP_TOGGLEITEMREAD, OP_TOGGLESHOWREAD, OP_SHOWURLS, OP_CLEARTAG, OP_SETTAG, OP_SEARCH, OP_GOTO_URL, OP_ENQUEUE, OP_REDRAW, OP_CMDLINE, OP_SETFILTER, OP_CLEARFILTER, OP_SELECTFILTER, OP_RELOADURLS, OP_BOOKMARK, OP_EDITFLAGS, OP_NEXTUNREADFEED, OP_PREVUNREADFEED, OP_NEXTFEED, OP_PREVFEED, OP_MACROPREFIX, OP_DELETE, OP_PURGE_DELETED, OP_EDIT_URLS, OP_CLOSEDIALOG, OP_VIEWDIALOGS, OP_NEXTDIALOG, OP_PREVDIALOG, OP_PIPE_TO, OP_RANDOMUNREAD, OP_SORT, OP_REVSORT, OP_NB_MAX, // podbeuter-specific operations: OP_PB_MIN = 1000, OP_PB_DOWNLOAD, OP_PB_CANCEL, OP_PB_DELETE, OP_PB_PURGE, OP_PB_TOGGLE_DLALL, OP_PB_MOREDL, OP_PB_LESSDL, OP_PB_PLAY, OP_PB_MARK_FINISHED, OP_PB_MAX, OP_SK_MIN = 1500, OP_SK_UP, OP_SK_DOWN, OP_SK_PGUP, OP_SK_PGDOWN, /* TODO: add more user-defined keys here */ OP_SK_HOME, OP_SK_END, OP_SK_MAX, OP_INT_MIN = 2000, OP_INT_END_CMDLINE, OP_INT_END_SETFILTER, OP_INT_BM_END, OP_INT_EDITFLAGS_END, OP_INT_START_SEARCH, OP_INT_GOTO_URL, OP_INT_END_QUESTION, OP_INT_CANCEL_QNA, OP_INT_QNA_NEXTHIST, OP_INT_QNA_PREVHIST, OP_INT_RESIZE, OP_INT_SET, OP_INT_MAX, OP_1 = 3001, OP_2, OP_3, OP_4, OP_5, OP_6, OP_7, OP_8, OP_9, OP_0 }; struct keymap_desc { std::string key; std::string cmd; std::string desc; std::string ctx; unsigned short flags; }; struct macrocmd { operation op; std::vector args; }; class keymap : public config_action_handler { public: keymap(unsigned int flags); ~keymap(); void set_key(operation op, const std::string& key, const std::string& context); void unset_key(const std::string& key, const std::string& context); operation get_opcode(const std::string& opstr); operation get_operation(const std::string& keycode, const std::string& context); std::vector get_macro(const std::string& key); char get_key(const std::string& keycode); std::string getkey(operation op, const std::string& context); virtual void handle_action(const std::string& action, const std::vector& params); virtual void dump_config(std::vector& config_output); void get_keymap_descriptions(std::vector& descs, unsigned short flags); unsigned short get_flag_from_context(const std::string& context); private: bool is_valid_context(const std::string& context); std::string getopname(operation op); std::map > keymap_; std::map > macros_; }; } #endif newsbeuter-2.7/include/listformatter.h000066400000000000000000000013501220711462700202410ustar00rootroot00000000000000#ifndef LISTFORMATTER__H #define LISTFORMATTER__H #include #include #include #include #include namespace newsbeuter { class listformatter { typedef std::pair line_id_pair; public: listformatter(); ~listformatter(); void add_line(const std::string& text, unsigned int id = UINT_MAX, unsigned int width = 0); void add_lines(const std::vector& lines, unsigned int width = 0); std::string format_list(regexmanager * r = NULL, const std::string& location = ""); inline unsigned int get_lines_count() { return lines.size(); } private: std::vector lines; std::string format_cache; bool refresh_cache; }; } #endif newsbeuter-2.7/include/logger.h000066400000000000000000000015751220711462700166320ustar00rootroot00000000000000#ifndef LOGGER__H #define LOGGER__H #include #include #include namespace newsbeuter { enum loglevel { LOG_NONE = 0, LOG_USERERROR, LOG_CRITICAL, LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG }; class logger { public: static logger &getInstance(); void set_logfile(const char * logfile); void set_errorlogfile(const char * logfile); void set_loglevel(loglevel level); void log(loglevel level, const char * format, ...); private: logger(); logger(const logger &) {} logger& operator=(const logger &) { return *this; } ~logger() { } loglevel curlevel; mutex logMutex; static mutex instanceMutex; std::fstream f; std::fstream ef; }; } // see http://kernelnewbies.org/FAQ/DoWhile0 #ifdef NDEBUG #define LOG(x, ...) do { } while(0) #else #define LOG(x, ...) do { logger::getInstance().log(x, __VA_ARGS__); } while(0) #endif #endif newsbeuter-2.7/include/markreadthread.h000066400000000000000000000006521220711462700203240ustar00rootroot00000000000000#ifndef MARKREADTHREAD_H_ #define MARKREADTHREAD_H_ #include #include namespace newsbeuter { class controller; class markreadthread : public thread { public: markreadthread( ttrss_api* r_api, const std::string& guid, bool read ); virtual ~markreadthread(); protected: virtual void run(); private: ttrss_api* _r_api; const std::string& _guid; bool _read; }; } #endif /*MARKREADTHREAD_H_*/ newsbeuter-2.7/include/matcher.h000066400000000000000000000020341220711462700167650ustar00rootroot00000000000000#ifndef NEWSBEUTER_MATCHER__H #define NEWSBEUTER_MATCHER__H #include namespace newsbeuter { class matchable { public: matchable(); virtual ~matchable(); virtual bool has_attribute(const std::string& attribname) = 0; virtual std::string get_attribute(const std::string& attribname) = 0; }; class matcher { public: matcher(); matcher(const std::string& expr); bool parse(const std::string& expr); bool matches(matchable* item); const std::string& get_parse_error(); const std::string& get_expression(); private: bool matches_r(expression * e, matchable * item); bool matchop_lt(expression * e, matchable * item); bool matchop_gt(expression * e, matchable * item); bool matchop_rxeq(expression * e, matchable * item); bool matchop_cont(expression * e, matchable * item); bool matchop_eq(expression * e, matchable * item); bool matchop_between(expression * e, matchable * item); FilterParser p; bool success; std::string errmsg; std::string exp; }; } #endif newsbeuter-2.7/include/mutex.h000066400000000000000000000006031220711462700165040ustar00rootroot00000000000000#ifndef AK_MUTEX__H #define AK_MUTEX__H #include namespace newsbeuter { class mutex { public: mutex(); ~mutex(); void lock(); void unlock(); bool trylock(); private: pthread_mutex_t mtx; pthread_mutexattr_t attr; friend class condition; }; class scope_mutex { public: scope_mutex(mutex * m); ~scope_mutex(); private: mutex * mtx; }; } #endif newsbeuter-2.7/include/pb_controller.h000066400000000000000000000027101220711462700202070ustar00rootroot00000000000000#ifndef PODBEUTER_CONTROLLER__H #define PODBEUTER_CONTROLLER__H #include #include #include #include #include namespace podbeuter { class pb_view; class queueloader; class pb_controller { public: pb_controller(); ~pb_controller(); inline void set_view(pb_view * vv) { v = vv; } void run(int argc, char * argv[] = 0); inline bool view_update_necessary() const { return view_update_; } inline void set_view_update_necessary(bool b) { view_update_ = b; } std::vector& downloads() { return downloads_; } void usage(const char * argv0); std::string get_dlpath(); unsigned int downloads_in_progress(); void reload_queue(bool remove_unplayed = false); unsigned int get_maxdownloads(); void start_downloads(); void increase_parallel_downloads(); void decrease_parallel_downloads(); double get_total_kbps(); void play_file(const std::string& str); inline newsbeuter::configcontainer * get_cfgcont() { return cfg; } private: bool setup_dirs_xdg(const char *env_home); pb_view * v; std::string config_file; std::string queue_file; newsbeuter::configcontainer * cfg; bool view_update_; std::vector downloads_; std::string config_dir; std::string url_file; std::string cache_file; std::string searchfile; std::string cmdlinefile; unsigned int max_dls; queueloader * ql; }; } #endif newsbeuter-2.7/include/pb_view.h000066400000000000000000000015101220711462700167730ustar00rootroot00000000000000#ifndef PODBEUTER_VIEW__H #define PODBEUTER_VIEW__H #include #include #include using namespace newsbeuter; namespace podbeuter { class pb_controller; struct keymap_hint_entry; class pb_view { public: pb_view(pb_controller * c = 0); ~pb_view(); void run(bool auto_download); void set_keymap(newsbeuter::keymap * k) { keys = k; set_bindings(); } private: friend class newsbeuter::colormanager; struct keymap_hint_entry { operation op; char * text; }; void run_help(); void set_dllist_keymap_hint(); void set_help_keymap_hint(); void set_bindings(); std::string prepare_keymaphint(keymap_hint_entry * hints); pb_controller * ctrl; newsbeuter::stfl::form dllist_form; newsbeuter::stfl::form help_form; newsbeuter::keymap * keys; }; } #endif newsbeuter-2.7/include/poddlthread.h000066400000000000000000000013171220711462700176370ustar00rootroot00000000000000#ifndef PODBEUTER_PODDLTHREAD__H #define PODBEUTER_PODDLTHREAD__H #include #include #include #include #include #include namespace podbeuter { class poddlthread : public newsbeuter::thread { public: poddlthread(download * dl_, newsbeuter::configcontainer *); virtual ~poddlthread(); size_t write_data(void * buffer, size_t size, size_t nmemb); int progress(double dlnow, double dltotal); protected: virtual void run(); double compute_kbps(); private: void mkdir_p(const char * file); download * dl; std::ofstream f; timeval tv1; timeval tv2; size_t bytecount; newsbeuter::configcontainer * cfg; }; } #endif newsbeuter-2.7/include/queueloader.h000066400000000000000000000007171220711462700176630ustar00rootroot00000000000000#ifndef PODBEUTER_QUEUELOADER__H #define PODBEUTER_QUEUELOADER__H #include #include #include namespace podbeuter { class queueloader { public: queueloader(const std::string& file, pb_controller * c = 0); void reload(std::vector& downloads, bool remove_unplayed = false); private: std::string get_filename(const std::string& str); std::string queuefile; pb_controller * ctrl; }; } #endif newsbeuter-2.7/include/regexmanager.h000066400000000000000000000022711220711462700200120ustar00rootroot00000000000000#ifndef REGEXMANAGER__H #define REGEXMANAGER__H #include #include #include #include #include #include #include namespace newsbeuter { class regexmanager : public config_action_handler { public: regexmanager(); ~regexmanager(); virtual void handle_action(const std::string& action, const std::vector& params); virtual void dump_config(std::vector& config_output); void quote_and_highlight(std::string& str, const std::string& location); void remove_last_regex(const std::string& location); int article_matches(matchable * item); private: typedef std::pair, std::vector > rc_pair; std::map locations; std::vector cheat_store_for_dump_config; std::vector, int> > matchers; std::string extract_initial_marker(const std::string& str); public: inline std::vector& get_attrs(const std::string& loc) { return locations[loc].second; } inline std::vector& get_regexes(const std::string& loc) { return locations[loc].first; } }; } #endif newsbeuter-2.7/include/reloadthread.h000066400000000000000000000006611220711462700200040ustar00rootroot00000000000000#ifndef RELOADTHREAD_H_ #define RELOADTHREAD_H_ #include #include #include namespace newsbeuter { class reloadthread : public thread { public: reloadthread(controller * c, configcontainer * cf); virtual ~reloadthread(); protected: virtual void run(); private: controller * ctrl; time_t oldtime; time_t waittime_sec; bool suppressed_first; configcontainer * cfg; }; } #endif newsbeuter-2.7/include/remote_api.h000066400000000000000000000015221220711462700174670ustar00rootroot00000000000000#ifndef NEWSBEUTER_REMOTE_API__H #define NEWSBEUTER_REMOTE_API__H #include #include #include #include #include namespace newsbeuter { typedef std::pair > tagged_feedurl; class remote_api { public: remote_api(configcontainer * c) : cfg(c) { } virtual ~remote_api() { } virtual bool authenticate() = 0; virtual std::vector get_subscribed_urls() = 0; virtual void configure_handle(CURL * handle) = 0; virtual bool mark_all_read(const std::string& feedurl) = 0; virtual bool mark_article_read(const std::string& guid, bool read) = 0; virtual bool update_article_flags(const std::string& oldflags, const std::string& newflags, const std::string& guid) = 0; // TODO protected: configcontainer * cfg; }; } #endif newsbeuter-2.7/include/rss.h000066400000000000000000000174101220711462700161550ustar00rootroot00000000000000#ifndef NEWSBEUTER_RSS__H #define NEWSBEUTER_RSS__H #include #include #include #include #include #include #include #include namespace newsbeuter { typedef std::pair feedurl_expr_pair; enum dl_status { SUCCESS, TO_BE_DOWNLOADED, DURING_DOWNLOAD, DL_ERROR }; class cache; class rss_feed; class rss_item : public matchable { public: rss_item(cache * c); ~rss_item(); std::string title() const; std::string title_raw() const { return title_; } void set_title(const std::string& t); inline const std::string& link() const { return link_; } void set_link(const std::string& l); std::string author() const; std::string author_raw() const { return author_; } void set_author(const std::string& a); std::string description() const; std::string description_raw() const { return description_; } void set_description(const std::string& d); void set_size(unsigned int size); std::string length() const; std::string pubDate() const; inline time_t pubDate_timestamp() const { return pubDate_; } void set_pubDate(time_t t); bool operator<(const rss_item& item) const { return item.pubDate_ < this->pubDate_; } // new items come first inline const std::string& guid() const { return guid_; } void set_guid(const std::string& g); inline bool unread() const { return unread_; } void set_unread(bool u); void set_unread_nowrite(bool u); void set_unread_nowrite_notify(bool u, bool notify); inline void set_cache(cache * c) { ch = c; } inline void set_feedurl(const std::string& f) { feedurl_ = f; } inline const std::string& feedurl() const { return feedurl_; } inline const std::string& enclosure_url() const { return enclosure_url_; } inline const std::string& enclosure_type() const { return enclosure_type_; } void set_enclosure_url(const std::string& url); void set_enclosure_type(const std::string& type); inline bool enqueued() { return enqueued_; } inline void set_enqueued(bool v) { enqueued_ = v; } inline const std::string& flags() const { return flags_; } inline const std::string& oldflags() const { return oldflags_; } void set_flags(const std::string& ff); void update_flags(); void sort_flags(); virtual bool has_attribute(const std::string& attribname); virtual std::string get_attribute(const std::string& attribname); void set_feedptr(std::tr1::shared_ptr ptr); inline std::tr1::shared_ptr get_feedptr() { return feedptr; } inline bool deleted() const { return deleted_; } inline void set_deleted(bool b) { deleted_ = b; } inline void set_index(unsigned int i) { idx = i; } inline unsigned int get_index() { return idx; } inline void set_base(const std::string& b) { base = b; } inline const std::string& get_base() { return base; } inline void set_override_unread(bool b) { override_unread_ = b; } inline bool override_unread() { return override_unread_; } inline void unload() { description_.clear(); } private: std::string title_; std::string link_; std::string author_; std::string description_; time_t pubDate_; std::string guid_; std::string feedurl_; bool unread_; cache * ch; std::string enclosure_url_; std::string enclosure_type_; bool enqueued_; std::string flags_; std::string oldflags_; std::tr1::shared_ptr feedptr; bool deleted_; unsigned int idx; std::string base; bool override_unread_; unsigned int size_; }; class rss_feed : public matchable { public: rss_feed(cache * c); rss_feed(); ~rss_feed(); std::string title_raw() const { return title_; } std::string title() const; inline void set_title(const std::string& t) { title_ = t; utils::trim(title_); } std::string description_raw() const { return description_; } std::string description() const; inline void set_description(const std::string& d) { description_ = d; } inline const std::string& link() const { return link_; } inline void set_link(const std::string& l) { link_ = l; } inline std::string pubDate() const { return "TODO"; } inline void set_pubDate(time_t t) { pubDate_ = t; } bool hidden() const; inline std::vector >& items() { return items_; } inline void add_item(std::tr1::shared_ptr item) { items_.push_back(item); items_guid_map[item->guid()] = item; } inline void clear_items() { items_.clear(); items_guid_map.clear(); } inline void erase_items(std::vector >::iterator begin, std::vector >::iterator end) { for (std::vector >::const_iterator it=begin;it!=end;++it) { items_guid_map.erase((*it)->guid()); } items_.erase(begin, end); } inline void erase_item(std::vector >::iterator pos) { items_guid_map.erase((*pos)->guid()); items_.erase(pos); } std::tr1::shared_ptr get_item_by_guid(const std::string& guid); std::tr1::shared_ptr get_item_by_guid_unlocked(const std::string& guid); inline const std::string& rssurl() const { return rssurl_; } void set_rssurl(const std::string& u); unsigned int unread_item_count(); inline unsigned int total_item_count() const { return items_.size(); } void set_tags(const std::vector& tags); bool matches_tag(const std::string& tag); std::string get_tags(); std::string get_firsttag(); virtual bool has_attribute(const std::string& attribname); virtual std::string get_attribute(const std::string& attribname); void update_items(std::vector > feeds); inline void set_query(const std::string& s) { query = s; } bool is_empty() { return empty; } void set_empty(bool t) { empty = t; } void sort(const std::string& method); void sort_unlocked(const std::string& method); void remove_old_deleted_items(); void purge_deleted_items(); inline void set_rtl(bool b) { is_rtl_ = b; } inline bool is_rtl() { return is_rtl_; } inline void set_index(unsigned int i) { idx = i; } inline unsigned int get_index() { return idx; } inline void set_order(unsigned int x) { order = x; } inline unsigned int get_order() { return order; } void set_feedptrs(std::tr1::shared_ptr self); std::string get_status(); inline void reset_status() { status_ = TO_BE_DOWNLOADED; } inline void set_status(dl_status st) { status_ = st; } void unload(); void load(); mutex item_mutex; // this is ugly, but makes it possible to lock items use e.g. from the cache class private: std::string title_; std::string description_; std::string link_; time_t pubDate_; std::string rssurl_; std::vector > items_; std::tr1::unordered_map > items_guid_map; std::vector tags_; std::string query; cache * ch; bool empty; bool is_rtl_; unsigned int idx; unsigned int order; dl_status status_; }; class rss_ignores : public config_action_handler { public: rss_ignores() { } virtual ~rss_ignores(); virtual void handle_action(const std::string& action, const std::vector& params); virtual void dump_config(std::vector& config_output); bool matches(rss_item * item); bool matches_lastmodified(const std::string& url); bool matches_resetunread(const std::string& url); private: std::vector ignores; std::vector ignores_lastmodified; std::vector resetflag; }; } #endif newsbeuter-2.7/include/rss_parser.h000066400000000000000000000041521220711462700175300ustar00rootroot00000000000000#ifndef RSS_PARSER__H #define RSS_PARSER__H #include #include #include #include namespace newsbeuter { class configcontainer; class cache; class rss_parser { public: rss_parser(const std::string& uri, cache * c, configcontainer *, rss_ignores * ii, remote_api * a = 0); ~rss_parser(); std::tr1::shared_ptr parse(); bool check_and_update_lastmodified(); void set_easyhandle(curl_handle *h) { easyhandle = h; } private: void replace_newline_characters(std::string& str); std::string render_xhtml_title(const std::string& title, const std::string& link); time_t parse_date(const std::string& datestr); void set_rtl(std::tr1::shared_ptr feed, const char * lang); void retrieve_uri(const std::string& uri); void download_http(const std::string& uri); void get_execplugin(const std::string& plugin); void download_filterplugin(const std::string& filter, const std::string& uri); void parse_file(const std::string& file); void fill_feed_fields(std::tr1::shared_ptr feed); void fill_feed_items(std::tr1::shared_ptr feed); void set_item_title(std::tr1::shared_ptr feed, std::tr1::shared_ptr x, rsspp::item& item); void set_item_author(std::tr1::shared_ptr x, rsspp::item& item); void set_item_content(std::tr1::shared_ptr x, rsspp::item& item); void set_item_enclosure(std::tr1::shared_ptr x, rsspp::item& item); std::string get_guid(rsspp::item& item); void add_item_to_feed(std::tr1::shared_ptr feed, std::tr1::shared_ptr item); void handle_content_encoded(std::tr1::shared_ptr x, rsspp::item& item); void handle_itunes_summary(std::tr1::shared_ptr x, rsspp::item& item); bool is_html_type(const std::string& type); void fetch_ttrss(const std::string& feed_id); std::string my_uri; cache * ch; configcontainer *cfgcont; bool skip_parsing; bool is_valid; rss_ignores * ign; rsspp::feed f; remote_api * api; bool is_ttrss; curl_handle *easyhandle; }; } #endif newsbeuter-2.7/include/select_formaction.h000066400000000000000000000021631220711462700210450ustar00rootroot00000000000000#ifndef NEWSBEUTER_select_formaction__H #define NEWSBEUTER_select_formaction__H #include #include namespace newsbeuter { class select_formaction : public formaction { public: enum { SELECTTAG, SELECTFILTER }; select_formaction(view *, std::string formstr); virtual ~select_formaction(); virtual void prepare(); virtual void init(); virtual keymap_hint_entry * get_keymap_hint(); inline std::string get_selected_value() { return value; } inline void set_tags(const std::vector& t) { tags = t; } inline void set_filters(const std::vector& ff) { filters = ff; } void set_type(int t) { type = t; } virtual void handle_cmdline(const std::string& cmd); virtual std::string id() const { return (type == SELECTTAG) ? "tagselection" : "filterselection"; } virtual std::string title(); private: virtual void process_operation(operation op, bool automatic = false, std::vector * args = NULL); bool quit; int type; std::string value; std::vector tags; std::vector filters; }; } #endif newsbeuter-2.7/include/stflpp.h000066400000000000000000000016471220711462700166630ustar00rootroot00000000000000#ifndef STFLPP__H #define STFLPP__H extern "C" { #include } #include namespace newsbeuter { class stfl { public: class form { public: form(const std::string& text); ~form(); const char * run(int timeout); std::string get(const std::string& name); void set(const std::string& name, const std::string& value); std::string get_focus(); void set_focus(const std::string& name); std::string dump(const std::string& name, const std::string& prefix, int focus); void modify(const std::string& name, const std::string& mode, const std::string& text); // std::string lookup(const std::string& path, const std::string& newname); private: stfl_form * f; stfl_ipool * ipool; }; // static std::string error(); // static void error_action(const std::string& mode); static void reset(); static std::string quote(const std::string& text); }; } #endif newsbeuter-2.7/include/tagsouppullparser.h000066400000000000000000000020431220711462700211360ustar00rootroot00000000000000#ifndef tagsouppullparser_H_ #define tagsouppullparser_H_ #include #include #include namespace newsbeuter { class tagsouppullparser { public: enum event { START_DOCUMENT, END_DOCUMENT, START_TAG, END_TAG, TEXT }; tagsouppullparser(); virtual ~tagsouppullparser(); void setInput(std::istream& is); std::string getAttributeValue(const std::string& name) const; event getEventType() const; std::string getText() const; event next(); private: typedef std::pair attribute; std::vector attributes; std::string text; std::istream * inputstream; event current_event; void skip_whitespace(); void add_attribute(std::string s); std::string read_tag(); event determine_tag_type(); std::string decode_attribute(const std::string& s); std::string decode_entities(const std::string& s); std::string decode_entity(std::string s); void parse_tag(const std::string& tagstr); void handle_tag(); void handle_text(); std::string ws; char c; }; } #endif /*tagsouppullparser_H_*/ newsbeuter-2.7/include/thread.h000066400000000000000000000007251220711462700166160ustar00rootroot00000000000000#ifndef AK_THREAD__H #define AK_THREAD__H #include namespace newsbeuter { class thread; void * run_thread(void * p); // TODO: implement an option to provide attributes class thread { public: thread(); virtual ~thread(); pthread_t start(); void join(); protected: virtual void run() = 0; void detach(); friend void * run_thread(void * p); private: static void cleanup(thread * p); pthread_t pt; }; } #endif newsbeuter-2.7/include/ttrss_api.h000066400000000000000000000032351220711462700173560ustar00rootroot00000000000000#ifndef NEWSBEUTER_TTRSS_API__H #define NEWSBEUTER_TTRSS_API__H #include #include #include #include namespace newsbeuter { class ttrss_api : public remote_api { public: ttrss_api(configcontainer * c); virtual ~ttrss_api(); virtual bool authenticate(); virtual struct json_object * run_op(const std::string& op, const std::map& args, bool try_login = true); virtual std::vector get_subscribed_urls(); virtual void configure_handle(CURL * handle); virtual bool mark_all_read(const std::string& feedurl); virtual bool mark_article_read(const std::string& guid, bool read); virtual bool update_article_flags(const std::string& oldflags, const std::string& newflags, const std::string& guid); rsspp::feed fetch_feed(const std::string& id); bool update_article(const std::string& guid, int mode, int field); private: void fetch_feeds_per_category(struct json_object * cat, std::vector& feeds); bool star_article(const std::string& guid, bool star); bool publish_article(const std::string& guid, bool publish); std::string url_to_id(const std::string& url); std::string retrieve_sid(); std::string sid; std::string auth_info; const char * auth_info_ptr; bool single; mutex auth_lock; }; class ttrss_urlreader : public urlreader { public: ttrss_urlreader(configcontainer * c, const std::string& url_file, remote_api * a); virtual ~ttrss_urlreader(); virtual void write_config(); virtual void reload(); virtual std::string get_source(); private: configcontainer * cfg; std::string file; remote_api * api; }; } #endif newsbeuter-2.7/include/urlreader.h000066400000000000000000000027661220711462700173430ustar00rootroot00000000000000#ifndef NEWSBEUTER_CONFIGREADER__H #define NEWSBEUTER_CONFIGREADER__H #include #include #include #include #include #include namespace newsbeuter { class urlreader { public: urlreader(); virtual ~urlreader(); virtual void write_config() = 0; virtual void reload() = 0; virtual std::string get_source() = 0; std::vector& get_urls(); std::vector& get_tags(const std::string& url); std::vector get_alltags(); inline void set_offline(bool off) { offline = off; } protected: std::vector urls; std::map > tags; std::set alltags; bool offline; }; class file_urlreader : public urlreader { public: file_urlreader(const std::string& file = ""); virtual ~file_urlreader(); virtual void write_config(); virtual void reload(); void load_config(const std::string& file); virtual std::string get_source(); private: std::string filename; }; class opml_urlreader : public urlreader { public: opml_urlreader(configcontainer * c); virtual ~opml_urlreader(); virtual void write_config(); virtual void reload(); virtual std::string get_source(); protected: virtual void handle_node(xmlNode * node, const std::string& tag); virtual const char * get_auth(); configcontainer * cfg; private: void rec_find_rss_outlines(xmlNode * node, std::string tag); }; } #endif newsbeuter-2.7/include/urlview_formaction.h000066400000000000000000000014241220711462700212620ustar00rootroot00000000000000#ifndef NEWSBEUTER_URLVIEW_FORMACTION__H #define NEWSBEUTER_URLVIEW_FORMACTION__H #include #include namespace newsbeuter { class urlview_formaction : public formaction { public: urlview_formaction(view *, std::string formstr); virtual ~urlview_formaction(); virtual void prepare(); virtual void init(); virtual keymap_hint_entry * get_keymap_hint(); inline void set_links(const std::vector& l) { links = l; } virtual std::string id() const { return "urlview"; } virtual std::string title(); virtual void handle_cmdline(const std::string& cmd); private: virtual void process_operation(operation op, bool automatic = false, std::vector * args = NULL); std::vector links; bool quit; }; } #endif newsbeuter-2.7/include/utils.h000066400000000000000000000110661220711462700165070ustar00rootroot00000000000000#ifndef UTIL_H_ #define UTIL_H_ #include #include #include #include #include #include #include namespace newsbeuter { // wrapped curl handle for exception safety and so on // see also: https://github.com/gsauthof/ccurl class curl_handle { private: CURL *h; curl_handle(const curl_handle &); curl_handle &operator=(const curl_handle &); public: curl_handle() : h(0) { h = curl_easy_init(); if (!h) throw std::runtime_error("Can't obtain curl handle"); } ~curl_handle() { curl_easy_cleanup(h); } CURL *ptr() { return h; } }; class utils { public: static std::vector tokenize(const std::string& str, std::string delimiters = " \r\n\t"); static std::vector tokenize_spaced(const std::string& str, std::string delimiters = " \r\n\t"); static std::vector tokenize_nl(const std::string& str, std::string delimiters = "\r\n"); static std::vector tokenize_quoted(const std::string& str, std::string delimiters = " \r\n\t"); static std::vector wtokenize(const std::wstring& str, std::wstring delimiters = L" \r\n\t"); static bool try_fs_lock(const std::string& lock_file, pid_t & pid); static void remove_fs_lock(const std::string& lock_file); static std::string convert_text(const std::string& text, const std::string& tocode, const std::string& fromcode); static std::string get_command_output(const std::string& cmd); static void extract_filter(const std::string& line, std::string& filter, std::string& url); static std::string retrieve_url(const std::string& url, configcontainer * cfgcont = NULL, const char * authinfo = NULL, const std::string* postdata = NULL); static void run_command(const std::string& cmd, const std::string& param); // used for notifications only static std::string run_program(char * argv[], const std::string& input); static std::string resolve_tilde(const std::string& ); static std::string replace_all(std::string str, const std::string& from, const std::string& to); static std::wstring str2wstr(const std::string& str); static std::string wstr2str(const std::wstring& wstr); static std::wstring clean_nonprintable_characters(std::wstring text); static std::wstring utf8str2wstr(const std::string& utf8str); template static std::string to_string(T var); static std::string absolute_url(const std::string& url, const std::string& link); static std::string strprintf(const char * format, ...); static std::string get_useragent(configcontainer * cfgcont); static size_t strwidth(const std::string& s); static size_t strwidth_stfl(const std::string& str); static size_t wcswidth_stfl(const std::wstring& str, size_t size); static inline unsigned int max(unsigned int a, unsigned int b) { return (a > b) ? a : b; } static unsigned int to_u(const std::string& str); static bool is_valid_color(const std::string& color); static bool is_valid_attribute(const std::string& attrib); static std::vector > partition_indexes(unsigned int start, unsigned int end, unsigned int parts); static std::string join(const std::vector& strings, const std::string& separator); static std::string censor_url(const std::string& url); static std::string quote_for_stfl(std::string str); static void trim_end(std::string& str); static void trim(std::string& str); static std::string quote(const std::string& str); static unsigned int get_random_value(unsigned int max); static std::string quote_if_necessary(const std::string& str); static void set_common_curl_options(CURL * handle, configcontainer * cfg); static curl_proxytype get_proxy_type(const std::string& type); static unsigned long get_auth_method(const std::string& type); static bool is_special_url(const std::string& url); static bool is_http_url(const std::string& url); static std::string get_content(xmlNode * node); static std::string get_prop(xmlNode * node, const char * prop, const char * ns = NULL); static std::string escape_url(const std::string& url); static std::string unescape_url(const std::string& url); static void initialize_ssl_implementation(void); private: static void append_escapes(std::string& str, char c); }; class scope_measure { public: scope_measure(const std::string& func, loglevel ll = LOG_DEBUG); ~scope_measure(); void stopover(const std::string& son = ""); private: struct timeval tv1, tv2; std::string funcname; loglevel lvl; }; } #endif /*UTIL_H_*/ newsbeuter-2.7/include/view.h000066400000000000000000000117041220711462700163200ustar00rootroot00000000000000#ifndef NEWSBEUTER_VIEW__H #define NEWSBEUTER_VIEW__H #include #include #include #include #include #include #include #include #include #include #include #include #include namespace newsbeuter { class formaction; class itemlist_formaction; class itemview_formaction; class view { public: view(controller *); ~view(); void run(); std::string run_modal(std::tr1::shared_ptr f, const std::string& value = ""); void set_feedlist(std::vector > feeds); void update_visible_feeds(std::vector > feeds); void set_keymap(keymap * k); void set_config_container(configcontainer * cfgcontainer); void show_error(const std::string& msg); void set_status(const std::string& msg); void set_status_unlocked(const std::string& msg); inline controller * get_ctrl() { return ctrl; } inline configcontainer * get_cfg() { return cfg; } inline keymap * get_keys() { return keys; } void set_tags(const std::vector& t); void push_empty_formaction(); void pop_current_formaction(); void remove_formaction(unsigned int pos); void set_current_formaction(unsigned int pos); inline unsigned int formaction_stack_size() { return formaction_stack.size(); } char confirm(const std::string& prompt, const std::string& charset); void push_itemlist(unsigned int pos); void push_itemlist(std::tr1::shared_ptr feed); void push_itemview(std::tr1::shared_ptr f, const std::string& guid, const std::string& searchphrase = ""); void push_help(); void push_urlview(const std::vector& links); void push_searchresult(std::tr1::shared_ptr feed, const std::string& phrase = ""); void view_dialogs(); std::string run_filebrowser(const std::string& default_filename = "", const std::string& dir = ""); std::string select_tag(const std::vector& tags); std::string select_filter(const std::vector& filters); void open_in_browser(const std::string& url); void open_in_pager(const std::string& filename); std::string get_filename_suggestion(const std::string& s); bool get_next_unread(itemlist_formaction * itemlist, itemview_formaction * itemview = NULL); bool get_previous_unread(itemlist_formaction * itemlist, itemview_formaction * itemview = NULL); bool get_next(itemlist_formaction * itemlist, itemview_formaction * itemview = NULL); bool get_previous(itemlist_formaction * itemlist, itemview_formaction * itemview = NULL); bool get_random_unread(itemlist_formaction * itemlist, itemview_formaction * itemview = NULL); bool get_next_unread_feed(itemlist_formaction * itemlist); bool get_prev_unread_feed(itemlist_formaction * itemlist); bool get_next_feed(itemlist_formaction * itemlist); bool get_prev_feed(itemlist_formaction * itemlist); void prepare_query_feed(std::tr1::shared_ptr feed); void force_redraw(); void set_colors(std::map& fg_colors, std::map& bg_colors, std::map >& attributes); void notify_itemlist_change(std::tr1::shared_ptr feed); void feedlist_mark_pos_if_visible(unsigned int pos); void set_regexmanager(regexmanager * r); std::vector > get_formaction_names(); std::tr1::shared_ptr get_current_formaction(); std::tr1::shared_ptr get_formaction(unsigned int idx) const { return formaction_stack[idx]; } void goto_next_dialog(); void goto_prev_dialog(); void apply_colors_to_all_formactions(); void update_bindings(); void inside_qna(bool f); void inside_cmdline(bool f); void dump_current_form(); protected: void set_bindings(std::tr1::shared_ptr fa); void apply_colors(std::tr1::shared_ptr fa); void handle_cmdline_completion(std::tr1::shared_ptr fa); void clear_line(std::tr1::shared_ptr fa); void clear_eol(std::tr1::shared_ptr fa); void cancel_input(std::tr1::shared_ptr fa); void delete_word(std::tr1::shared_ptr fa); controller * ctrl; configcontainer * cfg; keymap * keys; mutex * mtx; friend class colormanager; std::vector > formaction_stack; unsigned int current_formaction; std::vector tags; unsigned int feeds_shown; regexmanager * rxman; std::map fg_colors; std::map bg_colors; std::map > attributes; bool is_inside_qna; bool is_inside_cmdline; std::string last_fragment; unsigned int tab_count; std::vector suggestions; }; } #endif newsbeuter-2.7/mk/000077500000000000000000000000001220711462700141565ustar00rootroot00000000000000newsbeuter-2.7/mk/libbeuter.deps000066400000000000000000000003211220711462700170040ustar00rootroot00000000000000src/configcontainer.cpp src/configparser.cpp src/colormanager.cpp src/keymap.cpp src/stflpp.cpp src/logger.cpp src/exception.cpp src/mutex.cpp src/utils.cpp src/thread.cpp src/matcher.cpp src/formatstring.cpp newsbeuter-2.7/mk/mk.deps000066400000000000000000000104511220711462700154430ustar00rootroot00000000000000src/cache.o: include/cache.h include/configcontainer.h include/utils.h src/colormanager.o: include/logger.h include/colormanager.h include/pb_view.h \ include/feedlist_formaction.h include/itemlist_formaction.h include/itemview_formaction.h \ include/help_formaction.h include/filebrowser_formaction.h include/urlview_formaction.h \ include/select_formaction.h src/configcontainer.o: include/configcontainer.h include/configparser.h include/logger.h \ include/utils.h src/configparser.o: include/configparser.h include/tagsouppullparser.h include/exceptions.h \ include/utils.h include/logger.h config.h src/controller.o: include/view.h include/controller.h include/configparser.h \ include/configcontainer.h include/exceptions.h include/downloadthread.h \ include/colormanager.h include/logger.h include/utils.h include/stflpp.h \ config.h xlicense.h src/download.o: include/download.h include/pb_controller.h config.h src/downloadthread.o: include/downloadthread.h include/logger.h src/exception.o: include/exception.h include/exceptions.h src/feedlist_formaction.o: include/feedlist_formaction.h include/view.h include/logger.h \ include/reloadthread.h include/exceptions.h include/utils.h include/formatstring.h \ include/listformatter.h src/dialogs_formaction.o: include/dialogs_formaction.h include/view.h config.h src/filebrowser_formaction.o: include/filebrowser_formaction.h include/logger.h config.h \ include/view.h src/filtercontainer.o: include/filtercontainer.h src/formaction.o: include/formaction.h include/view.h include/utils.h config.h \ include/logger.h src/help_formaction.o: config.h include/help_formaction.h include/view.h include/listformatter.h src/history.o: include/history.h src/htmlrenderer.o: include/htmlrenderer.h include/tagsouppullparser.h include/utils.h \ include/logger.h config.h src/itemlist_formaction.o: include/itemlist_formaction.h include/view.h config.h \ include/exceptions.h include/utils.h include/formatstring.h include/listformatter.h src/itemview_formaction.o: include/itemview_formaction.h include/view.h config.h \ include/logger.h include/exceptions.h include/utils.h src/keymap.o: include/keymap.h include/logger.h config.h src/logger.o: include/logger.h include/exception.h src/matcher.o: include/matcher.h include/logger.h include/utils.h include/exceptions.h src/mutex.o: include/mutex.h src/pb_controller.o: include/pb_controller.h include/pb_view.h include/poddlthread.h \ include/utils.h config.h include/keymap.h include/configcontainer.h include/colormanager.h \ include/exceptions.h include/queueloader.h include/logger.h src/pb_view.o: include/pb_view.h include/pb_controller.h include/poddlthread.h include/download.h \ config.h include/logger.h stfl/dllist.h stfl/help.h src/poddlthread.o: include/poddlthread.h include/logger.h config.h src/queueloader.o: include/queueloader.h include/logger.h config.h src/reloadthread.o: include/reloadthread.h include/logger.h src/rss.o: include/rss.h config.h include/cache.h include/tagsouppullparser.h include/utils.h \ include/logger.h include/exceptions.h include/configcontainer.h src/select_formaction.o: include/select_formaction.h include/view.h config.h include/listformatter.h src/stflpp.o: include/stflpp.h include/logger.h include/exception.h src/thread.o: include/thread.h include/exception.h include/logger.h src/urlreader.o: include/urlreader.h include/utils.h include/logger.h config.h src/urlview_formaction.o: include/urlview_formaction.h include/view.h config.h include/listformatter.h src/utils.o: include/utils.h include/logger.h src/view.o: stfl/feedlist.h stfl/itemlist.h stfl/itemview.h stfl/help.h stfl/filebrowser.h stfl/urlview.h stfl/selecttag.h \ include/formaction.h include/feedlist_formaction.h include/itemlist_formaction.h \ include/itemview_formaction.h include/help_formaction.h include/urlview_formaction.h \ include/select_formaction.h include/logger.h include/reloadthread.h \ include/exception.h include/exceptions.h include/keymap.h stfl/dialogs.h src/tagsouppullparser.o: include/tagsouppullparser.h include/exceptions.h include/utils.h \ include/logger.h config.h src/formatstring.o: include/formatstring.h src/interpreter.o: include/interpreter.h src/rss_parser.o: include/rss_parser.h include/configcontainer.h include/cache.h include/rss.h src/ttrss_api.o: include/ttrss_api.h newsbeuter-2.7/mk/newsbeuter.deps000066400000000000000000000012151220711462700172150ustar00rootroot00000000000000newsbeuter.cpp src/cache.cpp src/htmlrenderer.cpp src/urlreader.cpp src/logger.cpp src/view.cpp src/controller.cpp src/reloadthread.cpp src/tagsouppullparser.cpp src/downloadthread.cpp src/rss.cpp src/rss_parser.cpp src/formaction.cpp src/feedlist_formaction.cpp src/itemlist_formaction.cpp src/itemview_formaction.cpp src/help_formaction.cpp src/filebrowser_formaction.cpp src/urlview_formaction.cpp src/select_formaction.cpp src/history.cpp src/filtercontainer.cpp src/listformatter.cpp src/regexmanager.cpp src/dialogs_formaction.cpp src/googlereader_urlreader.cpp src/google_api.cpp src/ttrss_api.cpp src/ttrss_urlreader.cpp src/markreadthread.cpp newsbeuter-2.7/mk/podbeuter.deps000066400000000000000000000001551220711462700170250ustar00rootroot00000000000000podbeuter.cpp src/pb_controller.cpp src/pb_view.cpp src/download.cpp src/queueloader.cpp src/poddlthread.cpp newsbeuter-2.7/newsbeuter.cpp000066400000000000000000000012131220711462700164330ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include using namespace newsbeuter; int main(int argc, char * argv[]) { utils::initialize_ssl_implementation(); if (!setlocale(LC_CTYPE,"") || !setlocale(LC_MESSAGES,"")) { std::cerr << "setlocale failed: " << strerror(errno) << std::endl; return 1; } bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); rsspp::parser::global_init(); controller c; newsbeuter::view v(&c); c.set_view(&v); c.run(argc,argv); rsspp::parser::global_cleanup(); return 0; } newsbeuter-2.7/po/000077500000000000000000000000001220711462700141655ustar00rootroot00000000000000newsbeuter-2.7/po/de.po000066400000000000000000001144521220711462700151240ustar00rootroot00000000000000# German translation for newsbeuter. # Copyright (C) Andreas Krennmair # This file is distributed under the same license as the newsbeuter package. # Andreas Krennmair , 2007-2008 # #, fuzzy msgid "" msgstr "" "Project-Id-Version: newsbeuter 0.3\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2007-02-21 13:03+0100\n" "Last-Translator: Andreas Krennmair \n" "Language-Team: Andreas Krennmair \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "`%s' ist keine gültige Farbe" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, c-format msgid "`%s' is not a valid attribute" msgstr "`%s' ist kein gültiges Attribut" #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "`%s' ist kein gültiges Konfigurationselement" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "" "newsbeuter: neuladen beendet, %f ungelesene Feeds (%n ungelesene Artikel " "insgesamt)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - Ihre Feeds (%u ungelesen, %t gesamt)%?T? - Tag `%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - Artikel im Feed '%T' (%u ungelesen, %t gesamt) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - Suchergebnisse (%u ungelesen, %t gesamt)" #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?Datei öffnen&Datei speichern? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - Hilfe" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - Tag auswählen" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - Filter auswählen" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - Artikel '%T'" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - URLs" #: src/configcontainer.cpp:111 msgid "%N %V - Dialogs" msgstr "%N %V - Dialoge" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "erwartete Boolschen Wert, fand stattdessen `%s'" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "erwartete Integerwert, fand stattdessen `%s'" #: src/configcontainer.cpp:159 #, c-format msgid "invalid configuration value `%s'" msgstr "Ungültiger Konfigurationswert `%s'" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "Fehler beim Bearbeiten von Kommando `%s' (%s Zeile %u): %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "unbekanntes Kommando `%s'" #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "Schwerer Fehler: konnte das Home-Verzeichnis nicht feststellen!" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "" "Bitte setzen Sie die HOME Umgebungsvariable oder fügen Sie einen gültigen " "Benutzer für UID %u hinzu!" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: unbekannte Option - %c" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "Starte %s %s..." #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "Fehler: eine Instanz von %s läuft bereits (PID: %u)" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "Lade Konfiguration..." #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "fertig." #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "Öffne Zwischenspeicher..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "Fehler: das Öffnen der Zwischenspeicherdatei `%s' schlug fehl: %s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "Lade Artikel aus dem Zwischenspeicher..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "Lade URLs von %s..." #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "" "Fehler: keine URLs konfiguriert. Bitte füllen Sie die Datei %s mit RSS-Feed-" "URLs oder importieren Sie eine OPML-Datei." #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "" "Es sieht so aus als würde die konfigurierte OPML-Datei keine Feeds " "enthalten. Bitte füllen Sie diese mit Feeds, und probieren Sie es erneut." #: src/controller.cpp:392 msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" "Es sieht so aus als hätten Sie keine Feeds in Ihrem Google-Reader-Account " "konfiguriert. Bitte tun Sie das, und probieren Sie es erneut." #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "Lade Artikel aus dem Zwischenspeicher..." #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "Bereinige Zwischenspeicher gründlich..." #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "Fehler beim Laden der Feeds aus der Datenbank: " #: src/controller.cpp:430 #, c-format msgid "Error while loading feed '%s': %s" msgstr "Fehler beim Laden von Feed`%s': %s" #: src/controller.cpp:448 msgid "Prepopulating query feeds..." msgstr "Query-Feed vorbefüllen..." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "Importiere Liste von gelesenen Artikeln..." #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "Exportierte Liste von gelesenen Artikeln..." #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "Bereinige Zwischenspeicher..." #: src/controller.cpp:523 msgid "failed: " msgstr "fehlgeschlagen: " #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "Fehler: konnte nicht alle Feeds gelesen markieren: %s" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%sLade %s..." #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "Fehler beim Abholen von %s: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "Fehler: ungültiger Feed!" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "ungültiger Feed-Index (Bug)" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "" "newsbeuter ist Freie Software und unter der MIT/X Consortium License " "lizenziert." #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "Für mehr Information `%s -vv' eingeben." #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" "%s %s\n" "Verwendung: %s [-i |-e] [-u ] [-c ] [-h]\n" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "exportiere OPML-Feed auf die Standardausgabe" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "Feeds beim Start neu laden" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 msgid "" msgstr "" #: src/controller.cpp:842 msgid "import OPML file" msgstr "OPML-Datei importieren" #: src/controller.cpp:843 msgid "" msgstr "" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "RSS-Feed URLs aus lesen" #: src/controller.cpp:844 msgid "" msgstr "" #: src/controller.cpp:844 msgid "use as cache file" msgstr " als Zwischenspeicherdatei verwenden" #: src/controller.cpp:845 msgid "" msgstr "" #: src/controller.cpp:845 msgid "read configuration from " msgstr "Konfiguration aus lesen" #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "Zwischenspeicher gründlich aufräumen" #: src/controller.cpp:847 msgid "..." msgstr "..." #: src/controller.cpp:847 msgid "execute list of commands" msgstr "Führe eine Liste von Kommandos aus" #: src/controller.cpp:848 msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "Offline-Modus aktivieren (nur im Google Reader Synchronisationsmodus)" #: src/controller.cpp:849 msgid "quiet startup" msgstr "ruhiger Start" #: src/controller.cpp:850 msgid "get version information" msgstr "Versionsinformation anzeigen" #: src/controller.cpp:851 msgid "" msgstr "" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "" "Schreibe eine Logdatei mit einem bestimmten Loglevel (gültige Werte: 1 bis 6)" #: src/controller.cpp:852 msgid "" msgstr "" #: src/controller.cpp:852 msgid "use as output log file" msgstr "Verwende als Ausgabe-Logdatei" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "Exportiere Liste von gelesenen Artikeln nach " #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "Importiere Liste von gelesenen Artikeln aus " #: src/controller.cpp:855 msgid "this help" msgstr "diese Hilfe" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "Ein Fehler ist beim Parsen von %s aufgetreten." #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "Import von %s fertig." #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "" "Die Lesezeichen-Unterstützung ist nicht konfiguriert. Bitte setzen Sie die " "Konfigurationsvariable `bookmark-cmd' entsprechend." #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u ungelesene Artikel" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "Titel: " #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "Autor: " #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "Datum: " #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "Link: " #: src/controller.cpp:1388 #, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "Fehler: konnte Konfigurationsdatei `%s' nicht öffnen!" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "Schließen" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "Gehe zu Dialog" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "Dialog schließen" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "Kein Element ausgewählt!" #: src/dialogs_formaction.cpp:74 msgid "Error: you can't remove the feed list!" msgstr "Fehler: Sie können die Feedliste nicht entfernen!" #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "Ungültige Position!" #: src/download.cpp:42 msgid "queued" msgstr "in Warteschlange" #: src/download.cpp:44 msgid "downloading" msgstr "wird herunterladen" #: src/download.cpp:46 msgid "cancelled" msgstr "abgebrochen" #: src/download.cpp:48 msgid "deleted" msgstr "gelöscht" #: src/download.cpp:50 msgid "finished" msgstr "fertig" #: src/download.cpp:52 msgid "failed" msgstr "fehlgeschlagen" #: src/download.cpp:54 msgid "incomplete" msgstr "unvollständig" #: src/download.cpp:56 msgid "played" msgstr "abgespielt" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "unbekannt (Bug)." #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "Attribut `%s' is not verfügbar." #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "regulärer Ausdrück '%s' ist ungültig: %s" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "ungültige Parameter." #: src/exception.cpp:43 msgid "too few parameters." msgstr "zu wenige Parameter." #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "unbekanntes Kommando (Bug)." #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "Datei konnte nicht geöffnet werden." #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "unbekannter Fehler (Bug)." #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "Kein Feed ausgewählt!" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "" "Sortieren nach (e)rstemtag/(t)itel/(a)rtikelzahl/(u)ngeleseneartikel/(n)" "ichts?" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "etaun" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "e" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "t" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "a" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "u" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "n" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "" "Umgekehrt sortieren nach (e)rstemtag/(t)itel/(a)rtikelzahl/(u)" "ngeleseneartikel/(n)ichts?" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "Markiere Feed als gelesen..." #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "Fehler: konnte Feed nicht gelesen markieren: %s" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "Keine Feeds mit ungelesenen Elementen." #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "Bereits beim letzten Feed." #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "Bereits beim ersten Feed." #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "Markiere alle Feeds als gelesen..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "Keine Tags definiert." #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "Fehler: konnte Filterkommando `%s' nicht parsen: %s" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "Keine Filter definiert." #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "Suche nach: " #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "Filter: " #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "Wollen Sie wirklich beenden (j:Ja n:Nein)? " #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "jn" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "j" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "Beenden" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "Öffnen" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "Nächstes Ungelesenes" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "Neu laden" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "Alle Neu laden" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "Gelesen Markieren" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "Alle Aufholen" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "Suchen" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "Hilfe" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "Fehler: konnte Filterkommando nicht parsen!" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "Suche..." #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "Fehler beim Suchen nach `%s': %s" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "Keine Ergebnisse." #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "Position nicht sichtbar!" #: src/feedlist_formaction.cpp:774 #, c-format msgid "Feed List - %u unread, %u total" msgstr "Feedliste - %u ungelesen, %u gesamt" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "Wollen Sie wirklich `%s' überschreiben (y:Ja n:Nein)? " #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "Datei: " #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - Datei öffnen - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - Datei speichern - %s" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "Abbrechen" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "Speichern" #: src/filebrowser_formaction.cpp:271 #, c-format msgid "Open File - %s" msgstr "Datei öffnen - %s" #: src/filebrowser_formaction.cpp:273 #, c-format msgid "Save File - %s" msgstr "Datei speichern - %s" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "Fehler: konnte Filterkommando `%s' nicht parsen: %s" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "Verwendung: set [=]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "Verwendung: source [...]" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "Verwendung: dumpconfig [...]" #: src/formaction.cpp:231 #, c-format msgid "Saved configuration to %s" msgstr "Konfiguration nach %s gespeichert" #: src/formaction.cpp:236 #, c-format msgid "Not a command: %s" msgstr "Kein Kommando: `%s'" #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "Speichere Lesezeichen..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "Lesezeichen gespeichert." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "Fehler beim Speichern des Lesezeichens: " #: src/formaction.cpp:303 msgid "URL: " msgstr "URL: " #: src/formaction.cpp:305 msgid "Description: " msgstr "Beschreibung: " #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "Personen, deren regelmäßiger Leser Sie sind" #: src/googlereader_urlreader.cpp:34 msgid "Starred items" msgstr "Markierte Artikel" #: src/googlereader_urlreader.cpp:35 msgid "Shared items" msgstr "Empfohlene Artikel" #: src/googlereader_urlreader.cpp:36 msgid "Popular items" msgstr "Populäre Artikel" #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "Allgemeine Tastenbelegungen:" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "Unbelegte Funktionen:" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "Löschen" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "eingebettetes Flash: " #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "Bild" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "Links: " #: src/htmlrenderer.cpp:594 msgid "link" msgstr "Link" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "eingebettetes Flash" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "unbekannt (Bug)." #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "Schalte Gelesen-Flag für Artikel um..." #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "Fehler beim Umschalten des Gelesen-Flag: %s" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "URL-Liste leer." #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "Flags: " #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "Fehler: kein Element ausgewählt!" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "Fehler: Sie können Suchergebnisse nicht neu laden." #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "Keine ungelesenen Elemente." #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "Bereits beim letzten Artikel." #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "Bereits beim ersten Artikel." #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "Keine ungelesenen Feeds." #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "Artikel zu Kommando umleiten: " #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "Sortieren nach (d)atum/(t)itel/(f)lags/(a)utor/(l)ink/(g)uid?" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 msgid "dtfalg" msgstr "dtfalg" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "d" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "l" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "g" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" "Umgekehrt sortieren nach (d)atum/(t)itel/(f)lags/(a)utor/(l)ink/(g)uid?" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "Flags aktualisiert." #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "Alle Gelesen Markieren" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "Speichern abgebrochen." #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "Artikel nach %s gespeichert" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "Fehler: konnte Artikel nicht nach %s speichern" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "Suchergebnis - '%s'" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "Query-Feed - %s" #: src/itemlist_formaction.cpp:1004 #, c-format msgid "Article List - %s" msgstr "Artikelliste - %s" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "Anfang" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "Ende" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "Feed: " #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "Podcast Download URL: " #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "Typ: " #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "Fehler beim als gelesen markieren des Artikels: %s" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "%s zur Download-Warteschlange hinzugefügt." #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "Ungültige URL: '%s'" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "Artikel nach %s gespeichert." #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "Fehler: konnte Artikel nicht nach %s speichern" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "Starte Browser..." #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "Fehler beim als ungelesen markieren des Artikels: %s" #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "Gehe zu URL #" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "Im Browser öffnen" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "In Warteschlange" #: src/itemview_formaction.cpp:586 #, c-format msgid "Article - %s" msgstr "Artikel - %s" #: src/itemview_formaction.cpp:624 msgid "Error: invalid regular expression!" msgstr "Fehler: ungültiger regulärer Ausdruck!" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "Feed/Artikel öffnen" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "Zum vorherigen Dialog zurückkehren/Beenden" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "Programm beenden, keine Bestätigung" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "Aktuell ausgewählten Feed neu laden" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "Alle Feeds neu laden" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "Feed als gelesen markieren" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "Alle Feeds als gelesen markieren" #: src/keymap.cpp:30 msgid "Save article" msgstr "Artikel speichern" #: src/keymap.cpp:31 msgid "Go to next article" msgstr "Zum nächsten Artikel gehen" #: src/keymap.cpp:32 msgid "Go to previous article" msgstr "Zum vorhergehenden Artikel gehen" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "Zum nächsten ungelesenen Artikel gehen" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "Zum vorhergehenden ungelesenen Artikel gehen" #: src/keymap.cpp:35 msgid "Go to a random unread article" msgstr "Zum einem zufälligen ungelesenen Artikel gehen" #: src/keymap.cpp:36 msgid "Open article in browser and mark read" msgstr "Artikel im Browser öffnen and als gelesen markieren" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "Artikel im Browser öffnen" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "Hilfe-Dialog öffnen" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "Quellansicht umschalten" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "Gelesen-Status für Artikel umschalten" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "Ansicht der gelesenen Feeds/Artikel umschalten" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "URLs im aktuellen Artikel zeigen" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "Aktuellen Tag löschen" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "Tag auswählen" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "Suchdialog öffnen" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "Download zur Warteschlange hinzufügen" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "Liste der URLs aus der Konfiguration neuladen" #: src/keymap.cpp:50 msgid "Download file" msgstr "Datei herunterladen" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "Download abbrechen" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "Download als gelöscht markieren" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "Fertige und gelöschte Downloads aus Warteschlange aufräumen" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "Automatischen Download ein/ausschalten" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "Player mit aktuell ausgewähltem Download starten" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "Anzahl der parallelen Downloads erhöhen" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "Anzahl der parallelen Downloads verringern" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "Bildschirm neu zeichnen" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "Die Kommandozeile öffnen" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "Einen Filter setzen" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "Einen vordefinierten Filter auswählen" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "Aktuell gesetzten Filter löschen" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "Lesezeichen für aktuellen Link/Artikel speichern" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "Flags bearbeiten" #: src/keymap.cpp:65 msgid "Go to next feed" msgstr "Zum nächsten Feed gehen" #: src/keymap.cpp:66 msgid "Go to previous feed" msgstr "Zum vorhergehenden Feed gehen" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "Zum nächsten ungelesenen Feed gehen" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "Zum vorhergehenden ungelesenen Feed gehen" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "Makro aufrufen" #: src/keymap.cpp:70 msgid "Delete article" msgstr "Artikel löschen" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "Gelöschte Artikel entfernen" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "Abonnierte URLs bearbeiten" #: src/keymap.cpp:73 msgid "Close currently selected dialog" msgstr "Aktuell ausgewählten Feed schließen" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "Liste von offenen Dialogen ansehen" #: src/keymap.cpp:75 msgid "Go to next dialog" msgstr "Zum nächsten Dialog gehen" #: src/keymap.cpp:76 msgid "Go to previous dialog" msgstr "Zum vorherigen Dialog gehen" #: src/keymap.cpp:77 msgid "Pipe article to command" msgstr "Artikel zu Kommando umleiten" #: src/keymap.cpp:78 msgid "Sort current list" msgstr "Aktuelle Liste sortieren" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "Aktuelle Liste sortieren (umgekehrt)" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "Öffne URL 10" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "Öffne URL 1" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "Öffne URL 2" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "Öffne URL 3" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "Öffne URL 4" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "Öffne URL 5" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "Öffne URL 6" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "Öffne URL 7" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "Öffne URL 8" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "Öffne URL 9" #: src/keymap.cpp:92 msgid "Move to the previous entry" msgstr "Zum vorhergehenden Eintrag gehen" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "Zum nächsten Eintrag gehen" #: src/keymap.cpp:94 msgid "Move to the previous page" msgstr "Zur vorherigen Seite gehen" #: src/keymap.cpp:95 msgid "Move to the next page" msgstr "Zur nächsten Seite gehen" #: src/keymap.cpp:97 msgid "Move to the start of page/list" msgstr "Zum Anfang der Seite/Liste gehen" #: src/keymap.cpp:98 msgid "Move to the end of page/list" msgstr "Zum Ende der Seite/Liste gehen" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "`%s' ist kein gültiger Kontext" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "`%s' ist kein gültiges Tastenkommando" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "Bereinige Warteschlange..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "Verwendung: %s [-C ] [-q ] [-h]\n" "-C Konfiguration aus lesen\n" "-q als Warteschlangendatei verwenden\n" "-a Download beim Programmstart beginen\n" "-h diese Hilfe\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr " - %u parallele Downloads" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "" "Warteschlange (%u Download im Gange, %u insgesamt) - %.2f kb/s insgesamt%s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "Fehler: kann nicht beenden: Download(s) im Gange." #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "" "Fehler: Download muss abgeschlossen sein bevor die Datei abgespielt werden " "kann." #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "Fehler: kann Vorgang nicht durchführen: Download(s) im Gange." #: src/pb_view.cpp:276 msgid "Download" msgstr "Download" #: src/pb_view.cpp:278 msgid "Delete" msgstr "Löschen" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "Fertige aufräumen" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "Automatischen Download umschalten" #: src/pb_view.cpp:281 msgid "Play" msgstr "Abspielen" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "`%s' ist ein ungültiger Dialogtyp" #: src/regexmanager.cpp:49 #, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "`%s' is kein gültiger regulärer Ausdruck: %s" #: src/rss.cpp:466 msgid "too few arguments" msgstr "zu wenige Parameter" #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "Fehler: nicht unterstützte URL: %s" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "Tag auswählen" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "Filter auswählen" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "Attribut nicht gefunden" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "Ende der Datei gefunden beim Lesen eines XML-Tags" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "Kein Link ausgewählt!" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "Lesezeichen speichern" #: src/urlview_formaction.cpp:146 msgid "URLs" msgstr "URLs" #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "Fehler: Anwenden des Filters fehlgeschlagen: %s" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "Fehler: Feed enthält keine Elemente!" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "Update Query-Feed..." #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "XML-Rootknoten ist NULL" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "konnte libcurl nicht initialisieren" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "" "Fehler: der Versuch den Feed `%s' herunzuladen wurde der HTTP-Status-Code " "%ld zurückgeliefert." #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "konnte Puffer nicht parsen" #: rss/parser.cpp:174 msgid "could not parse file" msgstr "konnte Datei nicht parsen" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "keine RSS-Version" #: rss/parser.cpp:211 msgid "invalid RSS version" msgstr "ungültige RSS-Version" #: rss/parser.cpp:226 rss/parser.cpp:233 msgid "invalid Atom version" msgstr "ungültige Atom-Version" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "keine Atom-Version" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "nicht unterstütztes Feed-Format" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "kein RSS-Channel gefunden" newsbeuter-2.7/po/es.po000066400000000000000000001152421220711462700151410ustar00rootroot00000000000000# Spanish translation of newsbeuter # Copyright (C) 2013 # This file is distributed under the same license as the newsbeuter package. # OmeGa , 2013. msgid "" msgstr "" "Project-Id-Version: newsbeuter 2.5\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2013-02-08 06:24-0500\n" "Last-Translator: OmeGa \n" "Language-Team: OmeGa omega@mailoo.org\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Virtaal 0.7.1\n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "`%s' no es un color válido" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, c-format msgid "`%s' is not a valid attribute" msgstr "`%s' no es un atributo válido" #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "`%s' no es un elemento de configuración válido" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "" "newsbeuter: recarga finalizada, %f fuentes no leídas (%n total de artículos " "no leídos)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - Tus fuentes (%u no leídas, %t en total)%?T? - etiqueta `%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - Artículos en la fuente «%T» (%u no leídos, %t en total) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - Resultado de la búsqueda (%u no leídos, %t en total)" #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?Abrir archivo&Guardar archivo? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - Ayuda" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - Seleccionar etiqueta" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - Seleccionar filtro" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - Artículo «%T»" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - URLs" #: src/configcontainer.cpp:111 msgid "%N %V - Dialogs" msgstr "%N %V - Diálogos" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "se esperaba un valor lógico, se encontró `%s' en su lugar" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "se esperaba un valor entero, se encontró `%s' en su lugar" #: src/configcontainer.cpp:159 #, c-format msgid "invalid configuration value `%s'" msgstr "valor de configuración inválido `%s'" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "Error al procesar el comando `%s' (%s línea %u): %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "comando inválido `%s'" #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "Error fatal: ¡no se pudo determinar el directorio de inicio!" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "" "¡Por favor define la variable de entorno HOME, o añade un usuario válido " "para UID %u!" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: opción desconocida - %c" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "Iniciando %s %s..." #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "Error: una instancia de %s ya se está ejecutando (PID: %u)" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "Cargando configuración..." #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "hecho." #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "Abriendo caché..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "Error: la apertura del archivo de caché `%s' falló: %s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "Cargando URLs desde el caché local..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "Cargando URLs desde %s..." #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "" "Error: no hay URLs configuradas. Por favor llena el archivo %s con URLs de " "fuentes RSS, o importa un archivo OPML." #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "" "Parece que la fuente OPML a la cual te suscribiste no contiene fuentes. Por " "favor llénala con fuentes, e inténtalo de nuevo." #: src/controller.cpp:392 msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" "Parece que no has configurado ninguna fuente en tu cuenta de Google Reader. " "Por favor hazlo e inténtalo de nuevo." #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "Cargando artículos desde caché..." #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "Limpiando el caché totalmente..." #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "Error al cargar las fuentes desde la base de datos: " #: src/controller.cpp:430 #, c-format msgid "Error while loading feed '%s': %s" msgstr "Error al cargar la fuente «%s»: %s" #: src/controller.cpp:448 msgid "Prepopulating query feeds..." msgstr "Rellenando las fuentes de consulta..." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "Importando la lista de artículos leídos..." #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "Exportando la lista de artículos leídos..." #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "Limpiando el caché..." #: src/controller.cpp:523 msgid "failed: " msgstr "falló: " #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "Error: no se pudieron marcar como leídas todas las fuentes: %s" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%sCargando %s..." #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "Error al obtener %s: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "Error: ¡fuente inválida!" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "índice de fuentes inválido (error de software)" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "" "newsbeuter es software libre, y licenciado bajo la MIT/X Consortium License." #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "Usa el comando `%s --v' para obtener más información." #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" "%s %s\n" "uso: %s [-i |-e] [-u ] [-c ] [-x " " ...] [-h]\n" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "exportar la fuente OPML a salida estándar" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "actualizar las fuentes al inicio" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 msgid "" msgstr "" #: src/controller.cpp:842 msgid "import OPML file" msgstr "importar archivo OPML" #: src/controller.cpp:843 msgid "" msgstr "" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "leer fuentes URLs de fuentes RSS desde " #: src/controller.cpp:844 msgid "" msgstr "" #: src/controller.cpp:844 msgid "use as cache file" msgstr "utilizar como archivo de caché" #: src/controller.cpp:845 msgid "" msgstr "" #: src/controller.cpp:845 msgid "read configuration from " msgstr "leer configuración desde " #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "limpiar el caché totalmente" #: src/controller.cpp:847 msgid "..." msgstr "..." #: src/controller.cpp:847 msgid "execute list of commands" msgstr "ejecutar lista de comandos" #: src/controller.cpp:848 msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "" "activar modo «fuera de línea» (aplica únicamente al modo de sincronización " "de Google Reader)" #: src/controller.cpp:849 msgid "quiet startup" msgstr "inicio silencioso" #: src/controller.cpp:850 msgid "get version information" msgstr "mostrar información de la versión" #: src/controller.cpp:851 msgid "" msgstr "" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "escribir un registro con un determinado nivel (valores válidos: 1 a 6)" #: src/controller.cpp:852 msgid "" msgstr "" #: src/controller.cpp:852 msgid "use as output log file" msgstr "utilizar como archivo de salida para el registro" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "exportar lista de artículos leídos a " #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "importar lista de artículos leídos desde " #: src/controller.cpp:855 msgid "this help" msgstr "esta ayuda" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "Ocurrió un error al procesar %s." #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "Importación de %s finalizada." #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "" "el soporte para marcadores no está configurado. Por favor define la variable " "de configuración `bookmark-cmd' adecuadamente." #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u artículos no leídos" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "Título: " #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "Autor: " #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "Fecha: " #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "Enlace: " #: src/controller.cpp:1388 #, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "Error: ¡no se pudo abrir el archivo de configuración `%s'!" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "Cerrar" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "Ir a diálogo" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "Cerrar diálogo" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "¡Ningún elemento seleccionado!" #: src/dialogs_formaction.cpp:74 msgid "Error: you can't remove the feed list!" msgstr "Error: ¡no puedes eliminar la lista de fuentes!" #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "¡Posición inválida!" #: src/download.cpp:42 msgid "queued" msgstr "en cola" #: src/download.cpp:44 msgid "downloading" msgstr "descargando" #: src/download.cpp:46 msgid "cancelled" msgstr "cancelado" #: src/download.cpp:48 msgid "deleted" msgstr "eliminado" #: src/download.cpp:50 msgid "finished" msgstr "terminado" #: src/download.cpp:52 msgid "failed" msgstr "fallido" #: src/download.cpp:54 msgid "incomplete" msgstr "incompleto" #: src/download.cpp:56 msgid "played" msgstr "reproducido" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "desconocido (error de software)." #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "el atributo `%s' no está disponible." #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "la expresión regular «%s» es inválida: %s" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "parámetros inválidos." #: src/exception.cpp:43 msgid "too few parameters." msgstr "insuficientes parámetros." #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "comando desconocido (error de software)." #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "no se pudo abrir el archivo." #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "error desconocido (error de software)." #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "¡Ninguna fuente seleccionada!" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "" "¿Ordenar por (p)rimera etiqueta/(t)ítulo/número de (a)rtículos/número de " "artículos no (l)eídos/(n)ada?" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "ptaln" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "p" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "t" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "a" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "l" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "n" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "" "¿Ordenar inversamente por (p)rimera etiqueta/(t)ítulo/número de " "(a)rtículos/número de artículos no (l)eídos/(n)ada?" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "Marcando fuente como leída..." #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "Error: no se pudo marcar la fuente como leída: %s" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "No hay fuentes con elementos no leídos." #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "Ya estás en la última fuente." #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "Ya estás en la primera fuente." #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "Marcando todas las fuentes como leídas..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "No hay etiquetas definidas." #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "Error: no se pudo procesar el comando de filtro `%s': %s" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "No hay filtros definidos." #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "Buscar: " #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "Filtro: " #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "¿Realmente deseas salir (s:Sí n:No)? " #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "sn" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "s" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "Salir" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "Abrir" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "Siguiente no leído" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "Actualizar" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "Actualizar todo" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "Marcar como leído" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "Poner todo al día" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "Buscar" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "Ayuda" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "Error: ¡no se pudo procesar el comando de filtro!" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "Buscando..." #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "Error al buscar `%s': %s" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "No hay resultados." #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "¡La posición no es visible!" #: src/feedlist_formaction.cpp:774 #, c-format msgid "Feed List - %u unread, %u total" msgstr "Lista de fuentes - %u no leídas, %u en total" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "¿Realmente deseas sobrescribir `%s' (s:Sí n:No)? " #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "Archivo: " #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - Abrir archivo - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - Guardar archivo - %s" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "Cancelar" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "Guardar" #: src/filebrowser_formaction.cpp:271 #, c-format msgid "Open File - %s" msgstr "Abrir archivo - %s" #: src/filebrowser_formaction.cpp:273 #, c-format msgid "Save File - %s" msgstr "Guardar archivo - %s" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "no se pudo procesar la expresión de filtro `%s': %s" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "uso: definir [=]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "uso: fuente [...]" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "uso: dumpconfig " #: src/formaction.cpp:231 #, c-format msgid "Saved configuration to %s" msgstr "Configuración guardada como %s" #: src/formaction.cpp:236 #, c-format msgid "Not a command: %s" msgstr "No es un comando: %s" #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "Guardando marcados..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "Marcador guardado." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "Error al guardar el marcados: " #: src/formaction.cpp:303 msgid "URL: " msgstr "URL: " #: src/formaction.cpp:305 msgid "Description: " msgstr "Descripción: " #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "Gente a la que sigues" #: src/googlereader_urlreader.cpp:34 msgid "Starred items" msgstr "Elementos destacados" #: src/googlereader_urlreader.cpp:35 msgid "Shared items" msgstr "Elementos compartidos" #: src/googlereader_urlreader.cpp:36 msgid "Popular items" msgstr "Elementos populares" #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "Atajos de teclado genéricos:" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "Funciones no definidas:" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "Borrar" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "flash incrustado:" #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "imagen" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "Enlaces: " #: src/htmlrenderer.cpp:594 msgid "link" msgstr "enlace" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "flash incrustado" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "desconocido (error de software)" #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "Cambiando el estado de lectura para el artículo..." #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "Error al cambiar el estado de lectura: %s" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "lista de URLs vacía." #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "Indicadores: " #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "Error: ¡ningún elemento seleccionado!" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "Error: no puedes recargar resultados de búsqueda." #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "No hay elementos no leídos." #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "Ya estás en el último elemento." #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "Ya estás en el primer elemento." #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "No hay fuentes no leídas." #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "Encadenar artículo al comando: " #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "¿Ordenar por (f)echa/(t)ítulo/(i)ndicadores/(a)utor/(e)nlace/(g)uid?" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 msgid "dtfalg" msgstr "ftmaeg" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "f" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "e" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "g" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" "¿Ordenar inversamente por " "(f)echa/(t)ítulo/(i)ndicadores/(a)utor/(e)nlace/(g)uid?" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "Indicadores actualizados." #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "Marcar todo como leído" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "Guardado abortado." #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "Guardar artículo como %s" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "Error: no se pudo guardar el artículo como %s" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "Resultado de la búsqueda - «%s»" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "Consultar fuente - %s" #: src/itemlist_formaction.cpp:1004 #, c-format msgid "Article List - %s" msgstr "Lista de artículos - %s" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "Arriba" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "Abajo" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "Fuente: " #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "URL de descarga del podcast: " #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "tipo: " #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "Error al marcar el artículo como leído: %s" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "Se añadió %s a la cola de descargas." #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "URL inválida: «%s»" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "Artículo guardado como %s." #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "Error: no se pudo escribir el artículo en el archivo %s" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "Iniciando el navegador..." #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "Error al marcar el artículo como no leído: %s" #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "Ir a URL #" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "Abrir en el navegador" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "Agregar a la cola" #: src/itemview_formaction.cpp:586 #, c-format msgid "Article - %s" msgstr "Artículo - %s" #: src/itemview_formaction.cpp:624 msgid "Error: invalid regular expression!" msgstr "Error: ¡expresión regular inválida!" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "Abrir fuente/artículo" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "Volver al diálogo anterior/Salir" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "Salir del programa sin confirmación" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "Actualizar la fuente selecionada" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "Actualizar todas las fuentes" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "Marcar fuente como leída" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "Marcar todas la fuentes como leídas" #: src/keymap.cpp:30 msgid "Save article" msgstr "Guardar artículo" #: src/keymap.cpp:31 msgid "Go to next article" msgstr "Ir al siguiente artículo" #: src/keymap.cpp:32 msgid "Go to previous article" msgstr "Ir al artículo anterior" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "Ir al siguiente artículo no leído" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "Ir al artículo no leído anterior" #: src/keymap.cpp:35 msgid "Go to a random unread article" msgstr "Ir a un artículo no leído aleatorio" #: src/keymap.cpp:36 msgid "Open article in browser and mark read" msgstr "Abrir el artículo en el navegador, y marcar como leído" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "Abrir artículo en el navegador" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "Abrir el diálogo de ayuda" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "Cambiar a vista de fuente" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "Cambiar el estado de lectura para el artículo" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "Cambiar mostrar fuentes/artículos" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "Mostrar URLs en el artículo actual" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "Eliminar la etiqueta actual" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "Seleccionar etiqueta" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "Abrir el diálogo de búsqueda" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "Añadir descarga a la cola" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "Actualizar la lista de URLs desde la configuración" #: src/keymap.cpp:50 msgid "Download file" msgstr "Descargar archivo" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "Cancelar descarga" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "Marcar la descarga como eliminada" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "Purgar las descargas finalizadas y eliminadas de la cola" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "Cambiar descarga automática activada/desactivada" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "Iniciar el reproductor con la descarga seleccionada actualmente" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "Incrementar el número de descargas simultáneas" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "Disminuir el número de descargas simultáneas" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "Redibujar pantalla" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "Abrir la línea de comandos" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "Establecer un filtro" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "Seleccionar un filtro predeterminado" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "Eliminar el filtro establecido actualmente" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "Añadir el artículo/enlace actual a marcadores" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "Editar indicadores" #: src/keymap.cpp:65 msgid "Go to next feed" msgstr "Ir a la siguiente fuente" #: src/keymap.cpp:66 msgid "Go to previous feed" msgstr "Ir a la fuente anterior" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "Ir a la siguiente fuente no leída" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "Ir a la anterior fuente no leída" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "Invocar un macro" #: src/keymap.cpp:70 msgid "Delete article" msgstr "Eliminar artículo" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "Purgar artículos eliminados" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "Editar las URLs de suscripción" #: src/keymap.cpp:73 msgid "Close currently selected dialog" msgstr "Cerrar el diálogo seleccionado actualmente" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "Ver la lista de diálogos abiertos" #: src/keymap.cpp:75 msgid "Go to next dialog" msgstr "Ir al diálogo siguiente" #: src/keymap.cpp:76 msgid "Go to previous dialog" msgstr "Ir al diálogo anterior" #: src/keymap.cpp:77 msgid "Pipe article to command" msgstr "Encadenar artículo a un comando" #: src/keymap.cpp:78 msgid "Sort current list" msgstr "Ordenar la lista actual" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "Ordenar la lista actual (inverso)" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "Abrir URL 10" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "Abrir URL 1" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "Abrir URL 2" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "Abrir URL 3" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "Abrir URL 4" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "Abrir URL 5" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "Abrir URL 6" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "Abrir URL 7" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "Abrir URL 8" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "Abrir URL 9" #: src/keymap.cpp:92 msgid "Move to the previous entry" msgstr "Ir a la entrada siguiente" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "Ir a al entrada anterior" #: src/keymap.cpp:94 msgid "Move to the previous page" msgstr "Ir a la página anterior" #: src/keymap.cpp:95 msgid "Move to the next page" msgstr "Ir a la página siguiente" #: src/keymap.cpp:97 msgid "Move to the start of page/list" msgstr "Ir al comienzo de la página/lista" #: src/keymap.cpp:98 msgid "Move to the end of page/list" msgstr "Ir al final de la página/lista" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "`%s' no es un contexto válido" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "`%s' no es un comando de tecla válido" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "Limpiando cola..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "uso %s [-C ] [-q ] [-h]\n" "-C leer configuración desde \n" "-q usar como archivo de cola\n" "-a comenzar la descarga al inicio\n" "-h esta ayuda\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr " - %u descargas paralelas" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "Cola (%u descargas en proceso, %u en total) - %.2f kb/s total%s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "Error: no se puede salir: descarga(s) en progreso." #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "" "Error: la descarga debe finalizar antes de que se pueda reproducir el " "archivo." #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "Erros: no se puede ejecutar la operación: descarga(s) en progreso." #: src/pb_view.cpp:276 msgid "Download" msgstr "Descargar" #: src/pb_view.cpp:278 msgid "Delete" msgstr "Eliminar" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "Purgar finalizadas" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "Cambiar a descarga automática" #: src/pb_view.cpp:281 msgid "Play" msgstr "Reproducir" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "`%s' es un tipo de diálogo inválido" #: src/regexmanager.cpp:49 #, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "`%s' no es una expresión regular válida: %s" #: src/rss.cpp:466 msgid "too few arguments" msgstr "insuficientes argumentos" #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "Error: URL no soportada: %s" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "Seleccionar etiqueta" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "Seleccionar filtro" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "atributo no encontrado" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "EOF encontrado al leer la etiqueta XML" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "¡Ningún enlace seleccionado!" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "Guardar marcador" #: src/urlview_formaction.cpp:146 msgid "URLs" msgstr "URLs" #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "Error: falló aplicar el filtro: %s" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "Error: ¡la fuente no contiene elementos!" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "Actualizando consulta de fuente..." #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "el nodo raíz de XML es nulo" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "no se pudo iniciar libcurl" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "" "Error: intentar descargar la fuente `%s' devolvió del código de estado HTTP " "%ld." #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "no se pudo procesar el búfer" #: rss/parser.cpp:174 msgid "could not parse file" msgstr "no se pudo procesar el archivo" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "sin versión de RSS" #: rss/parser.cpp:211 msgid "invalid RSS version" msgstr "versión de RSS inválida" #: rss/parser.cpp:226 rss/parser.cpp:233 msgid "invalid Atom version" msgstr "versión de Atom inválida" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "sin versión de Atom" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "formato de fuente no soportado" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "no se encontró ningún canal RSS" newsbeuter-2.7/po/es_ES.po000066400000000000000000001174151220711462700155340ustar00rootroot00000000000000# translation of es_ES.po to es-ES # translation of es_ES.po to # Copyright (C) 2009 THE es_ES'S COPYRIGHT HOLDER # This file is distributed under the same license as the es_ES package. # ROOT , 2008. # ROOT , 2009. # ROOT , 2010. # # msgid "" msgstr "" "Project-Id-Version: es_ES\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2010-02-23 14:50+0100\n" "Last-Translator: <>\n" "Language-Team: <>\n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: \n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "`%s' no es un color válido" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, c-format msgid "`%s' is not a valid attribute" msgstr "`%s' no es un atributo válido." #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "`%s' no es un elemento de configuración válido" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "" "newsbeauter: recarga finalizada, %f feeds no leidos (%n total de articulos " "no leidos)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - Tus feeds (%u no leidos, %t total)%?T? - etiqueta `%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - Articulos en el feed '%T' (%u no leidos, %t total) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - Resultados de busqueda (%u unread, %t total)" #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?Abrir arcivo&Salvar archivo? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - Ayuda" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - Seleccionar etiqueta" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - Seleccionar filtro" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - Articulo '%T'" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - URLs" #: src/configcontainer.cpp:111 msgid "%N %V - Dialogs" msgstr "%N %V - Diálogos" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "se esperaba un valor lógico, se ha encontrado `%s' en su lugar" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "se esperaba un valor entero, se encontró `%s' en su lugar" #: src/configcontainer.cpp:159 #, c-format msgid "invalid configuration value `%s'" msgstr "Valor de configuración `%s' inválido" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "Error ejecutando el comando `%s' (%s linea %u): %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "comando desconocido `%s'" #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "Error fatal: no se pudo encontrar el directorio home!" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "" "Por favor declara la variable de entorno HOME o añade un usuario valido " "para UID %u!" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: opcion desconocida - %c" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "Iniciando %s %s..." #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "Error: una instancia de %s esta ejecutandose (PID: %u)" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "Cargando configuracion..." #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "hecho." #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "Abriendo cache..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "Error: abriendo el archivo de cache `%s' fallo: %s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "Cargando URLs desde el cache local..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "Cargando URLs desde %s..." #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "" "Error: no hay URLs configuradas. Por favor inserta RSS en el fichero %s o " "importa un fichero OPML." #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "" "Parece que el feed OPML al que te has subscrito no contiene feeds. Por " "favor, rellenalocon feeds e intentalo de nuevo." #: src/controller.cpp:392 msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" "Parece que no has configurado ningun feed en tu cuenta de Google Reader. Por " "favor, hazlo e intentalo de nuevo." #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "Cargando articulos desde el cache..." #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "Limpiando el cache totalmente..." #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "" "Se produjo un error mientras se cargaban los feeds desde la base de datos:" #: src/controller.cpp:430 #, c-format msgid "Error while loading feed '%s': %s" msgstr "Error cargando feed '%s': %s" #: src/controller.cpp:448 msgid "Prepopulating query feeds..." msgstr "Preparando consulta de feeds..." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "Importando lista de articulos leidos..." #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "Exportando lista de articulos leidos..." #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "Limpiando el cache..." #: src/controller.cpp:523 msgid "failed: " msgstr "fallo: " #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "Error: no se pudieron marcar todos los feeds como leidos: %s" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%sCargando %s..." #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "Error descargando %s: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "Error: feed invalido!" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "Indice de feeds invalido (fallo)" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "newsbeuter es software libre bajo MIT/X Consortium License" #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "Teclea `%s -vv' para mas información" #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" "%s %s\n" "uso: %s [-i |-e] [-u ] [-c ] [-x " " ...] [-h]\n" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "exportar feed OPML a la salida estándar" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "actualizar feeds al iniciar" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 msgid "" msgstr "" #: src/controller.cpp:842 msgid "import OPML file" msgstr "importar archivo OPML" #: src/controller.cpp:843 msgid "" msgstr "" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "leer URLs de feeds RSS desde " #: src/controller.cpp:844 msgid "" msgstr "" #: src/controller.cpp:844 msgid "use as cache file" msgstr "usar como archivo de cache" #: src/controller.cpp:845 msgid "" msgstr "" #: src/controller.cpp:845 msgid "read configuration from " msgstr "leer configuracion desde " #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "Limpiar el cache totalmente" #: src/controller.cpp:847 msgid "..." msgstr "..." #: src/controller.cpp:847 msgid "execute list of commands" msgstr "ejecutar lista de comandos" #: src/controller.cpp:848 #, fuzzy msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "" "activar modo desconectado (solo se aplica al modo de sincronizacion de " "bloglines)" #: src/controller.cpp:849 msgid "quiet startup" msgstr "" #: src/controller.cpp:850 msgid "get version information" msgstr "informacion de la version" #: src/controller.cpp:851 msgid "" msgstr "" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "" "escribir una bitacora con un determinado nivel (valores validos: 1 a 6)" #: src/controller.cpp:852 msgid "" msgstr "" #: src/controller.cpp:852 msgid "use as output log file" msgstr "usar como archivo de salida de bitacora" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "exportar lista de articulos leidos a " #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "importar lista de articulos leidos desde " #: src/controller.cpp:855 msgid "this help" msgstr "esta ayuda" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "Se produjo un error analizando %s." #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "Importacion de %s finalizada." #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "" "El soporte para marcadores no esta connfigurado. Por favor configure " "lavariable `bookmark-cmd' correctamente." #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u articulos no leidos" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "Titulo: " #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "Autor: " #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "Fecha: " #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "Enlace: " #: src/controller.cpp:1388 #, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "Error: no se pudo abrir el archivo de configuración %s" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "Cerrar" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "Ir a Diálogo" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "Cerrar Diálogo" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "Ningun objeto seleccionado!" #: src/dialogs_formaction.cpp:74 msgid "Error: you can't remove the feed list!" msgstr "Error: no puedes eliminar la lista de feeds." #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "Posicion invalida!" #: src/download.cpp:42 msgid "queued" msgstr "encolado" #: src/download.cpp:44 msgid "downloading" msgstr "descargando" #: src/download.cpp:46 msgid "cancelled" msgstr "cancelado" #: src/download.cpp:48 msgid "deleted" msgstr "borrado" #: src/download.cpp:50 msgid "finished" msgstr "finalizado" #: src/download.cpp:52 msgid "failed" msgstr "fallido" #: src/download.cpp:54 msgid "incomplete" msgstr "incompleto" #: src/download.cpp:56 msgid "played" msgstr "ejecutado" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "desconocido (fallo)" #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "atributo `%s' no disponible." #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "la expresión regular '%s' es inválida: %s" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "parametros invalidos." #: src/exception.cpp:43 msgid "too few parameters." msgstr "pocos parametros." #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "comando desconocido (error)." #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "el archivo no se pudo abrir." #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "error desconocido (fallo)." #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "No hay feeds seleccionados!" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "" "¿Ordenar por primera etiqueta (f)/(t)ítulo/número de (a)rtíclulos/número de " "artíc(u)los no leídos/(n)ada?" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "ftaun" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "f" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "t" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "a" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "u" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "n" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "" "¿Orden inverso por primera etiqueta(f)/(t)ítulo/número de (a)rtíclulos/n(u)" "mero de artículos no leídos/(n)ada?" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "Marcando feed como leido..." #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "Error: no se pudo marcar el feed como leido: %s" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "No hay feeds con elementos no leidos" #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "" #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "" #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "Marcando todos los feeds como leidos..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "No se definieron etiquetas." #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "Error: no se pudo analizar el comando de filtro `%s': %s" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "No se definieron filtros." #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "Buscar: " #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "Filtro: " #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "Realmente quieres salir (y:Si n:No)?" #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "yn" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "y" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "Salir" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "Abrir" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "Siguiente no leido" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "Recargar" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "Recargar todos" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "Marcar como leido" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "Coger todos" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "Buscar" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "Ayuda" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "Error: no se pudo ejecutar el comando de filtro!" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "Buscando..." #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "Error buscando `%s': %s" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "Sin resultados." #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "Posicion no visible!" #: src/feedlist_formaction.cpp:774 #, c-format msgid "Feed List - %u unread, %u total" msgstr "Lista de Feeds - %u no leídos, %u total" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "Realmente quieres sobreescribir `%s' (y:Si n:No)? " #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "Fichero: " #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - Abrir Fichero - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - Salvar Fichero - %s" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "Cancelar" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "Salvar" #: src/filebrowser_formaction.cpp:271 #, c-format msgid "Open File - %s" msgstr "Abrir Fichero - %s" #: src/filebrowser_formaction.cpp:273 #, c-format msgid "Save File - %s" msgstr "Salvar Fichero - %s" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "No se pudo analizar el comando de filtro `%s': %s" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "Uso: set [=]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "uso: fuente [...]" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "uso: dumpconfig " #: src/formaction.cpp:231 #, c-format msgid "Saved configuration to %s" msgstr "Configuracion salvada en %s" #: src/formaction.cpp:236 #, c-format msgid "Not a command: %s" msgstr "No es un comando: %s" #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "Salvando marcador..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "Marcador salvado." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "Error salvando marcador: " #: src/formaction.cpp:303 msgid "URL: " msgstr "URL: " #: src/formaction.cpp:305 msgid "Description: " msgstr "Descripcion: " #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "Personas a las que sigues" #: src/googlereader_urlreader.cpp:34 msgid "Starred items" msgstr "Elementos declarados" #: src/googlereader_urlreader.cpp:35 msgid "Shared items" msgstr "Elementos compartidos" #: src/googlereader_urlreader.cpp:36 msgid "Popular items" msgstr "Elementos populares" #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "Uniones generales:" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "funciones de desunión:" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "Limpiar" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "flash incrustado: " #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "imagen" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "Enlaces: " #: src/htmlrenderer.cpp:594 msgid "link" msgstr "enlace" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "flash incrustado" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "desconodico (fallo)" #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "Cambiando bandera de lectura para el articulo..." #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "Error cambiando bandera de lectura: %s" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "Lista de URL vacia." #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "Banderas: " #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "Error: ningun objeto seleccionado!" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "Error: no puedes recargar los resultados de la busqueda." #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "Ningun elemento no leido." #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "" #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "" #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "Ningun feed no leido." #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "Unir artículo a comando: " #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "¿Ordenar por fecha(d)/(t)ítulo/etiquetas(f)/(a)utor/en(l)ace/(g)uid?" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 msgid "dtfalg" msgstr "dtflag" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "d" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "l" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "g" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" "¿Orden inverso por fecha(d)/(t)ítulo/etiquetas(f)/(a)utor/en(l)ace/(g)uid?" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "Banderas actualizadas." #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "Marcar todo como leido" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "Salvar abortado." #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "Articulo salvado como %s" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "Error: No se pudo salvar el articulo como %s" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "Resultado de búsqueda - '%s'" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "Consultar Feed - %s" #: src/itemlist_formaction.cpp:1004 #, c-format msgid "Article List - %s" msgstr "Lista de artículos - %s" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "Arriba" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "Abajo" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "Feed: " #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "URL de descarga de Podcast: " #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "tipo: " #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "Error marcando articulo como leido: %s" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "Añadido %s para descarga." #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "URL inválido: '%s'" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "Articulo salvado como %s." #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "Error: no se pudo escibir el articulo en el fichero %s" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "Iniciando navegador..." #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "Error marcando articulo como no leido: %s" #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "Ir a URL #" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "Abrir en navegador" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "Encolado" #: src/itemview_formaction.cpp:586 #, c-format msgid "Article - %s" msgstr "Articulo - %s" #: src/itemview_formaction.cpp:624 msgid "Error: invalid regular expression!" msgstr "Error: ¡Expresión regular inválida!" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "Abrir feed/articulo" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "Volver/Salir" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "Salir del programa sin confirmación" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "Recargar el feed seleccionado" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "Recargar todos los feeds" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "Marcar el feed como leido" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "Marcar todos los feeds como leidos" #: src/keymap.cpp:30 msgid "Save article" msgstr "Salvar articulo" #: src/keymap.cpp:31 #, fuzzy msgid "Go to next article" msgstr "Ir al proximo articulo no leido" #: src/keymap.cpp:32 #, fuzzy msgid "Go to previous article" msgstr "Ir al anterior articulo no leido" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "Ir al proximo articulo no leido" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "Ir al anterior articulo no leido" #: src/keymap.cpp:35 msgid "Go to a random unread article" msgstr "Ir a un artículo no leído aleatorio" #: src/keymap.cpp:36 #, fuzzy msgid "Open article in browser and mark read" msgstr "Abrir articulo en navegador" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "Abrir articulo en navegador" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "Abrir cuadro de ayuda" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "Cambiar vista" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "Cambiar modo de lectura del articulo" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "Cambiar mostrar feeds leidos" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "Mostrar URLs en el articulo actual" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "Borrar etiqueta actual" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "Seleccionar etiqueta" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "Abrir cuadro de busqueda" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "Añadir descarga a la cola" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "Recargar lista de URLs desde la configuracion" #: src/keymap.cpp:50 msgid "Download file" msgstr "Descargar fichero" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "Cancelar descarga" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "Marcar descarga como borrada" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "Limpiar descargas finalizadas y borradas de la cola" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "Cambiar descarga automatica on/off" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "Iniciar reproductor con la descarga seleccionada" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "Incrementar el numero de descargas simultaneas" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "Reducir el numero de descargas simultaneas" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "Redibujar pantalla" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "Abrir la linea de comandos" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "Establecer un filtro" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "Seleccionar un filtro predeterminado" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "Borrar Establecer un filtro actual" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "Añadir a marcadores el enlace/articulo actual" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "Editar banderas" #: src/keymap.cpp:65 #, fuzzy msgid "Go to next feed" msgstr "Ir al proximo feed no leido" #: src/keymap.cpp:66 #, fuzzy msgid "Go to previous feed" msgstr "Ir al anterior feed no leido" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "Ir al proximo feed no leido" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "Ir al anterior feed no leido" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "Llamar a un macro" #: src/keymap.cpp:70 msgid "Delete article" msgstr "Borrar articulo" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "Eliminar definitivamente articulos borrados " #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "Editar URLs suscritas" #: src/keymap.cpp:73 msgid "Close currently selected dialog" msgstr "Cerrar el diálogo actualmente seleccionado" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "Ver lista de diálogos abiertos" #: src/keymap.cpp:75 msgid "Go to next dialog" msgstr "Ir al proximo diálogo" #: src/keymap.cpp:76 msgid "Go to previous dialog" msgstr "Ir al diálogo anterior" #: src/keymap.cpp:77 msgid "Pipe article to command" msgstr "Llevar artículo a comando" #: src/keymap.cpp:78 msgid "Sort current list" msgstr "Ordenar la lista actual" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "Ordenar la lista actual (inverso)" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "Abrir URL 10" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "Abrir URL 1" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "Abrir URL 2" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "Abrir URL 3" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "Abrir URL 4" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "Abrir URL 5" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "Abrir URL 6" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "Abrir URL 7" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "Abrir URL 8" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "Abrir URL 9" #: src/keymap.cpp:92 msgid "Move to the previous entry" msgstr "Ir a la entrada anterior" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "Ir a la siguiente entrada" #: src/keymap.cpp:94 msgid "Move to the previous page" msgstr "Ir a la página anterior" #: src/keymap.cpp:95 msgid "Move to the next page" msgstr "Ir a la página siguiente" #: src/keymap.cpp:97 msgid "Move to the start of page/list" msgstr "Ir al principio de la página/lista" #: src/keymap.cpp:98 msgid "Move to the end of page/list" msgstr "Ir al final de la página/lista" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "`%s' no es un contexto válido" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "`%s' no es un comando de tecla válido" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "Limpiando cola..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "uso %s [-C ] [-q ] [-h]\n" "-C leer configuracion desde \n" "-q usa como fichero de cola\n" "-a comenzar a descargar al iniciar\n" "-h esta ayuda\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr " - %u descargas paralelas" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "Cola (%u descargas en proceso, %u total) - %.2f kb/s total%s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "Error: no se puede salir: descarga(s) en proceso" #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "Error: la descarga debe finalizar antes de poder ser reproducida." #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "Error: imposible ejecutar operacion: descarga(s) en proceso." #: src/pb_view.cpp:276 msgid "Download" msgstr "Descarga" #: src/pb_view.cpp:278 msgid "Delete" msgstr "Borrar" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "Limpiar finalizadas" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "Cambiar Descarga Automatica" #: src/pb_view.cpp:281 msgid "Play" msgstr "Ejecutar" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "`%s' es un tipo de diálogo inválido" #: src/regexmanager.cpp:49 #, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "`%s' no es una expresión regular válida: %s" #: src/rss.cpp:466 msgid "too few arguments" msgstr "muy pocos parámetros." #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "Error: URL no soportada: %s" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "Selecciona Etiqueta" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "Selecciona Filtro" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "atributo no encontrado" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "Fin De Fichero (EOF) encontrado leyendo etiqueta XML" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "Ningun enlace seleccionado!" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "Salvar Marcador" #: src/urlview_formaction.cpp:146 msgid "URLs" msgstr "URLs" #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "Error: Fallo al aplicar el filtro: %s" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "Error: el feed no contiene elementos!" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "Actualizando consulta de feed..." #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "nodo raiz XML es NULO" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "no se pudo inicializar libcurl" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "" "Error: intentando descargar feed `%s' devolvió código de estado HTTP %ld." #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "no se pudo analizar el buffer" #: rss/parser.cpp:174 msgid "could not parse file" msgstr "no se pudo analizar el archivo" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "sin versión RSS" #: rss/parser.cpp:211 msgid "invalid RSS version" msgstr "versión RSS inválida" #: rss/parser.cpp:226 rss/parser.cpp:233 msgid "invalid Atom version" msgstr "versión Atom inválida" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "sin versión Aton" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "formato de feed no soportado" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "ningún canal RSS encontrado" #~ msgid "" #~ "%s %s\n" #~ "usage: %s [-i |-e] [-u ] [-c ] [-x " #~ " ...] [-h]\n" #~ "-e export OPML feed to stdout\n" #~ "-r refresh feeds on start\n" #~ "-i import OPML file\n" #~ "-u read RSS feed URLs from \n" #~ "-c use as cache file\n" #~ "-C read configuration from \n" #~ "-v clean up cache thoroughly\n" #~ "-x ... execute list of commands\n" #~ "-o activate offline mode (only applies to bloglines synchronization " #~ "mode)\n" #~ "-V get version information\n" #~ "-l write a log with a certain loglevel (valid values: 1 to 6)\n" #~ "-d use as output log file\n" #~ "-E export list of read articles to \n" #~ "-I import list of read articles from \n" #~ "-h this help\n" #~ msgstr "" #~ "%s %s\n" #~ "Uso: %s [-i |-e] [-u ] [-c ] [-" #~ "h]\n" #~ "-e exportar feed OPML a la salida estandar\n" #~ "-r actualizar feeds al iniciar\n" #~ "-i importar fichero OPML\n" #~ "-u leer URLs de feeds RSS desde \n" #~ "-c usar como fichero de cache\n" #~ "-C leer configuracion de \n" #~ "-v limpiar cache totalmente\n" #~ "-x ejecutar lista de comandos\n" #~ "-o activar modo desconectado (solo para el modo de sincronizacion de " #~ "bloglines)\n" #~ "-V informacion de version\n" #~ "-l escribir un log con un cierto numero de nivel de log " #~ "(valores validos del 1 al 6)\n" #~ "-d usar como fichero de salida de log\n" #~ "-E exportar lista de articulos leidos a \n" #~ "-I importar lista de articulos leidos desde \n" #~ "-h esta ayuda\n" newsbeuter-2.7/po/fr.po000066400000000000000000001143371220711462700151450ustar00rootroot00000000000000# msgid "" msgstr "" "Project-Id-Version: newsbeuter\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2008-08-11 19:13+0200\n" "Last-Translator: Nicolas Martyanoff \n" "Language-Team: Nicolas Martyanoff \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, fuzzy, c-format msgid "`%s' is not a valid attribute" msgstr "L'attribut '%s' n'est pas disponible" #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "" "newsbeuter: rechargement terminé, %f fils non-lus (%n articles non-lus au " "total)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - Vos fils (%u non lus, %t total)%?T? - tag `%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - Articles dans le fils '%T' (%u non-lus, %t total) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - Résultats de recherche (%u non lus, %t total) " #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?Ouvrir Fichier&Enregistrer Fichier? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - Aide" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - Sélectionner Tag" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - Sélectionner Filtre" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - Article '%T'" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - URLs" #: src/configcontainer.cpp:111 #, fuzzy msgid "%N %V - Dialogs" msgstr "%N %V - URLs" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "" #: src/configcontainer.cpp:159 #, fuzzy, c-format msgid "invalid configuration value `%s'" msgstr "Article enregistré dans %s" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "Erreur durant le déroulement de la commande `%s' (%s ligne %u): %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "commande inconnue `%s'" #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "Erreur fatale, impossible de localiser le répertoire personnel !" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "" "S'il-vous-plaît, définissez la variable d'environnement HOME ou ajoutez un " "utilisateur valide pour l'UID %u !" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: option inconnue - %c" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "Démarrage %s %s..." #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "Erreur: une instance de %s est déjà lancée (PID: %u)" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "Chargement de la configuration..." #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "fait." #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "Vidage du cache..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "Erreur, impossible d'ouvrir le fichier cache`%s': %s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "Chargement des URLs depuis le cache local..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "Chargement des URLs depuis %s..." #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "" "Erreur: aucune URL configurée. S'il-vous-plaît, remplissez le fichier %s " "avec des URLs de fils RSS, ou importez un fichier OPML." #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "" "Il semble que le fil OPML auquel vous vous être inscris ne contient aucun " "fil.S'il vous plaît, faites le, et essayez encore." #: src/controller.cpp:392 #, fuzzy msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" "Il semble que vous n'avez configuré aucun fil dans votre aggrégateur.S'il " "vous plait, faites le, et essayez encore." #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "Chargement des articles depuis le cache..." #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "Vidage du cache..." #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "Erreur lors du chargement des fils depuis la database" #: src/controller.cpp:430 #, fuzzy, c-format msgid "Error while loading feed '%s': %s" msgstr "Erreur lors de la recherche pour '%s': %s" #: src/controller.cpp:448 #, fuzzy msgid "Prepopulating query feeds..." msgstr "Mise à jour du fil.." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "" #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "" #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "Vidage du cache..." #: src/controller.cpp:523 msgid "failed: " msgstr "echoué: " #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "Erreur: impossible de marquer tous les fils comme lus: %s" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%sChargement %s..." #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "Erreur lors de la récupération de %s: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "Erreur: fil invalide !" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "Index de fil invalide (bug)" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "" #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "" #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 #, fuzzy msgid "" msgstr "manqué" #: src/controller.cpp:842 msgid "import OPML file" msgstr "" #: src/controller.cpp:843 msgid "" msgstr "" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "" #: src/controller.cpp:844 #, fuzzy msgid "" msgstr "annulé" #: src/controller.cpp:844 msgid "use as cache file" msgstr "" #: src/controller.cpp:845 msgid "" msgstr "" #: src/controller.cpp:845 msgid "read configuration from " msgstr "" #: src/controller.cpp:846 #, fuzzy msgid "clean up cache thoroughly" msgstr "Vidage du cache..." #: src/controller.cpp:847 msgid "..." msgstr "" #: src/controller.cpp:847 msgid "execute list of commands" msgstr "" #: src/controller.cpp:848 msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "" #: src/controller.cpp:849 msgid "quiet startup" msgstr "" #: src/controller.cpp:850 msgid "get version information" msgstr "" #: src/controller.cpp:851 msgid "" msgstr "" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "" #: src/controller.cpp:852 msgid "" msgstr "" #: src/controller.cpp:852 msgid "use as output log file" msgstr "" #: src/controller.cpp:853 #, fuzzy msgid "export list of read articles to " msgstr "Erreur, impossible d'écrire l'article dans %s" #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "" #: src/controller.cpp:855 msgid "this help" msgstr "" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "" #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "Import de %s terminé." #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "" "Le support des marque-pages n'est pas configuré. S'il vous plait, éditez la " "variable de configuration 'bookmark-cmd'" #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u articles non-lus" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "Titre: " #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "Auteur: " #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "Date: " #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "Lien: " #: src/controller.cpp:1388 #, fuzzy, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "Erreur, impossible d'écrire l'article dans %s" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "Aucun élément sélectionné" #: src/dialogs_formaction.cpp:74 #, fuzzy msgid "Error: you can't remove the feed list!" msgstr "Erreur: vous ne pouvez recharger les résultats de recherche." #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "Position invalide!" #: src/download.cpp:42 msgid "queued" msgstr "mis à la queue" #: src/download.cpp:44 msgid "downloading" msgstr "téléchargement" #: src/download.cpp:46 msgid "cancelled" msgstr "annulé" #: src/download.cpp:48 msgid "deleted" msgstr "supprimé" #: src/download.cpp:50 msgid "finished" msgstr "terminé" #: src/download.cpp:52 msgid "failed" msgstr "manqué" #: src/download.cpp:54 msgid "incomplete" msgstr "incomplet" #: src/download.cpp:56 #, fuzzy msgid "played" msgstr "Jouer" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "inconnu (bug)." #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "L'attribut '%s' n'est pas disponible" #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "paramètres invalides" #: src/exception.cpp:43 msgid "too few parameters." msgstr "paramètres insuffisants." #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "commande inconnue (bug)." #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "le fichier n'a pu être ouvert" #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "erreur inconnue (bug)." #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "Aucun fil sélectionné !" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "n" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "Noter le fil lu..." #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "Erreur: impossible de noter le fil comme lu %s" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "Aucun fil avec des éléments non lus" #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "" #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "" #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "Noter tous les fils lus..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "Aucun tag définis." #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, fuzzy, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "Erreur: impossible d'analyser la commande de filtre %s !" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "Aucun filtre définis." #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "Rechercher: " #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "Filtre: " #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "Voulez vous vraiment quitter (y: Oui n: Non) ?" #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "on" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "o" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "Quitter" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "Ouvrir" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "Prochain non-lu" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "Recharger" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "Recharger Tous" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "Notez Lu" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "Notez tous les messages comme lus" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "Rechercher" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "Aide" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "Erreur: impossible d'analyser la commande de filtre %s !" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "Recherche en cours..." #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "Erreur lors de la recherche pour '%s': %s" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "Aucun résultat." #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "Position non visible!" #: src/feedlist_formaction.cpp:774 #, fuzzy, c-format msgid "Feed List - %u unread, %u total" msgstr "%N %V - Résultats de recherche (%u non lus, %t total) " #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "Voulez-vous vraiment écraser `%s' (y:Oui n:No)? " #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "Fichier: " #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - Ouvrir Fichier - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - Enregistrer Fichier - %s" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "Annuler" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "Enregistrer" #: src/filebrowser_formaction.cpp:271 #, fuzzy, c-format msgid "Open File - %s" msgstr "%s %s - Ouvrir Fichier - %s" #: src/filebrowser_formaction.cpp:273 #, fuzzy, c-format msgid "Save File - %s" msgstr "%s %s - Enregistrer Fichier - %s" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, fuzzy, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "Erreur: impossible d'analyser la commande de filtre %s !" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "Mode d'emploi: set [=]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "" #: src/formaction.cpp:231 #, fuzzy, c-format msgid "Saved configuration to %s" msgstr "Article enregistré dans %s" #: src/formaction.cpp:236 #, fuzzy, c-format msgid "Not a command: %s" msgstr "commande inconnue `%s'" #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "Enregistrement du marque-page..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "Marque page sauvegardé." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "Erreur lors de l'enregistrement du marque-page: " #: src/formaction.cpp:303 msgid "URL: " msgstr "URL: " #: src/formaction.cpp:305 msgid "Description: " msgstr "Description: " #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "" #: src/googlereader_urlreader.cpp:34 #, fuzzy msgid "Starred items" msgstr "Aucun élément non-lu." #: src/googlereader_urlreader.cpp:35 #, fuzzy msgid "Shared items" msgstr "Aucun élément non-lu." #: src/googlereader_urlreader.cpp:36 #, fuzzy msgid "Popular items" msgstr "Aucun élément non-lu." #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "Effacer" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "flash embarqué:" #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "image" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "Liens:" #: src/htmlrenderer.cpp:594 msgid "link" msgstr "lien" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "flash embarqué" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "inconnu (bug)" #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "Basculer le drapeau de lecture pour cet article..." #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "Erreur lors de la bascule du drapeau de lecture: %s" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "List d'URL vide" #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "Drapeaux: " #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "Erreur: aucun élément sélectionné" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "Erreur: vous ne pouvez recharger les résultats de recherche." #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "Aucun élément non-lu." #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "" #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "" #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "Aucun fil non-lu." #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "" #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 #, fuzzy msgid "dtfalg" msgstr "Editer drapeaux" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "Drapeaux mis-à-jour" #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "Notez Tous Non-Lus" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "Enregistrement avorté." #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "Article enregistré dans %s" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "Erreur: impossible d'enregistrer l'article dans %s" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "" #: src/itemlist_formaction.cpp:1004 #, fuzzy, c-format msgid "Article List - %s" msgstr "Article enregistré dans %s" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "Haut" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "Bas" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "Fil: " #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "URL de téléchargement de Podcast: " #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "type: " #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "Erreur en notant un article comme lu: %s" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "Ajout de %s à la queue de téléchargement." #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "Article enregistré dans %s." #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "Erreur, impossible d'écrire l'article dans %s" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "Lancement du navigateur..." #: src/itemview_formaction.cpp:328 #, fuzzy, c-format msgid "Error while marking article as unread: %s" msgstr "Erreur en notant un article comme lu: %s" #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "Ouvrir dans le navigateur" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "Mettre à la Queue" #: src/itemview_formaction.cpp:586 #, fuzzy, c-format msgid "Article - %s" msgstr "Article enregistré dans %s" #: src/itemview_formaction.cpp:624 #, fuzzy msgid "Error: invalid regular expression!" msgstr "Erreur: fil invalide !" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "Ouvrir fil/article" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "Retourner au précédent dialogue/Quitter" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "Recharger le fil actuellement sélectionné" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "Recharger tous les fils" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "Noter le fil comme lu" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "Noter tous les fils comme lus" #: src/keymap.cpp:30 msgid "Save article" msgstr "Enregistrer article" #: src/keymap.cpp:31 #, fuzzy msgid "Go to next article" msgstr "Aller au prochain article non lu" #: src/keymap.cpp:32 #, fuzzy msgid "Go to previous article" msgstr "Aller au précédent article non lu" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "Aller au prochain article non lu" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "Aller au précédent article non lu" #: src/keymap.cpp:35 #, fuzzy msgid "Go to a random unread article" msgstr "Aller au prochain article non lu" #: src/keymap.cpp:36 #, fuzzy msgid "Open article in browser and mark read" msgstr "Ouvrir l'article dans le navigateur" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "Ouvrir l'article dans le navigateur" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "Ouvrir la page d'aide" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "Basculer l'affichage de la source" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "Basculer le status de lecture pour cet article" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "Basculer l'affichage des fils lus / articles" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "Afficher les URLs dans l'article en cours" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "Supprimer les tag en cours" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "Sélectionner tag" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "Ouvrir la page de recherche" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "Ajouter un téléchargement à la queue" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "Recharger la liste des URLs depuis la configuration" #: src/keymap.cpp:50 msgid "Download file" msgstr "Télécharger fichier" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "Annuler téléchargement" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "Noter un téléchargement comme supprimé" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "Vider les téléchargements finis et supprimés de la queue" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "Basculer le téléchargement automatique" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "Démarrer le lecteur avec le fichier téléchargé sélectionné" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "Augmenter le nombre de téléchargements en parallèle" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "Diminuer le nombre de téléchargements en parallèle" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "Rafraîchier l'écran" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "Ouvrir la ligne de commande" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "Appliquer un filtre" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "Sélectionnez un filtre prédéfinit" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "Supprimer les filtres en cours" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "Mettre un marque-page sur le lien/article courant" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "Editer drapeaux" #: src/keymap.cpp:65 #, fuzzy msgid "Go to next feed" msgstr "Aller au prochain fil non lu" #: src/keymap.cpp:66 #, fuzzy msgid "Go to previous feed" msgstr "Aller au précédent fil non lu" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "Aller au prochain fil non lu" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "Aller au précédent fil non lu" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "Appeler une macro" #: src/keymap.cpp:70 msgid "Delete article" msgstr "Supprimer l'article" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "Purger les articles supprimés" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "" #: src/keymap.cpp:73 #, fuzzy msgid "Close currently selected dialog" msgstr "Recharger le fil actuellement sélectionné" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "" #: src/keymap.cpp:75 #, fuzzy msgid "Go to next dialog" msgstr "Aller au prochain article non lu" #: src/keymap.cpp:76 #, fuzzy msgid "Go to previous dialog" msgstr "Retourner au précédent dialogue/Quitter" #: src/keymap.cpp:77 #, fuzzy msgid "Pipe article to command" msgstr "Article enregistré dans %s" #: src/keymap.cpp:78 #, fuzzy msgid "Sort current list" msgstr "Supprimer les tag en cours" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "" #: src/keymap.cpp:92 #, fuzzy msgid "Move to the previous entry" msgstr "Aller au précédent fil non lu" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "" #: src/keymap.cpp:94 #, fuzzy msgid "Move to the previous page" msgstr "Retourner au précédent dialogue/Quitter" #: src/keymap.cpp:95 #, fuzzy msgid "Move to the next page" msgstr "Aller au prochain article non lu" #: src/keymap.cpp:97 #, fuzzy msgid "Move to the start of page/list" msgstr "Aller au prochain article non lu" #: src/keymap.cpp:98 #, fuzzy msgid "Move to the end of page/list" msgstr "Aller au prochain article non lu" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "Nettoyage de la queue..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "utilisation %s [-C ] [-q ] [-h]\n" "-C lire le fichier de configuration depuis \n" "-q utiliser comme fichier de queue\n" "-a débuter le téléchargement au démarrage\n" "-h afficher cette aide\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr " - %u téléchargements parallèles" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "Queue (%u téléchargements en cours, %u total) - %.2f kb/s total%s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "Erreur: impossible de quitter: téléchargement(s) en cours" #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "" "Erreur: le téléchargement doit être terminé avant que le fichier puisse être " "lu" #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "Erreur: impossible d'accomplir l'opération: téléchargement(s) en cours" #: src/pb_view.cpp:276 msgid "Download" msgstr "Télécharger" #: src/pb_view.cpp:278 msgid "Delete" msgstr "Supprimer" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "Vider les Téléchargements Finis" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "Basculer le téléchargement automatique" #: src/pb_view.cpp:281 msgid "Play" msgstr "Jouer" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "" #: src/regexmanager.cpp:49 #, fuzzy, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "Erreur: fil invalide !" #: src/rss.cpp:466 #, fuzzy msgid "too few arguments" msgstr "paramètres insuffisants." #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "Erreur, URL non supportée: %s" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "Sélectionner Tag" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "Sélectionner Filtre" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "Attribut non-trouvé" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "EOF trouvé en lisant un tag XML" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "Aucun lien sélectionné !" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "Enregistrez marque-page" #: src/urlview_formaction.cpp:146 #, fuzzy msgid "URLs" msgstr "URL: " #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "Erreur, l'application du filtre a échoué: %s" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "Erreur: le fil ne contient aucun élément !" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "Mise à jour du fil.." #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "" #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "" #: rss/parser.cpp:174 #, fuzzy msgid "could not parse file" msgstr "Erreur: impossible d'analyser la commande de filtre %s !" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "" #: rss/parser.cpp:211 #, fuzzy msgid "invalid RSS version" msgstr "Position invalide!" #: rss/parser.cpp:226 rss/parser.cpp:233 #, fuzzy msgid "invalid Atom version" msgstr "Position invalide!" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "" #, fuzzy #~ msgid "" #~ "%s %s\n" #~ "usage: %s [-i |-e] [-u ] [-c ] [-x " #~ " ...] [-h]\n" #~ "-e export OPML feed to stdout\n" #~ "-r refresh feeds on start\n" #~ "-i import OPML file\n" #~ "-u read RSS feed URLs from \n" #~ "-c use as cache file\n" #~ "-C read configuration from \n" #~ "-v clean up cache thoroughly\n" #~ "-x ... execute list of commands\n" #~ "-o activate offline mode (only applies to bloglines " #~ "synchronization mode)\n" #~ "-V get version information\n" #~ "-l write a log with a certain loglevel (valid values: 1 to " #~ "6)\n" #~ "-d use as output log file\n" #~ "-E export list of read articles to \n" #~ "-I import list of read articles from \n" #~ "-h this help\n" #~ msgstr "" #~ "%s %s\n" #~ "utilisation: %s [-i |-e] [-u ] [-c ] " #~ "[-x ] [-h]\n" #~ "-e exporte un fil OPML vers la sortie standard\n" #~ "-r met à jour les fils au démarrage\n" #~ "-i importe un fichier OPML\n" #~ "-u lire les URLs de fils RSS depuis \n" #~ "-c utiliser comme un fichier cache\n" #~ "-C lire la configuration depuis \n" #~ "-v vider le cache\n" #~ "-x exécute une liste de commandes\n" #~ "-o activer le mode hors-ligne (s'applique uniquement en " #~ "mode Bloglines)\n" #~ "-V afficher des informations sur la version du logiciel\n" #~ "-l écrire un fichier de log avec un certain niveau (valeurs " #~ "valides: 1 à 6)\n" #~ "-d utiliser comme fichier de log en sortie\n" #~ "-h affiche cette aide\n" newsbeuter-2.7/po/hu.po000066400000000000000000001176141220711462700151530ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) 2008-2009. # This file is distributed under the same license as the newsbeuter package. # Zsolt Udvari , 2008-2009. # msgid "" msgstr "" "Project-Id-Version: 0.7\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2008-01-28 10:00+GMT+1\n" "Last-Translator: Zsolt Udvari \n" "Language-Team: Hungarian \n" "Language: hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "`%s' nem érvényes szín" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, c-format msgid "`%s' is not a valid attribute" msgstr "`%s' nem érvényes attríbútum" #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "`%s' nem érvényes konfigurációs elem" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "" "newsbeuter: újratöltés befejezve, %f olvasatlan üzenet (%n olvasatlan " "összesen)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - Hírek (%u olvasatlan, %t összesen)%?T? - cimke `%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - Cikkek '%T'-ben (%u olvasatlan, %t összesen) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - Keresési eredmény (%u olvasatlan, %t összesen)" #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?File megnyitása&Menti a fájlt? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - Súgó" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - Cimke kiválasztása" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - Szűrő kiválasztása" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - Cikk '%T'" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - URL" #: src/configcontainer.cpp:111 msgid "%N %V - Dialogs" msgstr "%N %V - Dialógusok" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "logikai értéket várok, viszont `%s'-t találtam" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "egész értéket várok, viszont `%s'-t találtam" #: src/configcontainer.cpp:159 #, c-format msgid "invalid configuration value `%s'" msgstr "érvénytelen konfigurációs érték: `%s'" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "Hiba a `%s' (%s line %u) parancs végrehajtása közben: %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "ismeretlen parancs: `%s'" #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "Végzetes hiba: nem tudtam meghatározni a home-könyvtárat!" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "" "Kérlek, állítsd be a HOME változót vagy adj valódi felhasználót a(z) %u UID-" "hoz!" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: ismeretlen opció - %c" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "%s %s indítása..." #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "Hiba: egy példány már fut %s-ből (PID: %u)" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "Konfiguráció betöltése..." #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "kész." #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "Cache megnyitása..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "Hiba `%s' cache-file megnyitása közben: %s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "URL-ek betöltése a helyi cache-bõl..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "URL-ek betöltése %s-ből..." #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "" "Hiba: nincs URL beállítva. Kérlek töltsd fel a(z) %s file-t RSS URL-ekkel " "vagy importálj egy OPML file-ból." #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "" "Úgy tűnik, az OPML, amit betöltöttél, nem tartalmaz hírforrásokat. Töltsd " "fel forrásokkal és próbáld újra!" #: src/controller.cpp:392 msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" "Úgy tűnik, még nem konfiguráltál semmilyen forrást a Google Reader " "fiókodban. Tedd meg, és próbáld újra!" #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "Cikkek töltése a cache-bõl..." #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "A cache teljes ürítése..." #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "Nem sikerült betölteni a forrásokat az adatbázisból: " #: src/controller.cpp:430 #, c-format msgid "Error while loading feed '%s': %s" msgstr "Hiba a `%s' forrás betöltése közben: %s" #: src/controller.cpp:448 msgid "Prepopulating query feeds..." msgstr "A lekérdezési mezők kezdeti feltöltése..." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "Olvasott cikkek listájának importálása..." #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "Olvasott cikkek listájának exportálása..." #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "A cache takarítása..." #: src/controller.cpp:523 msgid "failed: " msgstr "nem sikerült: " #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "Hiba: nem tudtam olvasottnak megjelölni: %s" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%sTöltés %s..." #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "Hiba letöltés közben: %s: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "Hiba: érvénytelen hírforrás!" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "érvénytelen hírforrás index (bug)" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "" "newsbeuter egy ingyenes szoftver és MIT/X Consortium License-szel " "rendelkezik." #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "Írj be `%s -vv'-t több információért." #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" "%s %s\n" "használat: %s [-i |-e] [-u ] [-c ] [-x " " ...] [-h]\n" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "OPML exportálása az stdout-ra" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "források frissítése induláskor" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 msgid "" msgstr "" #: src/controller.cpp:842 msgid "import OPML file" msgstr "OPML fájl importálása" #: src/controller.cpp:843 msgid "" msgstr "" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "RSS források URL-jeinek olvasása -ból" #: src/controller.cpp:844 msgid "" msgstr "" #: src/controller.cpp:844 msgid "use as cache file" msgstr " használata cache fájlként" #: src/controller.cpp:845 msgid "" msgstr "" #: src/controller.cpp:845 msgid "read configuration from " msgstr "beállítások olvasása -ból" #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "a cache teljes ürítése" #: src/controller.cpp:847 msgid "..." msgstr "..." #: src/controller.cpp:847 msgid "execute list of commands" msgstr "parancsok listájának futtatása" #: src/controller.cpp:848 #, fuzzy msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "offline mód aktiválása (csak a blogline szinkronizációra érvényes)" #: src/controller.cpp:849 msgid "quiet startup" msgstr "" #: src/controller.cpp:850 msgid "get version information" msgstr "verzió információ" #: src/controller.cpp:851 msgid "" msgstr "" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "log írása az adott szinten (érvényes értékek: 1-től 6-ig)" #: src/controller.cpp:852 msgid "" msgstr "" #: src/controller.cpp:852 msgid "use as output log file" msgstr " használata naplófájlként" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "olvasott cikkek listájának exportálása -ba" #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "olvasott cikkek listájának importálása -ból" #: src/controller.cpp:855 msgid "this help" msgstr "ez a súgó" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "Egy hiba lépett fel, miközben %s-t elemeztem." #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "%s importálása befejeződött." #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "" "könyvjelző lehetőség nem konfigurált. Kérlek állítsd be a `bookmark-cmd' " "változót megfelelően." #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u olvasatlan hír" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "Cím: " #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "Szerzõ: " #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "Dátum: " #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "Link: " #: src/controller.cpp:1388 #, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "Hiba: nem tudtam megnyitni a(z) `%s' konfigurációs fájlt!" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "Bezár" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "Goto Dialógus" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "Bezár Dialógus" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "Nincs elem kijelölve!" #: src/dialogs_formaction.cpp:74 msgid "Error: you can't remove the feed list!" msgstr "Hiba: nem törölheted a cikk listát!" #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "Érvénytelen pozíció!" #: src/download.cpp:42 msgid "queued" msgstr "listába" #: src/download.cpp:44 msgid "downloading" msgstr "letöltés" #: src/download.cpp:46 msgid "cancelled" msgstr "megszakítva" #: src/download.cpp:48 msgid "deleted" msgstr "törölve" #: src/download.cpp:50 msgid "finished" msgstr "befejezve" #: src/download.cpp:52 msgid "failed" msgstr "hibás" #: src/download.cpp:54 msgid "incomplete" msgstr "befejezetlen" #: src/download.cpp:56 msgid "played" msgstr "lejátszott" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "ismeretlen (bug)." #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "%s argumentum nem elérhető." #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "'%s' reguláris kifejezés érvénytelen: %s" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "érvénytelen paraméter." #: src/exception.cpp:43 msgid "too few parameters." msgstr "túl kevés paraméter." #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "ismeretlen parancs (bug)." #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "a file-t nem tudtam megnyitni." #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "ismeretlen hiba (bug)." #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "Nincs forrás kijelölve" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "" "Rendezés (e)lső cimke/(c)ím/cikk(s)zám/(o)olvasatlan források száma/semmi " "szeri(n)t?" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "ecson" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "e" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "c" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "s" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "o" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "n" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "" "Visszafele rendezés (e)lső cimke/(c)ím/cikk(s)zám/(o)olvasatlan források " "száma/semmi szeri(n)t?" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "Forrás olvasottá tétele..." #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "Hiba: nem tudtam olvasottnak megjelölni: %s" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "Nincs forrás olvasatlan elemekkel." #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "" #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "" #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "Az összes forrás olvasottként jelölése..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "Nincs cimke definiálva." #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "Hiba: nem tudtam feldolgozni a filter parancsot: `%s': %s" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "Nincs szűrő (filter) definiálva." #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "Keresés: " #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "Filter: " #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "Biztos kilépsz (i:Igen n:Nem)? " #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "in" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "i" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "Kilép" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "Megnyit" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "Köv. olvasatlan" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "Újratölt" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "Mind újratölt" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "Olvasottnak megjelöl" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "Mind elkapása" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "Keres" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "Súgó" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "Hiba: nem tudtam feldolgozni a filter parancsot!" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "Keresés..." #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "Hiba `%s' keresése közben: %s" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "Nincs találat." #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "A pozíció nem látható!" #: src/feedlist_formaction.cpp:774 #, c-format msgid "Feed List - %u unread, %u total" msgstr "Forrás lista - %u olvasatlan, %u összesen" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "Biztos felülírod `%s'-t (y:Yes n:No)? " #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "File: " #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - File megnyitása - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - File mentése - %s" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "Mégsem" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "Mentés" #: src/filebrowser_formaction.cpp:271 #, c-format msgid "Open File - %s" msgstr "File megnyitása - %s" #: src/filebrowser_formaction.cpp:273 #, c-format msgid "Save File - %s" msgstr "File mentése - %s" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "nem tudtam feldolgozni a filter parancsot `%s': %s" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "használat: set [=<érték>]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "használat: source [...]" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "használat: dumpconfig " #: src/formaction.cpp:231 #, c-format msgid "Saved configuration to %s" msgstr "Konfiguráció elmentve %s-be" #: src/formaction.cpp:236 #, c-format msgid "Not a command: %s" msgstr "Nem parancs: %s" #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "Könyvjelző mentése..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "Könyvjelző elmentve." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "Hiba a könyvjelző mentése közben: " #: src/formaction.cpp:303 msgid "URL: " msgstr "URL: " #: src/formaction.cpp:305 msgid "Description: " msgstr "Leírás: " #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "Akik téged követnek" #: src/googlereader_urlreader.cpp:34 msgid "Starred items" msgstr "Csillagozott elemek" #: src/googlereader_urlreader.cpp:35 msgid "Shared items" msgstr "Megosztott elemek" #: src/googlereader_urlreader.cpp:36 msgid "Popular items" msgstr "Népszerű elemek" #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "Általános kötések:" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "Kötetlen funkciók:" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "Vissza" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "beágyazott flash: " #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "kép" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "Linkek: " #: src/htmlrenderer.cpp:594 msgid "link" msgstr "link" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "beágyazott flash" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "ismeretlen (bug)" #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "Az olvasott jelző ki/beállítása a cikkre..." #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "Hiba az olvasott jelző állítása közben: %s" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "URL lista üres." #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "Jelzõk: " #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "Hiba: nincs elem kijelölve!" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "Hiba: nem töltheted újra a keresési eredményt." #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "Nincs olvasatlan elem." #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "" #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "" #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "Nincs olvasatlan forrás." #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "A cikk pipe-olása a parancsnak: " #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "Rendezés (d)átum/(c)ím/(j)elzők/(s)zerző/(l)ink/(g)uid alapján?" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 msgid "dtfalg" msgstr "dcjslg" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "d" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "c" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "j" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" "Fordított rendezés (d)átum/(c)ím/(j)elzők/(s)zerző/(l)ink/(g)uid alapján?" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "Jelzők frissítve." #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "Mindet olvasottnak" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "Mentés megszakítva." #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "Cikk mentése %s-be" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "Hiba: nem tudtam a cikket %s fájlba menteni" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "Keresés eredménye . '%s'" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "Lekérdezési lista - %s" #: src/itemlist_formaction.cpp:1004 #, c-format msgid "Article List - %s" msgstr "Cikk lista - %s" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "Fent" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "Lent" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "Forrás: " #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "Podcast letöltés URL: " #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "típus: " #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "Hiba a cikk olvasottá tétele közben: %s " #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "%s hozzáadása a letöltési listához." #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "Érvénytelen URL: '%s'" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "Cikk mentve %s-be." #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "Hiba: nem tudtam a cikket a(z) %s file-ba menteni" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "Böngésző indítása..." #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "Hiba a cikk olvasatlanná tétele közben: %s " #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "Ugrás: URL #" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "Megnyitás böngészőben" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "Lista" #: src/itemview_formaction.cpp:586 #, c-format msgid "Article - %s" msgstr "Cikk %s" #: src/itemview_formaction.cpp:624 msgid "Error: invalid regular expression!" msgstr "Hiba: érvénytelen reguláris kifejezés!" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "Forrás/cikk megnyitása" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "Vissza az előzőhöz/Kilépés" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "Kilépés a programból, megerősítés nélkül" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "Az aktuális forrás újratöltése" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "Összes forrás újratöltése" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "Forrás olvasottá" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "Összes forrás olvasottá" #: src/keymap.cpp:30 msgid "Save article" msgstr "Cikk mentése" #: src/keymap.cpp:31 #, fuzzy msgid "Go to next article" msgstr "Következő olvasatlan cikk" #: src/keymap.cpp:32 #, fuzzy msgid "Go to previous article" msgstr "Elõző olvasatlan cikk" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "Következő olvasatlan cikk" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "Elõző olvasatlan cikk" #: src/keymap.cpp:35 msgid "Go to a random unread article" msgstr "Véletlenszerű olvasatlan cikk" #: src/keymap.cpp:36 #, fuzzy msgid "Open article in browser and mark read" msgstr "Cikk megnyitása böngészőben" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "Cikk megnyitása böngészőben" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "Súgó megnyitása" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "Forrás nézet" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "Olvasott státusz ki/beállítása a cikkre" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "Olvasott források mutatása" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "URL-ek az aktuális cikkben" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "Aktuális cimke törlése" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "Cimke kijelölése" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "Keresés megnyitása" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "Letöltési listához hozzáad" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "Az URL-ek listájának újratöltése" #: src/keymap.cpp:50 msgid "Download file" msgstr "Fájl letöltése" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "Letöltés megszakítása" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "Letöltés töröltnek nyilvánítása" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "Befejezett és törölt letöltések ürítése a listából" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "Automatikus letöltés be/ki" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "Lejátszó indítása a kijelölt letöltéssel" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "Párhuzamos letöltések számának növelése" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "Párhuzamos letöltések számának csökkentése" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "Képernyő újrarajzolása" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "Parancssor nyitása" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "Szűrő állítása" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "Előredefiniált szűrő kiválasztása" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "Aktuális szűrő törlése" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "Aktuális link/cikk könyvjelzőbe" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "Jelzők szerkesztése" #: src/keymap.cpp:65 #, fuzzy msgid "Go to next feed" msgstr "Következő olvasatlan forrás" #: src/keymap.cpp:66 #, fuzzy msgid "Go to previous feed" msgstr "Előző olvasatlan forrás" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "Következő olvasatlan forrás" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "Előző olvasatlan forrás" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "Makró hívása" #: src/keymap.cpp:70 msgid "Delete article" msgstr "Cikk törlése" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "Végleges törlés" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "Feliratkozott URL-ek szerkesztése" #: src/keymap.cpp:73 msgid "Close currently selected dialog" msgstr "Az aktuálisan kijelölt dialógus bezárása" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "Megnyitott dialógusok listája" #: src/keymap.cpp:75 msgid "Go to next dialog" msgstr "Következő dialógus" #: src/keymap.cpp:76 msgid "Go to previous dialog" msgstr "Előző dialógus" #: src/keymap.cpp:77 msgid "Pipe article to command" msgstr "Cikk pipe-olása parancsnak" #: src/keymap.cpp:78 msgid "Sort current list" msgstr "Aktuális lista rendezése" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "Aktuális lista rendezése (fordított)" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "10. URL megnyitása" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "1. URL megnyitása" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "2. URL megnyitása" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "3. URL megnyitása" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "4. URL megnyitása" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "5. URL megnyitása" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "6. URL megnyitása" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "7. URL megnyitása" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "8. URL megnyitása" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "9. URL megnyitása" #: src/keymap.cpp:92 msgid "Move to the previous entry" msgstr "Előző bejegyzés" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "Következő bejegyzés" #: src/keymap.cpp:94 msgid "Move to the previous page" msgstr "Az előző oldalra" #: src/keymap.cpp:95 msgid "Move to the next page" msgstr "A következő oldalra" #: src/keymap.cpp:97 msgid "Move to the start of page/list" msgstr "Mozgatás az oldal/lista elejére" #: src/keymap.cpp:98 msgid "Move to the end of page/list" msgstr "Mozgatás az oldal/lista végére" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "`%s' nem valódi környezet" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "`%s' nem érvényes billentyűparancs" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "Lista törlése..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "használat %s [-C ] [-h]\n" "-C beállítások -ból\n" "-q használata listaként\n" "-a\t\t letöltés megkezdése induláskor\n" "-h ez a súgó\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr " - %u párhuzamos letöltés" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "Lista (%u letöltés folyamatban, %u összesen) - %.2f kb/s összesen%s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "Hiba: nem léphetsz ki: letöltés(ek) folyamatban." #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "Hiba: a letöltésnek be kell fejeződnie, mielőtt lejátszhatnád." #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "Hiba: nem hajthatom végre: letöltés(ek) folyamatban." #: src/pb_view.cpp:276 msgid "Download" msgstr "Letöltés" #: src/pb_view.cpp:278 msgid "Delete" msgstr "Törlés" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "Takarítás befejezve" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "Automatikus letöltés" #: src/pb_view.cpp:281 msgid "Play" msgstr "Lejátszás" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "`%s' érvénytelen dialógus típus" #: src/regexmanager.cpp:49 #, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "`%s' nem valódi reguláris kifejezés: %s" #: src/rss.cpp:466 msgid "too few arguments" msgstr "túl kevés paraméter" #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "Hiba: nem támogatott URL: %s" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "Cimke kijelölése" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "Szűrő kijelölése" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "argumentumot nem találom" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "EOF-t találtam XML cimke olvasása közben" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "Nincs link kijelölve!" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "Könyvjelző mentése" #: src/urlview_formaction.cpp:146 msgid "URLs" msgstr "URL-ek: " #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "Hiba: szűrő alkalmazása nem sikerült: %s" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "Hiba: a forrás nem tartalmaz elemeket!" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "Források lekérdezése..." #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "XML gyökér bejegyzés NULL" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "nem tudtam inicializálni a libcurl-t" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "" "Hiba: miközben `%s' forrásból való töltés a következő HTTP kóddal tért " "vissza: %ld." #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "nem tudtam a buffer-t elemezni" #: rss/parser.cpp:174 msgid "could not parse file" msgstr "nem tudtam feldolgozni a file-t" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "nincs RSS verzió" #: rss/parser.cpp:211 msgid "invalid RSS version" msgstr "érvénytelen RSS verzió" #: rss/parser.cpp:226 rss/parser.cpp:233 msgid "invalid Atom version" msgstr "érvénytelen Atom verzió" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "nincs Atom verzió" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "nem támogatott forrás formátum" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "nem találtam RSS csatornát" #~ msgid "" #~ "%s %s\n" #~ "usage: %s [-i |-e] [-u ] [-c ] [-x " #~ " ...] [-h]\n" #~ "-e export OPML feed to stdout\n" #~ "-r refresh feeds on start\n" #~ "-i import OPML file\n" #~ "-u read RSS feed URLs from \n" #~ "-c use as cache file\n" #~ "-C read configuration from \n" #~ "-v clean up cache thoroughly\n" #~ "-x ... execute list of commands\n" #~ "-o activate offline mode (only applies to bloglines " #~ "synchronization mode)\n" #~ "-V get version information\n" #~ "-l write a log with a certain loglevel (valid values: 1 to " #~ "6)\n" #~ "-d use as output log file\n" #~ "-E export list of read articles to \n" #~ "-I import list of read articles from \n" #~ "-h this help\n" #~ msgstr "" #~ "%s %s\n" #~ "használat: %s [-i |-e] [-u ] [-c ] [-x " #~ " ] [-h]\n" #~ "-e exportálás OPML-be a stdout-ra\n" #~ "-r hírforrások frissítése indításkor\n" #~ "-i OPML file importálása\n" #~ "-u RSS források URL-jeink olvasása -ból\n" #~ "-c használata cache file-ként\n" #~ "-C beállítások olvasása -ból\n" #~ "-v cache teljes tisztítása\n" #~ "-x ... parancsok végrehajtása\n" #~ "-o offline mód (bloglines szinkronizáció mód)\n" #~ "-V verzió információ\n" #~ "-l log-olási szint beállítása (értékei lehetnek: 1-től 6-" #~ "ig)\n" #~ "-d használata a log-ok tárolására\n" #~ "-E olvasott cikkek exportálása -ba\n" #~ "-I olvasott cikkek importálása -ból\n" #~ "-h ez a súgó\n" newsbeuter-2.7/po/it.po000066400000000000000000001143121220711462700151430ustar00rootroot00000000000000# # Italian translation for newsbeuter. # Copyright (C) Claudio M. Alessi # This file is distributed under the same license as the newsbeuter package. # Claudio M. Alessi , 2009 # msgid "" msgstr "" "Project-Id-Version: newsbeuter 2.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2010-04-29 12:01+0200\n" "Last-Translator: Andrea Marchesini \n" "Language-Team: Claudio M. Alessi \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Italian\n" "X-Poedit-Country: ITALY\n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "`%s' non è un colore valido" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, c-format msgid "`%s' is not a valid attribute" msgstr "`%s' non è un attributo valido" #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "`%s' non è un elemento di configurazione valido" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "" "newsbeuter: caricamento terminato, %f feed non letti (%n totale articoli non " "letti)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - I tuoi feed (%u non letti, %t totali)%?T? - tag `%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - Articoli nel feed '%T' (%u non letti, %t totali) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - Risultati della ricerca (%u non letti, %t totali) " #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?Apri File&Salva File? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - Aiuto" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - Seleziona Tag" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - Seleziona Filtro" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - Articolo '%T'" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - URL" #: src/configcontainer.cpp:111 msgid "%N %V - Dialogs" msgstr "%N %V - Schermate" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "atteso valore booleano, trovato `%s' invece" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "atteso valore intero, trovato `%s' invece" #: src/configcontainer.cpp:159 #, c-format msgid "invalid configuration value `%s'" msgstr "Valore di configurazione non valido %s" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "Errore elaborando il comando `%s' (%s linea %u): %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "comando sconosciuto `%s'" #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "Errore fatale: impossibile determinare la directory home!" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "" "Si prega di impostare la variabile d'ambiente HOME o aggiungere un utente " "valido per l'UID %u!" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: opzione sconosciuta - %c" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "Sto avviando %s %s..." #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "Errore: un'istanza di %s è già in esecuzione (PID: %u)" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "Sto caricando la configurazione..." #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "fatto." #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "Sto aprendo la cache..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "Errore: apertura del file cache `%s' fallita: %s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "Sto caricando gli URL dalla cache locale..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "Sto caricando gli URL da %s..." #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "" "Errore: nessun URL configurato. Si prega di inserire nel file %s gli URL dei " "feed RSS o importare un file OPML." #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "" "Sembra che il feed OPML di cui hai chiesto la sottoscrizione non contenga " "feed. Sei pregato di inserire i feed, e riprovare." #: src/controller.cpp:392 msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" "Sembra che tu non abbia configurato alcun feed nel tuo account di Google " "Reader. Sei pregato di farlo e riprovare." #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "Sto caricando gli articoli dalla cache..." #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "Sto pulendo accuratamente la cache..." #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "Errore durante il caricamento dei feed dal database: " #: src/controller.cpp:430 #, c-format msgid "Error while loading feed '%s': %s" msgstr "Errore durante il caricamento del feed `%s': %s" #: src/controller.cpp:448 msgid "Prepopulating query feeds..." msgstr "Sto precompilando l'interrogazione dei feed..." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "Sto importando la lista degli articoli letti..." #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "Sto esportando la lista degli articoli letti..." #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "Sto pulendo la cache..." #: src/controller.cpp:523 msgid "failed: " msgstr "fallito: " #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "Errore: impossibile contrassegnare tutti i feed letti: %s" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%sSto caricando %s..." #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "Errore durante il recupero di %s: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "Errore: feed non valido!" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "indice del feed non valido (bug)" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "" "newsbeuter è software libero e concesso in licenza nei termini della Licenza " "MIT/X Consortium." #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "Digita `%s -vv' per maggiori informazioni." #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" "%s %s\n" "uso: %s [-i |-e] [-u ] [-c ] [-x ...] [-" "h]\n" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "esporta il feed OPML sullo stdout" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "ricarica i feed all'avvio" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 msgid "" msgstr "" #: src/controller.cpp:842 msgid "import OPML file" msgstr "importa file OPML" #: src/controller.cpp:843 msgid "" msgstr "" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "leggi gli URL dei feed RSS da " #: src/controller.cpp:844 msgid "" msgstr "" #: src/controller.cpp:844 msgid "use as cache file" msgstr "usa come file cache" #: src/controller.cpp:845 msgid "" msgstr "" #: src/controller.cpp:845 msgid "read configuration from " msgstr "leggi la configurazione da " #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "pulisci accuratamente la cache" #: src/controller.cpp:847 msgid "..." msgstr "..." #: src/controller.cpp:847 msgid "execute list of commands" msgstr "esegui un elenco di comandi" #: src/controller.cpp:848 #, fuzzy msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "" "attiva modalità non in linea (si applica solo alla modalità sincronizzazione " "di bloglines)" #: src/controller.cpp:849 msgid "quiet startup" msgstr "" #: src/controller.cpp:850 msgid "get version information" msgstr "ottieni informazioni sulla versione" #: src/controller.cpp:851 msgid "" msgstr "" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "scrivi un log con un certo loglevel (valori validi: da 1 a 6)" #: src/controller.cpp:852 msgid "" msgstr "" #: src/controller.cpp:852 msgid "use as output log file" msgstr "usa come log file di output" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "esporta lista articoli letti su " #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "importa lista articoli letti da " #: src/controller.cpp:855 msgid "this help" msgstr "questo aiuto" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "Si è verificato un errore analizzando %s." #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "Importazione di %s finita." #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "" "supporto per i segnalibri non configurato. Si prega di impostare " "adeguatamente la variabile di configurazione `bookmark-cmd'." #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u articoli non letti" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "Titolo: " #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "Autore: " #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "Data: " #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "Collegamento: " #: src/controller.cpp:1388 #, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "Errore: impossibile aprire il file di configurazione `%s'!" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "Chiudi" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "Vai alla schermata" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "Chiudi schermata" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "Nessuna voce selezionata!" #: src/dialogs_formaction.cpp:74 msgid "Error: you can't remove the feed list!" msgstr "Errore: non puoi rimuovere la lista dei feed!" #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "Posizione non valida!" #: src/download.cpp:42 msgid "queued" msgstr "in coda" #: src/download.cpp:44 msgid "downloading" msgstr "sto scaricando" #: src/download.cpp:46 msgid "cancelled" msgstr "cancellato" #: src/download.cpp:48 msgid "deleted" msgstr "eliminato" #: src/download.cpp:50 msgid "finished" msgstr "finito" #: src/download.cpp:52 msgid "failed" msgstr "fallito" #: src/download.cpp:54 msgid "incomplete" msgstr "incompleto" #: src/download.cpp:56 msgid "played" msgstr "iniziato" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "sconosciuto (bug)." #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "l'attributo `%s' non è disponibile." #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "l'espressione regolare `%s' non è valida: %s" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "parametri non validi." #: src/exception.cpp:43 msgid "too few parameters." msgstr "parametri insufficienti." #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "comando sconosciuto (bug)." #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "Il file non può essere aperto." #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "errore sconosciuto (bug)." #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "Nessun feed selezionato!" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "" "Ordina per (p)rimotag/(t)itolo/n(u)meroarticolo/nu(m)eroarticolononletto/(n)" "iente?" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "ptumn" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "p" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "t" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "u" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "m" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "n" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "" "Ordina al contrario per (p)rimotag/(t)itolo/n(u)meroarticolo/nu(m)" "eroarticolononletto/(n)iente?" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "Sto contrassegnando il feed come letto..." #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "Errore: impossibile contrassegnare il feed come letto: %s" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "Nessun feed con voci non lette." #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "" #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "" #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "Sto segnando tutti i feed come letti..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "Nessun tag definito." #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "Errore: impossibile analizzare il comando di filtro `%s': %s" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "Nessun filtro definito." #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "Ricerca: " #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "Filtro: " #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "Vuoi veramente uscire (s:Si n:No)?" #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "sn" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "s" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "Esci" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "Apri" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "Prossimo non letto" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "Ricarica" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "Ricarica tutti" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "Segna come letto" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "Recupera tutti" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "Cerca" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "Aiuto" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "Errore: impossibile analizzare il comando di filtro!" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "Sto cercando..." #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "Errore durante la ricerca di `%s': %s" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "Nessun risultato." #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "Posizione non visibile!" #: src/feedlist_formaction.cpp:774 #, c-format msgid "Feed List - %u unread, %u total" msgstr "Lista feed - %u non letti, %u totali" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "Vuoi veramente sovrascrivere `%s' (s:Si n:No)? " #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "File: " #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - Apri File - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - Salva File - %s" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "Cancella" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "Salva" #: src/filebrowser_formaction.cpp:271 #, c-format msgid "Open File - %s" msgstr "Apri File - %s" #: src/filebrowser_formaction.cpp:273 #, c-format msgid "Save File - %s" msgstr "Salva File - %s" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "impossibile analizzare l'espressione di filtro `%s': %s" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "uso: set [=]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "uso: source [...]" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "uso: dumpconfig " #: src/formaction.cpp:231 #, c-format msgid "Saved configuration to %s" msgstr "Configurazione salvata su %s" #: src/formaction.cpp:236 #, c-format msgid "Not a command: %s" msgstr "Non è un comando: %s" #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "Sto salvando il segnalibro..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "Segnalibro salvato." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "Errore durante il salvataggio del segnalibro: " #: src/formaction.cpp:303 msgid "URL: " msgstr "URL: " #: src/formaction.cpp:305 msgid "Description: " msgstr "Descrizione:" #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "Persone che segui" #: src/googlereader_urlreader.cpp:34 msgid "Starred items" msgstr "Item selezionati" #: src/googlereader_urlreader.cpp:35 msgid "Shared items" msgstr "Item condivisi" #: src/googlereader_urlreader.cpp:36 msgid "Popular items" msgstr "Item popolari" #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "Associazioni di tasti generiche:" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "Funzioni non associate:" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "Pulisci" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "flash integrato:" #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "immagine" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "Collegamenti:" #: src/htmlrenderer.cpp:594 msgid "link" msgstr "collegamento" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "flash integrato" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "sconosciuto (bug)" #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "Cambiando la flag \"letto\" per l'articolo..." #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "Errore cambiando la flag \"letto\": %s" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "Lista URL vuota." #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "Flag: " #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "Errore: nessuna voce selezionata!" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "Errore: non puoi ricaricare i risultati della ricerca." #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "Nessuna voce non letta." #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "" #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "" #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "Nessun feed non letto." #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "Metti in pipe l'articolo col comando: " #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "Ordina per (d)ata/(t)itolo/(f)lag/(a)utore/(c)ollegamento/(g)uid?" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 msgid "dtfalg" msgstr "dtfacg" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "d" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "c" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "g" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" "Ordina al contrario per (d)ata/(t)itolo/(f)lag/(a)utore/(c)ollegamento/(g)" "uid?" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "Flag aggiornate." #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "Marca tutti come letti" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "Salvataggio annullato." #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "Articolo salvato su %s" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "Errore: impossibile salvare l'articolo su %s" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "Risultati della ricerca - '%s'" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "Feed interrogati - %s" #: src/itemlist_formaction.cpp:1004 #, c-format msgid "Article List - %s" msgstr "Lista articoli - %s" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "Su" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "Giù" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "Feed: " #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "URL scaricamento podcast: " #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "tipo: " #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "Errore contrassegnando l'articolo come letto: %s" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "Aggiunto %s alla coda dei download." #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "URL invalido: '%s'" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "Articolo salvato su %s." #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "Errore: impossibile scrivere l'articolo sul file %s" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "Sto avviando il browser..." #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "Errore contrassegnando l'articolo come non letto: %s" #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "Vai a URL #" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "Apri nel browser" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "Accoda" #: src/itemview_formaction.cpp:586 #, c-format msgid "Article - %s" msgstr "Articolo - %s" #: src/itemview_formaction.cpp:624 msgid "Error: invalid regular expression!" msgstr "Errore: espressione regolare non valida!" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "Apri feed/articolo" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "Torna alla schermata precedente/Esci" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "Programma in uscita, nessuna conferma" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "Ricarica il feed attualmente selezionato" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "Ricarica tutti i feed" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "Segna feed come letto" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "Segna tutti i feed come letti" #: src/keymap.cpp:30 msgid "Save article" msgstr "Salva articolo" #: src/keymap.cpp:31 #, fuzzy msgid "Go to next article" msgstr "Vai al prossimo articolo non letto" #: src/keymap.cpp:32 #, fuzzy msgid "Go to previous article" msgstr "Vai al precedente articolo non letto" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "Vai al prossimo articolo non letto" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "Vai al precedente articolo non letto" #: src/keymap.cpp:35 msgid "Go to a random unread article" msgstr "Vai su un articolo non letto a caso" #: src/keymap.cpp:36 #, fuzzy msgid "Open article in browser and mark read" msgstr "Apri l'articolo nel browser" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "Apri l'articolo nel browser" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "Apri schermata di aiuto" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "Attiva/Disattiva la visualizzazione del sorgente" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "Attiva/Disattiva lo stato di \"letto\" per l'articolo" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "Attiva/Disattiva la visualizzazione dei feed/articoli letti" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "Mostra gli URL nell'articolo corrente" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "Pulisci il tag corrente" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "Seleziona tag" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "Apri la schermata di ricerca" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "Aggiungi il download in coda" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "Ricarica la lista degli URL dalla configurazione" #: src/keymap.cpp:50 msgid "Download file" msgstr "Scarica file" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "Cancella download" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "Segna il download come eliminato" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "Elimina finiti e cancella i download dalla coda" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "Attiva/Disattiva download automatico on/off" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "Avvia il player con il download correntemente selezionato" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "Incrementa il numero di download paralleli" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "Decrementa il numero di download paralleli" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "Ridisegna lo schermo" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "Apri la riga di comando" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "Imposta un filtro" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "Seleziona un filtro predefinito" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "Pulisci il filtro correntemente impostato" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "Aggiungi il collegamento/l'articolo corrente ai segnalibri" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "Modifica le flag" #: src/keymap.cpp:65 #, fuzzy msgid "Go to next feed" msgstr "Vai al prossimo feed non letto" #: src/keymap.cpp:66 #, fuzzy msgid "Go to previous feed" msgstr "Vai al precedente feed non letto" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "Vai al prossimo feed non letto" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "Vai al precedente feed non letto" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "Richiama una macro" #: src/keymap.cpp:70 msgid "Delete article" msgstr "Cancella articolo" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "Pulisce gli articoli cancellati" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "Modifica gli URL sottoscritti" #: src/keymap.cpp:73 msgid "Close currently selected dialog" msgstr "Chiude la schermata selezionata correntemente" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "Mostra la lista delle schermate aperte" #: src/keymap.cpp:75 msgid "Go to next dialog" msgstr "Vai alla prossima schermata" #: src/keymap.cpp:76 msgid "Go to previous dialog" msgstr "Vai alla schermata precedente" #: src/keymap.cpp:77 msgid "Pipe article to command" msgstr "Metti in pipe l'articolo con un comando" #: src/keymap.cpp:78 msgid "Sort current list" msgstr "Ordina la lista corrente" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "Ordina la lista corrente (inverso)" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "Apri URL 10" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "Apri URL 1" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "Apri URL 2" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "Apri URL 3" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "Apri URL 4" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "Apri URL 5" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "Apri URL 6" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "Apri URL 7" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "Apri URL 8" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "Apri URL 9" #: src/keymap.cpp:92 msgid "Move to the previous entry" msgstr "Spostati alla voce precedente" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "Spostati alla voce successiva" #: src/keymap.cpp:94 msgid "Move to the previous page" msgstr "Spostati alla pagina precedente" #: src/keymap.cpp:95 msgid "Move to the next page" msgstr "Spostati alla pagina successiva" #: src/keymap.cpp:97 msgid "Move to the start of page/list" msgstr "Spostati all'inizio della pagina/lista" #: src/keymap.cpp:98 msgid "Move to the end of page/list" msgstr "Spostati alla fine della pagina/lista" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "`%s' non è un contesto valido" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "`%s' non è una tasto di comando valido" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "Sto pulendo la coda..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "uso %s [-C ] [-q ] [-h]\n" "-C legge la configurazione da \n" "-q usa come file di coda\n" "-a lancia il download all'avvio\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr " - %u download paralleli" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "Coda (%u download in corso, %u totali) - %.2f kb/s totale%s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "Errore: impossibile uscire: ci sono download in esecuzione." #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "" "Errore: il download deve finire prima che il file possa essere richiamato." #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "" "Errore: impossibile effettuare l'operazione: ci sono download in esecuzione." #: src/pb_view.cpp:276 msgid "Download" msgstr "Scarica" #: src/pb_view.cpp:278 msgid "Delete" msgstr "Elimina" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "Pulisci terminati" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "Attiva/Disattiva Download Automatico" #: src/pb_view.cpp:281 msgid "Play" msgstr "Avvia" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "`%s' non è un tipo di schermata valida" #: src/regexmanager.cpp:49 #, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "`%s' non è un'espressione regolare valida: %s" #: src/rss.cpp:466 msgid "too few arguments" msgstr "parametri insufficienti" #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "Errore: URL non supportato: %s" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "Seleziona Tag" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "Seleziona Filtro" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "attributo non trovato" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "EOF trovato durante la lettura del tag XML" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "Nessun collegamento selezionato!" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "Salva Segnalibro" #: src/urlview_formaction.cpp:146 msgid "URLs" msgstr "URL" #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "Errore: applicazione del filtro fallita: %s" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "Errore: il feed non contiene voci!" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "Aggiornamento interrogazione feed..." #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "Il nodo XML radice è NULL" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "impossibile inizializzare libcurl" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "" "Errore: provando a scaricare il feed `%s' è ritornato un codice di stato " "HTTP %ld." #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "impossibile analizzare il buffer" #: rss/parser.cpp:174 msgid "could not parse file" msgstr "impossibile analizzare il file" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "versione RSS non presente" #: rss/parser.cpp:211 msgid "invalid RSS version" msgstr "versione RSS non valida" #: rss/parser.cpp:226 rss/parser.cpp:233 msgid "invalid Atom version" msgstr "versione Atom non valida" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "versione Atom non presente" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "formato feed non supportato" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "nessun canale RSS trovato" newsbeuter-2.7/po/nb.po000066400000000000000000001136001220711462700151250ustar00rootroot00000000000000# Norwegian bokmål translation for newsbeuter. # Copyright (C) 2012 # This file is distributed under the same license as the newsbeuter package. # Daniel Aleksandersen , 2012. # msgid "" msgstr "" "Project-Id-Version: newsbeuter 2.5\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2012-08-08 20:07+0100\n" "Last-Translator: Daniel Aleksandersen \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Norwegian Bokmal\n" "X-Poedit-Country: NORWAY\n" #: src/colormanager.cpp:44 #: src/colormanager.cpp:46 #: src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 #: src/regexmanager.cpp:113 #: src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "`%s' er ikke en gyldig farge" #: src/colormanager.cpp:51 #: src/regexmanager.cpp:73 #: src/regexmanager.cpp:131 #, c-format msgid "`%s' is not a valid attribute" msgstr "`%s' er ikke en gyldig attributt" #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "`%s' er ikke et gyldig oppsettselement" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "newsbeuter: fullførte oppdateringen, %f uleste nyhetsstrømmer (totalt %n uleste artikler)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - Nyhetsstrømmene dine (%u uleste, %t totalt)%?T? - etikett `%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - Artikler i nyhetsnyhetsstrømmen '%T' (%u ulest, %t totalt) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - Søkeresultater (%u ulest, %t totalt)" #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?Åpne fil&Lagre fil? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - Hjelp" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - Velg etikett" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - Velg filter" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - Artikkel '%T'" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - URLer" #: src/configcontainer.cpp:111 msgid "%N %V - Dialogs" msgstr "%N %V - Dialoger" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "forventet en boolsk verdi, fant `%s' istedenfor" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "forventet en heltallsverdi, fant `%s' i stedet" #: src/configcontainer.cpp:159 #, c-format msgid "invalid configuration value `%s'" msgstr "ugyldig oppsettsverdi `%s'" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "Feil under behandling av kommandoen `%s' (%s linje %u): %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "ukjent kommando `%s'" #: src/controller.cpp:90 #: src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "Kraftig feil: kunne ikke finne hjemmemappen!" #: src/controller.cpp:91 #: src/pb_controller.cpp:44 #, c-format msgid "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "Vennligst sett miljøvariablen HOME eller legg til en gyldig bruker for UID %u!" #: src/controller.cpp:226 #: src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: ukjent valg - %c" #: src/controller.cpp:250 #: src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "Starter %s %s..." #: src/controller.cpp:260 #: src/controller.cpp:319 #: src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "Feil: en annen instans av %s kjører allerede (PID: %u)" #: src/controller.cpp:267 #: src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "Leser oppsett..." #: src/controller.cpp:299 #: src/controller.cpp:337 #: src/controller.cpp:364 #: src/controller.cpp:380 #: src/controller.cpp:408 #: src/controller.cpp:412 #: src/controller.cpp:444 #: src/controller.cpp:456 #: src/controller.cpp:470 #: src/controller.cpp:479 #: src/controller.cpp:518 #: src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "utført." #: src/controller.cpp:325 #: src/controller.cpp:403 msgid "Opening cache..." msgstr "Åpner mellomlager..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "Feil: åpning av mellomlagerfilen `%s' feilet: %s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "Laster inn URLer fra lokalt mellomlager..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "Laster inn URLer fra %s..." #: src/controller.cpp:388 #, c-format msgid "Error: no URLs configured. Please fill the file %s with RSS feed URLs or import an OPML file." msgstr "Feil: ingen URLer er satt opp. Vennligst fyll inn filen %s med RSS nyhetsstrømmer, eller importer fra en OPML-fil." #: src/controller.cpp:390 msgid "It looks like the OPML feed you subscribed contains no feeds. Please fill it with feeds, and try again." msgstr "Det ser ut til at OPML-strømmen du abonnerer på ikke inneholder noen nyhetsstrømmer. Vennligst sørg for at den inneholder noen nyhetsstrømmer og prøv igjen." #: src/controller.cpp:392 msgid "It looks like you haven't configured any feeds in your Google Reader account. Please do so, and try again." msgstr "Det ser ikke ut til at du har satt opp noen nyhetsstrømmer i din Google Reader-konto. Vennligst sørg for å gjøre det og prøv igjen." #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "Leser artikler fra mellomlageret..." #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "Rydder grundig opp i mellomlageret..." #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "Feil under innlesing av nyhetsstrømmer fra databasen: " #: src/controller.cpp:430 #, c-format msgid "Error while loading feed '%s': %s" msgstr "Feil under innlastning av nyhetsstrømmen '%s': %s" #: src/controller.cpp:448 msgid "Prepopulating query feeds..." msgstr "Forhåndsutfyller spørringsstrømmer..." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "Importerer liste over leste artikler..." #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "Eksporterer liste over leste artikler..." #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "Rydder opp i mellomlageret..." #: src/controller.cpp:523 msgid "failed: " msgstr "feilet: " #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "Feil: kunne ikke markere alle nyhetsstrømmene som lest: %s" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%sInnlasting%s..." #: src/controller.cpp:622 #: src/controller.cpp:624 #: src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "Feil under innhenting av %s: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "Feil: ugyldig nyhetsstrøm!" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "ugyldig strøminndeks (programfeil)" #: src/controller.cpp:803 msgid "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "newsbeuter er fri programvare lisensiert under MIT/X Consortium License." #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "Skriv `%s -vv' for mer informasjon." #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] [-h]\n" msgstr "" "%s %s\n" "bruk: %s [-i |-e] [-u ] [-c ] [-x ...] [-h]\n" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "eksporter OPML strømmer til stdout" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "oppdater nyhetsstrømmer under oppstart" #: src/controller.cpp:842 #: src/controller.cpp:853 #: src/controller.cpp:854 msgid "" msgstr "" #: src/controller.cpp:842 msgid "import OPML file" msgstr "importer OPML-fil" #: src/controller.cpp:843 msgid "" msgstr "" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "les RSS-strømmer fra " #: src/controller.cpp:844 msgid "" msgstr "" #: src/controller.cpp:844 msgid "use as cache file" msgstr "bruk som mellomlagerfil" #: src/controller.cpp:845 msgid "" msgstr "" #: src/controller.cpp:845 msgid "read configuration from " msgstr "les oppsettsfilen fra " #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "grunndig opprydding av mellomlagret" #: src/controller.cpp:847 msgid "..." msgstr "..." #: src/controller.cpp:847 msgid "execute list of commands" msgstr "utfør kommandoliste" #: src/controller.cpp:848 msgid "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "bytt til frakoblet modus (kun for Google Reader-synkroniseringsmodus)" #: src/controller.cpp:849 msgid "quiet startup" msgstr "stille oppstart" #: src/controller.cpp:850 msgid "get version information" msgstr "få versjonsinformasjon" #: src/controller.cpp:851 msgid "" msgstr "" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "skriv en logg med angitt loggskrivningsnivå mellom 1 og 6" #: src/controller.cpp:852 msgid "" msgstr "" #: src/controller.cpp:852 msgid "use as output log file" msgstr "bruk som loggfil" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "eksporterer en liste med leste artikler til " #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "importer en liste med leste artikler fra " #: src/controller.cpp:855 msgid "this help" msgstr "denne hjelpen" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "En feil oppsto under tolkningen av %s" #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "Fullførte importeringen av %s." #: src/controller.cpp:1120 msgid "bookmarking support is not configured. Please set the configuration variable `bookmark-cmd' accordingly." msgstr "bokmerkestøtte er ikke satt opp. Vennligst sett valgvariabelen `bookmark-cmd' etter ønske." #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u uleste artikler" #: src/controller.cpp:1164 #: src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "Tittel: " #: src/controller.cpp:1168 #: src/itemview_formaction.cpp:90 msgid "Author: " msgstr "Forfatter: " #: src/controller.cpp:1172 #: src/itemview_formaction.cpp:99 msgid "Date: " msgstr "Dato: " #: src/controller.cpp:1176 #: src/itemview_formaction.cpp:95 msgid "Link: " msgstr "Lenke: " #: src/controller.cpp:1388 #, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "Feil: kunne ikke åpne oppsettsfilen `%s'!" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "Lukk" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "Gå til dialogen" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "Lukk dialogen" #: src/dialogs_formaction.cpp:62 #: src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 #: src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 #: src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 #: src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 #: src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "Ingen innlegg merket!" #: src/dialogs_formaction.cpp:74 msgid "Error: you can't remove the feed list!" msgstr "Feil: du kan ikke fjerne nyhetsstrømlisten!" #: src/dialogs_formaction.cpp:99 #: src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 #: src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "ugyldig posisjon!" #: src/download.cpp:42 msgid "queued" msgstr "lagt i køen" #: src/download.cpp:44 msgid "downloading" msgstr "laster ned" #: src/download.cpp:46 msgid "cancelled" msgstr "avbrutt" #: src/download.cpp:48 msgid "deleted" msgstr "slettet" #: src/download.cpp:50 msgid "finished" msgstr "fullført" #: src/download.cpp:52 msgid "failed" msgstr "feilet" #: src/download.cpp:54 msgid "incomplete" msgstr "ufullstendig" #: src/download.cpp:56 msgid "played" msgstr "avspilt" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "ukjent (programfeil)." #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "attributten `%s' er ikke tilgjengelig." #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "det regulære uttrykket '%s' er ugyldig: %s" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "ugyldige parametere." #: src/exception.cpp:43 msgid "too few parameters." msgstr "for få parametere." #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "ukjent kommando (programfeil)." #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "filen kunne ikke åpnes." #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "ukjent feil (programfeil)." #: src/feedlist_formaction.cpp:99 #: src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "Ingen nyhetsstrømmer merket!" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "Sorter stigende etter (f)ørste etikett/(t)ittel/antall (a)artikler/antall (u)leste artikler/(i)ngen?" #: src/feedlist_formaction.cpp:120 #: src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "ftaui" #: src/feedlist_formaction.cpp:123 #: src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 #: src/itemlist_formaction.cpp:439 msgid "f" msgstr "f" #: src/feedlist_formaction.cpp:125 #: src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 #: src/itemlist_formaction.cpp:437 msgid "t" msgstr "t" #: src/feedlist_formaction.cpp:127 #: src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 #: src/itemlist_formaction.cpp:441 msgid "a" msgstr "a" #: src/feedlist_formaction.cpp:129 #: src/feedlist_formaction.cpp:146 msgid "u" msgstr "u" #: src/feedlist_formaction.cpp:131 #: src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "i" #: src/feedlist_formaction.cpp:137 msgid "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "Sorter synkende etter (f)ørste etikett/(t)ittel/antall (a)artikler/antall (u)leste artikler/(i)ngen?" #: src/feedlist_formaction.cpp:175 #: src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "Markerer nyhetsstrømmen som lest..." #: src/feedlist_formaction.cpp:184 #: src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "Feil: kunne ikke markere nyhetsstrømmen som lest: %s" #: src/feedlist_formaction.cpp:208 #: src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "Ingen nyhetsstrømmer med uleste innlegg." #: src/feedlist_formaction.cpp:224 #: src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "Allerede i den siste nyhetsstrømmen." #: src/feedlist_formaction.cpp:232 #: src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "Allerede i den første nyhetsstrømmen." #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "Markerer alle nyhetsstrømmer som lest..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "Ingen etiketter angitt." #: src/feedlist_formaction.cpp:285 #: src/itemlist_formaction.cpp:378 #, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "Feil: kunne ikke tolke filterkommandoen `%s': %s" #: src/feedlist_formaction.cpp:295 #: src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "Ingen angitte filtere." #: src/feedlist_formaction.cpp:308 #: src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 #: src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "Søk etter: " #: src/feedlist_formaction.cpp:325 #: src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "Filter: " #: src/feedlist_formaction.cpp:334 #: src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "Vil du virkelig avslutte (j:Ja n:Nei)? " #: src/feedlist_formaction.cpp:334 #: src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "jn" #: src/feedlist_formaction.cpp:334 #: src/view.cpp:184 msgid "y" msgstr "j" #: src/feedlist_formaction.cpp:416 #: src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 #: src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 #: src/pb_view.cpp:275 #: src/urlview_formaction.cpp:124 msgid "Quit" msgstr "Avslutt" #: src/feedlist_formaction.cpp:417 #: src/itemlist_formaction.cpp:837 msgid "Open" msgstr "Åpne" #: src/feedlist_formaction.cpp:418 #: src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "Neste uleste" #: src/feedlist_formaction.cpp:419 #: src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "Oppdater" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "Oppdater alle" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "Merk som lest" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "Merk alt som lest" #: src/feedlist_formaction.cpp:423 #: src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "Søk" #: src/feedlist_formaction.cpp:424 #: src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 #: src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 #: src/pb_view.cpp:282 msgid "Help" msgstr "Hjelp" #: src/feedlist_formaction.cpp:681 #: src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "Feil: kunne ikke tolke filterkommandoen!" #: src/feedlist_formaction.cpp:696 #: src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "Leter..." #: src/feedlist_formaction.cpp:703 #: src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "Feil under søket etter `%s': %s" #: src/feedlist_formaction.cpp:712 #: src/itemlist_formaction.cpp:564 msgid "No results." msgstr "Ingen resultater." #: src/feedlist_formaction.cpp:721 #: src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "Posisjonen er ikke synlig!" #: src/feedlist_formaction.cpp:774 #, c-format msgid "Feed List - %u unread, %u total" msgstr "Nyhetsstrømliste - %u uleste, %u totalt" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "Vil du virkelig overskrive `%s' (j:Ja n:Nei)? " #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "Fil: " #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - Åpne fil - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - Lagre fil - %s" #: src/filebrowser_formaction.cpp:194 #: src/pb_view.cpp:277 #: src/select_formaction.cpp:145 #: src/select_formaction.cpp:150 msgid "Cancel" msgstr "Avbryt" #: src/filebrowser_formaction.cpp:195 #: src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "Lagre" #: src/filebrowser_formaction.cpp:271 #, c-format msgid "Open File - %s" msgstr "Åpne fil - %s" #: src/filebrowser_formaction.cpp:273 #, c-format msgid "Save File - %s" msgstr "Lagre fil - %s" #: src/filtercontainer.cpp:22 #: src/regexmanager.cpp:138 #: src/rss.cpp:355 #, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "kunne ikke tolke filteruttrykket `%s': %s" #: src/formaction.cpp:186 #: src/formaction.cpp:207 msgid "usage: set [=]" msgstr "bruk: set [=]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "bruk: source [...]" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "bruk: dumpconfig " #: src/formaction.cpp:231 #, c-format msgid "Saved configuration to %s" msgstr "Lagret oppsettsfilen til %s" #: src/formaction.cpp:236 #, c-format msgid "Not a command: %s" msgstr "Ikke en kommando: %s" #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "Lagrer bokmerke..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "Lagret bokmerke." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "Feil under lagring av bokmerke: " #: src/formaction.cpp:303 msgid "URL: " msgstr "URL: " #: src/formaction.cpp:305 msgid "Description: " msgstr "Beskrivelse: " #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "Folk du følger" #: src/googlereader_urlreader.cpp:34 msgid "Starred items" msgstr "Favorittinnlegg" #: src/googlereader_urlreader.cpp:35 msgid "Shared items" msgstr "Delte innlegg" #: src/googlereader_urlreader.cpp:36 msgid "Popular items" msgstr "Populære innlegg" #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "Generelle bindinger:" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "Utilknyttede funksjoner:" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "Tøm" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "innbakt Flash-tillegg" #: src/htmlrenderer.cpp:176 #: src/htmlrenderer.cpp:595 msgid "image" msgstr "bilde" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "Lenker: " #: src/htmlrenderer.cpp:594 msgid "link" msgstr "lenke" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "innbakt Flash-tillegg" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "ukjent (programfeil)" #: src/itemlist_formaction.cpp:112 #: src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "Setter lestflagg for artikkelen..." #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "Feil under setting av lestflagg: %s" #: src/itemlist_formaction.cpp:145 #: src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "URL-listen er tom." #: src/itemlist_formaction.cpp:182 #: src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "Flagg: " #: src/itemlist_formaction.cpp:205 #: src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "Feil: ingen markerte innlegg!" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "Feil: du kan ikke oppdatere søkeresultater." #: src/itemlist_formaction.cpp:239 #: src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 #: src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 #: src/itemview_formaction.cpp:318 #: src/view.cpp:626 #: src/view.cpp:684 msgid "No unread items." msgstr "Ingen uleste innlegg." #: src/itemlist_formaction.cpp:255 #: src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "Allerede på siste innlegg." #: src/itemlist_formaction.cpp:263 #: src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "Allerede på første innlegg." #: src/itemlist_formaction.cpp:276 #: src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "Ingen uleste nyhetsstrømmer." #: src/itemlist_formaction.cpp:340 #: src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "Send artikkel til kommando: " #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "Sorter etter (d)ato)/(t)ittel/(f)lagg/f(o)rfatter/(l)enke/(g)uide?" #: src/itemlist_formaction.cpp:413 #: src/itemlist_formaction.cpp:432 msgid "dtfalg" msgstr "dtfolg" #: src/itemlist_formaction.cpp:416 #: src/itemlist_formaction.cpp:435 msgid "d" msgstr "d" #: src/itemlist_formaction.cpp:424 #: src/itemlist_formaction.cpp:443 msgid "l" msgstr "l" #: src/itemlist_formaction.cpp:426 #: src/itemlist_formaction.cpp:445 msgid "g" msgstr "g" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "Sorter synkende etter (d)ato)/(t)ittel/(f)lagg/f(o)rfatter/(l)enke/(g)uide?" #: src/itemlist_formaction.cpp:537 #: src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "Flagg oppdatert." #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "Marker alle som lest" #: src/itemlist_formaction.cpp:917 #: src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "Avbrøt lagringen." #: src/itemlist_formaction.cpp:921 #: src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "Lagret artikkelen til %s" #: src/itemlist_formaction.cpp:923 #: src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "Feil: kunne ikke lagre artikkelen til %s" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "Søkeresultater - '%s'" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "Spørringsstrøm - %s" #: src/itemlist_formaction.cpp:1004 #, c-format msgid "Article List - %s" msgstr "Artikkelliste - %s" #: src/itemview_formaction.cpp:34 #: src/itemview_formaction.cpp:575 msgid "Top" msgstr "Toppen" #: src/itemview_formaction.cpp:34 #: src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "Bunnen" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "Strøm: " #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "Podkastnedlastings-URL: " #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "slag: " #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "Feil mens artikkelen ble markert som lest: %s" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "La til %s til nedlastingskøen." #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "Ugyldig URL: '%s'" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "Lagret artikkel til %s." #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "Feil: kunne ikke skrive artikkelen til filen %s" #: src/itemview_formaction.cpp:208 #: src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 #: src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "Åpner nettleseren..." #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "Feil mens artikkelen ble markert som lest: %s" #: src/itemview_formaction.cpp:372 #: src/keymap.cpp:47 msgid "Goto URL #" msgstr "Gå til URL #" #: src/itemview_formaction.cpp:396 #: src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "Åpne i nettleseren" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "Legg til i køen" #: src/itemview_formaction.cpp:586 #, c-format msgid "Article - %s" msgstr "Artikkel - %s" #: src/itemview_formaction.cpp:624 msgid "Error: invalid regular expression!" msgstr "Feil: ugyldig regulært uttrykk!" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "Åpne nyhetsstrøm/artikkel" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "Vend tilbake til forrige dialog/avslutt" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "Avslutt programmet uten bekreftelse" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "Oppdater den markerte nyhetsstrømmen" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "Oppdater alle nyhetsstrømmer" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "Marker nyhetsstrømmen som lest" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "Marker alle nyhetsstrømmer som lest" #: src/keymap.cpp:30 msgid "Save article" msgstr "Lagre artikkel" #: src/keymap.cpp:31 msgid "Go to next article" msgstr "Gå til neste artikkel" #: src/keymap.cpp:32 msgid "Go to previous article" msgstr "Gå til forrige artikkel" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "Gå til neste uleste artikkel" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "Gå til forrige uleste artikkel" #: src/keymap.cpp:35 msgid "Go to a random unread article" msgstr "Gå til en tilfeldig ulest artikkel" #: src/keymap.cpp:36 msgid "Open article in browser and mark read" msgstr "Åpne artikkel i en nettleser og marker som lest" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "Åpne artikkel i en nettleser" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "Åpne hjelpedialog" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "Kildevisning [av/på]" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "Leststatus for artikkel [av/på]" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "Vis leste nyhetsstrømmer/artikler [av/på]" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "Vis artikkelens URLer" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "Tøm valgte etikett" #: src/keymap.cpp:44 #: src/keymap.cpp:45 msgid "Select tag" msgstr "Velg etikett" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "Åpne søkedialog" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "Legg til i nedlastingskøen" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "Oppdater listen over URLer fra oppsettet" #: src/keymap.cpp:50 msgid "Download file" msgstr "Last ned filen" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "Avbryt nedlastingen" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "Merk nedlastingen som slettet" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "Fjern ferdige og slettede nedlastinger fra køen" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "Automatisk nedlasting [av/på]" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "Start markerte nedlasting i avspilleren" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "Øk antallet samtidige nedlastinger" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "Reduser antallet samtidige nedlastinger" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "Tegn skjermen på nytt" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "Åpne kommandolinjen" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "Velg et filter" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "Velg et eksisterende filter" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "Tøm gjeldende filtrering" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "Sett bokmerke på denne lenken/artikkelen" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "Endre flagg" #: src/keymap.cpp:65 msgid "Go to next feed" msgstr "Gå til neste nyhetsstrøm" #: src/keymap.cpp:66 msgid "Go to previous feed" msgstr "Gå til forrige nyhetsstrøm" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "Gå til neste uleste nyhetsstrøm" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "Gå til forrige uleste nyhetsstrøm" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "Bruk en makro" #: src/keymap.cpp:70 msgid "Delete article" msgstr "Slett artikkel" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "Fjern slettede artikkler" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "Endre abonnements-URLene" #: src/keymap.cpp:73 msgid "Close currently selected dialog" msgstr "Lukk den markerte dialogen" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "Vis listen over åpne dialoger" #: src/keymap.cpp:75 msgid "Go to next dialog" msgstr "Gå til neste dialog" #: src/keymap.cpp:76 msgid "Go to previous dialog" msgstr "Vend tilbake til forrige dialog" #: src/keymap.cpp:77 msgid "Pipe article to command" msgstr "Send artikkel til kommando" #: src/keymap.cpp:78 msgid "Sort current list" msgstr "Sorter denne listen stigende" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "Sorter denne listen synkende" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "Åpne URL 10" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "Åpne URL 1" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "Åpne URL 2" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "Åpne URL 3" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "Åpne URL 4" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "Åpne URL 5" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "Åpne URL 6" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "Åpne URL 7" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "Åpne URL 8" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "Åpne URL 9" #: src/keymap.cpp:92 msgid "Move to the previous entry" msgstr "Gå til forrige innlegg" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "Gå til neste innlegg" #: src/keymap.cpp:94 msgid "Move to the previous page" msgstr "Gå til forrige side" #: src/keymap.cpp:95 msgid "Move to the next page" msgstr "Gå til neste side" #: src/keymap.cpp:97 msgid "Move to the start of page/list" msgstr "Gå til starten av siden/listen" #: src/keymap.cpp:98 msgid "Move to the end of page/list" msgstr "Gå til slutten av siden/listen" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "`%s' er ikke en gyldig kontekst" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "`%s' er en ugyldig nøkkelkommando" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "Rydder opp i køen..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "bruk %s [-C ] [-q ] [-h]\n" "-C les instillinger fra \n" "-q bruk som kilde for køen\n" "-a start nedlastinger under oppstart\n" "-h vis denne hjelpen\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr " - %u samtidige nedlastinger" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "Kø (%u nedlastinger pågår, %u totalt) - %.2f kb/s totalt%s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "Feil: kan ikke avslutte: nedlasting(er) pågår." #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "Feil: nedlastinger må fullføres før filen kan spilles av." #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "Feil: klarte ikke å utføre oppgaven: nedlasting(er) pågår." #: src/pb_view.cpp:276 msgid "Download" msgstr "Last ned" #: src/pb_view.cpp:278 msgid "Delete" msgstr "Slett" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "Fjern fullførte" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "Automatisk nedlasting [av/på]" #: src/pb_view.cpp:281 msgid "Play" msgstr "Spill av" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "`%s' er en ugyldig dialogtype" #: src/regexmanager.cpp:49 #, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "`%s' er ikke et gyldig regulært utrykk: %s" #: src/rss.cpp:466 msgid "too few arguments" msgstr "for få argumenter" #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "Feil: URLen støttes ikke: %s" #: src/select_formaction.cpp:146 #: src/select_formaction.cpp:166 msgid "Select Tag" msgstr "Velg etikett" #: src/select_formaction.cpp:151 #: src/select_formaction.cpp:168 msgid "Select Filter" msgstr "Velg filter" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "attributten ble ikke funnet" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "fant EOF mens XML-element ble lest inn" #: src/urlview_formaction.cpp:38 #: src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "Ingen lenke valgt!" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "Lagre bokmerke" #: src/urlview_formaction.cpp:146 msgid "URLs" msgstr "URLer" #: src/view.cpp:366 #: src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "Feil: bruk av filteret feilet: %s" #: src/view.cpp:412 #: src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "Feil: nyhetsstrømmen inneholder ingen innlegg!" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "Frisker opp spørringsstrømmen..." #: rss/atom_parser.cpp:16 #: rss/parser.cpp:250 #: rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 #: rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "XML-rotelementet er NULL" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "kunne ikke initialisere libcurl" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "Feil: forsøket på å laste ned nyhetsstrømmen `%s' ga HTTP-feilkoden %ld." #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "kunne ikke tolke bufferen" #: rss/parser.cpp:174 msgid "could not parse file" msgstr "kunne ikke tolke filen" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "ingen RSS-versjon" #: rss/parser.cpp:211 msgid "invalid RSS version" msgstr "ugyldig RSS-versjon" #: rss/parser.cpp:226 #: rss/parser.cpp:233 msgid "invalid Atom version" msgstr "ugyldig Atom-versjon" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "ingen Atom-versjon" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "strømformatet støttes ikke" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "fant ingen RSS-kanal" newsbeuter-2.7/po/newsbeuter.pot000066400000000000000000000712741220711462700171070ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, c-format msgid "`%s' is not a valid attribute" msgstr "" #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "" #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "" #: src/configcontainer.cpp:111 msgid "%N %V - Dialogs" msgstr "" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "" #: src/configcontainer.cpp:159 #, c-format msgid "invalid configuration value `%s'" msgstr "" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "" #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "" #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "" #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "" #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "" #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "" #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "" #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "" #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "" #: src/controller.cpp:392 msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "" #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "" #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "" #: src/controller.cpp:430 #, c-format msgid "Error while loading feed '%s': %s" msgstr "" #: src/controller.cpp:448 msgid "Prepopulating query feeds..." msgstr "" #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "" #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "" #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "" #: src/controller.cpp:523 msgid "failed: " msgstr "" #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "" #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "" #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "" #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 msgid "" msgstr "" #: src/controller.cpp:842 msgid "import OPML file" msgstr "" #: src/controller.cpp:843 msgid "" msgstr "" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "" #: src/controller.cpp:844 msgid "" msgstr "" #: src/controller.cpp:844 msgid "use as cache file" msgstr "" #: src/controller.cpp:845 msgid "" msgstr "" #: src/controller.cpp:845 msgid "read configuration from " msgstr "" #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "" #: src/controller.cpp:847 msgid "..." msgstr "" #: src/controller.cpp:847 msgid "execute list of commands" msgstr "" #: src/controller.cpp:848 msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "" #: src/controller.cpp:849 msgid "quiet startup" msgstr "" #: src/controller.cpp:850 msgid "get version information" msgstr "" #: src/controller.cpp:851 msgid "" msgstr "" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "" #: src/controller.cpp:852 msgid "" msgstr "" #: src/controller.cpp:852 msgid "use as output log file" msgstr "" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "" #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "" #: src/controller.cpp:855 msgid "this help" msgstr "" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "" #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "" #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "" #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "" #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "" #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "" #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "" #: src/controller.cpp:1388 #, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "" #: src/dialogs_formaction.cpp:74 msgid "Error: you can't remove the feed list!" msgstr "" #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "" #: src/download.cpp:42 msgid "queued" msgstr "" #: src/download.cpp:44 msgid "downloading" msgstr "" #: src/download.cpp:46 msgid "cancelled" msgstr "" #: src/download.cpp:48 msgid "deleted" msgstr "" #: src/download.cpp:50 msgid "finished" msgstr "" #: src/download.cpp:52 msgid "failed" msgstr "" #: src/download.cpp:54 msgid "incomplete" msgstr "" #: src/download.cpp:56 msgid "played" msgstr "" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "" #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "" #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "" #: src/exception.cpp:43 msgid "too few parameters." msgstr "" #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "" #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "" #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "" #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "" #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "" #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "" #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "" #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "" #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "" #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "" #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "" #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "" #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "" #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "" #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "" #: src/feedlist_formaction.cpp:774 #, c-format msgid "Feed List - %u unread, %u total" msgstr "" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "" #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "" #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "" #: src/filebrowser_formaction.cpp:271 #, c-format msgid "Open File - %s" msgstr "" #: src/filebrowser_formaction.cpp:273 #, c-format msgid "Save File - %s" msgstr "" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "" #: src/formaction.cpp:231 #, c-format msgid "Saved configuration to %s" msgstr "" #: src/formaction.cpp:236 #, c-format msgid "Not a command: %s" msgstr "" #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "" #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "" #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "" #: src/formaction.cpp:303 msgid "URL: " msgstr "" #: src/formaction.cpp:305 msgid "Description: " msgstr "" #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "" #: src/googlereader_urlreader.cpp:34 msgid "Starred items" msgstr "" #: src/googlereader_urlreader.cpp:35 msgid "Shared items" msgstr "" #: src/googlereader_urlreader.cpp:36 msgid "Popular items" msgstr "" #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "" #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "" #: src/htmlrenderer.cpp:594 msgid "link" msgstr "" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "" #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "" #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "" #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "" #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "" #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "" #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "" #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "" #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "" #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "" #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 msgid "dtfalg" msgstr "" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "" #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "" #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "" #: src/itemlist_formaction.cpp:1004 #, c-format msgid "Article List - %s" msgstr "" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "" #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "" #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "" #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "" #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "" #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "" #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "" #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "" #: src/itemview_formaction.cpp:586 #, c-format msgid "Article - %s" msgstr "" #: src/itemview_formaction.cpp:624 msgid "Error: invalid regular expression!" msgstr "" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "" #: src/keymap.cpp:30 msgid "Save article" msgstr "" #: src/keymap.cpp:31 msgid "Go to next article" msgstr "" #: src/keymap.cpp:32 msgid "Go to previous article" msgstr "" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "" #: src/keymap.cpp:35 msgid "Go to a random unread article" msgstr "" #: src/keymap.cpp:36 msgid "Open article in browser and mark read" msgstr "" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "" #: src/keymap.cpp:50 msgid "Download file" msgstr "" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "" #: src/keymap.cpp:65 msgid "Go to next feed" msgstr "" #: src/keymap.cpp:66 msgid "Go to previous feed" msgstr "" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "" #: src/keymap.cpp:70 msgid "Delete article" msgstr "" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "" #: src/keymap.cpp:73 msgid "Close currently selected dialog" msgstr "" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "" #: src/keymap.cpp:75 msgid "Go to next dialog" msgstr "" #: src/keymap.cpp:76 msgid "Go to previous dialog" msgstr "" #: src/keymap.cpp:77 msgid "Pipe article to command" msgstr "" #: src/keymap.cpp:78 msgid "Sort current list" msgstr "" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "" #: src/keymap.cpp:92 msgid "Move to the previous entry" msgstr "" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "" #: src/keymap.cpp:94 msgid "Move to the previous page" msgstr "" #: src/keymap.cpp:95 msgid "Move to the next page" msgstr "" #: src/keymap.cpp:97 msgid "Move to the start of page/list" msgstr "" #: src/keymap.cpp:98 msgid "Move to the end of page/list" msgstr "" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "" #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr "" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "" #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "" #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "" #: src/pb_view.cpp:276 msgid "Download" msgstr "" #: src/pb_view.cpp:278 msgid "Delete" msgstr "" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "" #: src/pb_view.cpp:281 msgid "Play" msgstr "" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "" #: src/regexmanager.cpp:49 #, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "" #: src/rss.cpp:466 msgid "too few arguments" msgstr "" #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "" #: src/urlview_formaction.cpp:146 msgid "URLs" msgstr "" #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "" #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "" #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "" #: rss/parser.cpp:174 msgid "could not parse file" msgstr "" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "" #: rss/parser.cpp:211 msgid "invalid RSS version" msgstr "" #: rss/parser.cpp:226 rss/parser.cpp:233 msgid "invalid Atom version" msgstr "" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "" newsbeuter-2.7/po/nl.po000066400000000000000000001202011220711462700151320ustar00rootroot00000000000000# Dutch translation for newsbeuter # Copyright (C) 2009 # This file is distributed under the same license as the newsbeuter package # Bart Van Loon , 2009 # msgid "" msgstr "" "Project-Id-Version: newsbeuter 0.6\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2009-04-08 12:45+0200\n" "Last-Translator: Bart Van Loon \n" "Language-Team: Dutch \n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "`%s' is geen geldige kleur" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, c-format msgid "`%s' is not a valid attribute" msgstr "`%s' is een ongeldige attribuutindex" #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "`%s' is geen geldig configuratie-element" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "" "newsbeuter: klaar met herladen, %f ongelezen feeds (%n ongelezen artikels in " "totaal)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - Uw feeds (%u ongelezen, %t totaal)%?T? - tag `%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - Artikels in feed '%T' (%u ongelezen, %t totaal) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - Zoekresultaten (%u ongelezen, %t totaal)" #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?Open Bestand&Bestand Opslagen? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - Hulp" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - Tag Selecteren" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - Filter Selecteren" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - Artikel '%T'" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - URLs" #: src/configcontainer.cpp:111 msgid "%N %V - Dialogs" msgstr "%N %V - Dialogen" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "verwachtte booelaanse waarden, vond `%s' in de plaats" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "verwachtte geheel getal, vond `%s' in de plaats" #: src/configcontainer.cpp:159 #, fuzzy, c-format msgid "invalid configuration value `%s'" msgstr "Configuratie opgeslagen naar %s" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "Fout bij het behadelen van opdrachtregel `%s' (%s regel %u): %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "onbekende opdrachtregel `%s'" #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "Fatale fout: can de home directory niet bepalen!" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "" "Zet de HOME omgevingsvariabele of voeg een geldige gebruiker toe voor UID %u!" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: onbekende optie - %c" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "Bezig met starten van %s %s..." #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "Fout: er draait al een instantie van %s (PID: %u)" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "Bezig met laden van de configuratie..." #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "klaar." #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "Bezig met openen van de cache..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "Fout: openen van het cachebestand `%s' is mislukt: %s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "Bezig met laden van artikels uit de lokale cache..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "Bezig met URLs te laden laden van %s..." #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "" "Fout: geen URLs geconfigureerd. Plaats RSS feed URLs in het bestand %s of " "importeer een OPML bestand." #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "" "Blijkbaar bevat de OPML feed waar uw zich op ingeschreven heeft geen feeds. " "Vul hemmet feeds aub, en probeer dan opnieuw." #: src/controller.cpp:392 #, fuzzy msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" "Blijkbaar hebt u nog geen feeds geconfigureerd in uw bloglines accountDoe " "dit even aub, en probeer dan opnieuw." #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "Bezig met laden van artikels uit de cache..." #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "Bezig met grondig kuisen van de cache..." #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "Fout bij het laden van de feeds van de database: " #: src/controller.cpp:430 #, fuzzy, c-format msgid "Error while loading feed '%s': %s" msgstr "Fout tijdens het oproepen van `%s': %s" #: src/controller.cpp:448 msgid "Prepopulating query feeds..." msgstr "Bezig met feedvraag te pre-vullen..." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "Bezig met importeren van lijst van gelezen artikels..." #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "Bezig met exporteren van lijst van gelezen artikels..." #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "Bezig met kuisen van de cache..." #: src/controller.cpp:523 msgid "failed: " msgstr "mislukt: " #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "Fout: kon niet alle feeds als gelezen markeren: %s" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%sBezig met laden van %s..." #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "Fout bij het ophalen van %s: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "Fout: ongeldige feed!" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "ongeldige feed index (bug)" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "" "newsbeuter is vrije software en gelicencieerd onder de MIT/X Consortium " "License." #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "Geef `%s -vv' in voor meer informatie" #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" "%s %s\n" "gebruik: %s [-i |-e] [-u ] [-c ] [-x " " ...] [-h]\n" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "exporteer OPML feed naar stdout" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "ververs feeds bij opstarten" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 msgid "" msgstr "" #: src/controller.cpp:842 msgid "import OPML file" msgstr "importeer OPML bestand" #: src/controller.cpp:843 msgid "" msgstr "" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "lees RSS feed URLs van " #: src/controller.cpp:844 msgid "" msgstr "" #: src/controller.cpp:844 msgid "use as cache file" msgstr "gebruik als cachebestand" #: src/controller.cpp:845 msgid "" msgstr "" #: src/controller.cpp:845 msgid "read configuration from " msgstr "gebruik de configuration van " #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "Bezig met grondig kuisen van de cache" #: src/controller.cpp:847 msgid "..." msgstr "..." #: src/controller.cpp:847 msgid "execute list of commands" msgstr "voer lijst van opdrachten uit" #: src/controller.cpp:848 #, fuzzy msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "activeer offline mode (enkel geldig voor bloglines synchronizationmde)" #: src/controller.cpp:849 msgid "quiet startup" msgstr "" #: src/controller.cpp:850 msgid "get version information" msgstr "haal versieïnformatie op" #: src/controller.cpp:851 msgid "" msgstr "" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "hou een log bij met een zeker logniveau (geldige waarden: 1 tot 6)" #: src/controller.cpp:852 msgid "" msgstr "" #: src/controller.cpp:852 msgid "use as output log file" msgstr "gebruikt als output logbestand" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "Bezig met exporteren van lijst van gelezen artikels naar " #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "Bezig met importeren van lijst van gelezen artikels naar " #: src/controller.cpp:855 msgid "this help" msgstr "deze hulp" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "Een fout trad op bij het ontleden van %s." #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "Klaar met importeren van %s" #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "" "bladwijzerondersteuning is niet geconfigureerd. Corrigeer de waarde van de " "configuratievariabele`bookmark-cmd' aub." #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u ongelezen artikels" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "Titel: " #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "Auteur: " #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "Datum: " #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "Koppeling: " #: src/controller.cpp:1388 #, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "Fout: kon configuratiebestand `%s' niet openen!" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "Sluit" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "Ga Naar Dialoogvenster" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "Sluit Dialoogvenster" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "Geen item geselecteerd!" #: src/dialogs_formaction.cpp:74 msgid "Error: you can't remove the feed list!" msgstr "Fout: u can de feedlijst niet verwijderen!" #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "Ongeldige positie!" #: src/download.cpp:42 msgid "queued" msgstr "in de wachtrij geplaatst" #: src/download.cpp:44 msgid "downloading" msgstr "bezig met downloaden" #: src/download.cpp:46 msgid "cancelled" msgstr "geannuleerd" #: src/download.cpp:48 msgid "deleted" msgstr "verwijderd" #: src/download.cpp:50 msgid "finished" msgstr "klaar" #: src/download.cpp:52 msgid "failed" msgstr "mislukt" #: src/download.cpp:54 msgid "incomplete" msgstr "onvolledig" #: src/download.cpp:56 msgid "played" msgstr "Afgespeeld" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "onbekend (bug)" #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "attribuut `%s' is niet beschikbaar." #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "reguliere expressie '%s' is ongeldig: %s" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "ongeldige parameters" #: src/exception.cpp:43 msgid "too few parameters." msgstr "onvoldoende aantal parameters" #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "onbekende opdrachtregel (bug)" #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "bestand kon niet geopend worden" #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "onbekende fout (bug)" #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "Geen feeds geselecteerd!" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "" "Sorteren op (e)erste tag/(t)itel/(a)antal artikels/aantal (o)ngelezen " "artikels/(n)iets?" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "etaon" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "e" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "t" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "a" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "o" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "n" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "" "Sorteren op (e)erste tag/(t)itel/(a)antal artikels/aantal (o)ngelezen " "artikels/(n)iets?" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "Bezig met feed als gelezen aan te duiden..." #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "Fout: kon feed niet als gelezen aanduiden: %s" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "Geen feeds met ongelezen items" #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "" #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "" #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "Beizg met alle feeds als gelezen aan te duiden..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "Geen tags gedefinieerd" #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "Fout: kon filteropdracht `%s' niet begrijpen: %s" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "Geen filters gedefinieerd" #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "Zoeken naar: " #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "Filter:" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "Zeker dat u wilt afsluiten (j:Ja n:No)? " #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "jn" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "j" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "Afsluiten" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "Openen" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "Volgende Ongelezen" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "Herladen" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "Alles Herladen" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "Aanduiden als gelezen" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "Alles Bijhalen" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "Zoeken" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "Hulp" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "Fout: kon filteropdracht niet begrijpen" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "Bezig met zoeken..." #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "Fout tijdens het zoeken naar `%s': %s" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "Geen resultaten." #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "Positie niet zichtbaar!" #: src/feedlist_formaction.cpp:774 #, c-format msgid "Feed List - %u unread, %u total" msgstr "Feedlijst - %u ongelezen, %u totaal" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "Bent u zeker dat u `%s' wilt overschrijven (j:Ja n:Nee)? " #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "Bestand: " #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - Open Bestand - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - Bestand Opslagen - %s" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "Annuleren" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "Opslagen" #: src/filebrowser_formaction.cpp:271 #, c-format msgid "Open File - %s" msgstr "Open Bestand - %s" #: src/filebrowser_formaction.cpp:273 #, c-format msgid "Save File - %s" msgstr "Bestand Opslaan - %s" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "Fout: kon filterexpressie `%s' niet ontleden: %s" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "gebruik: set [=]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "gebruiksaanwijzing: bron [...]" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "gebruiksaanwijzing: dumpconfig " #: src/formaction.cpp:231 #, c-format msgid "Saved configuration to %s" msgstr "Configuratie opgeslagen naar %s" #: src/formaction.cpp:236 #, c-format msgid "Not a command: %s" msgstr "Geen opdracht: %s" #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "Bezig met opslaan van bladwijzer..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "Opgeslagen bladwijzer." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "Fout tijdens het opslaan van bladwijzer: " #: src/formaction.cpp:303 msgid "URL: " msgstr "URL:" #: src/formaction.cpp:305 msgid "Description: " msgstr "Omschrijving: " #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "" #: src/googlereader_urlreader.cpp:34 #, fuzzy msgid "Starred items" msgstr "Geen ongelezen items" #: src/googlereader_urlreader.cpp:35 #, fuzzy msgid "Shared items" msgstr "Geen ongelezen items" #: src/googlereader_urlreader.cpp:36 #, fuzzy msgid "Popular items" msgstr "Geen ongelezen items" #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "Generische koppelingen:" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "Ongekoppelde functies" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "Schoon Op" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "ingebedde flash" #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "prent" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "Koppelingen: " #: src/htmlrenderer.cpp:594 msgid "link" msgstr "koppeling" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "ingebedde flash" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "onbekend (bug)" #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "Bezig met schakelen van gelezen vlag van artikel..." #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "Fout bij het schakelen van de gelezen vlag: %s" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "URL lijst leeg." #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "Vlaggen: " #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "Fout: geen item geselecteerd!" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "Fout: u kan zoekresultaten niet herladen." #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "Geen ongelezen items" #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "" #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "" #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "Geen ongelezen feeds" #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "Pipe artikel naar opdacht: " #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "Sorteren op (d)datum/(t)itel/(a)uteur/(l)ink/(g)uid" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 msgid "dtfalg" msgstr "dtfalg" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "d" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "l" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "g" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "Omgekeer Sorteren op (d)datum/(t)itel/(a)uteur/(l)ink/(g)uid" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "Vlaggen zijn geupdate." #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "Markeer Alles als Gelezen" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "Opslagen afgebroken" #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "Artikel opgeslagen naar %s" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "Fout: kon artikel niet opslagen naar %s" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "Zoekresultaat - '%s'" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "Bevraag Feed - %s" #: src/itemlist_formaction.cpp:1004 #, c-format msgid "Article List - %s" msgstr "Artikellijst - %s" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "Boven" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "Onder" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "Feed: " #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "Podcast Download URL" #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "type: " #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "Fout bij het als gelezen markeren van de artikels: %s" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "%s toegevoegd aan de downloadwachtrij" #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "Artikel opgeslagen naar %s." #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "Fout: kon artikel niet opslagen naar bestand %s" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "Bezig met starten van bladerprogramma..." #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "Fout bij het als gelezen markeren van het artikel: %s" #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "Openen in Bladerprogramma" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "Toevoegen aan wachtrij" #: src/itemview_formaction.cpp:586 #, c-format msgid "Article - %s" msgstr "Artikel - %s" #: src/itemview_formaction.cpp:624 msgid "Error: invalid regular expression!" msgstr "Fout: ongeldige reguliere expressie!" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "Feed/artikel openen" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "Terugkeren naar vorige dialoogvenster/Afsluiten" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "Huidig geselecteerde feed herladen" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "Alles feeds herladen" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "Feeds als gelezen markeren" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "Alle feeds als gelezen markeren" #: src/keymap.cpp:30 msgid "Save article" msgstr "Artikel opslagen" #: src/keymap.cpp:31 #, fuzzy msgid "Go to next article" msgstr "Naar volgend ongelezen artikel gaan" #: src/keymap.cpp:32 #, fuzzy msgid "Go to previous article" msgstr "Naar vorig ongelezen artikel gaan" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "Naar volgend ongelezen artikel gaan" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "Naar vorig ongelezen artikel gaan" #: src/keymap.cpp:35 msgid "Go to a random unread article" msgstr "Naar volgend ongelezen artikel gaan" #: src/keymap.cpp:36 #, fuzzy msgid "Open article in browser and mark read" msgstr "Artikel openen in bladerprogramma" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "Artikel openen in bladerprogramma" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "Hulp dialoogvenster openen" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "Broncodezicht shakelen" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "Gelezen status schakelen voor artikel" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "Gelezen feeds/artikels tonen schakelen" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "URLs in huidige artikels tonen" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "Huidige tag leegmaken" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "Tag selecteren" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "Zoek dialoogvenster openen" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "Download toevoegen aan wachtrij" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "Lijst van URLs terug ophalen uit de configuratie" #: src/keymap.cpp:50 msgid "Download file" msgstr "Bestand downloaden" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "Download annuleren" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "Download als verwijderd aanduiden" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "Afgelopen en verwijderde downloads uit de lijst verwijderen" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "Automatisch downloaden schakelen" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "Speler starten met huidig geselecteerde download" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "Aantal gelijktijdige downloads verhogen" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "Aantal gelijktijdige downloads verminderen" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "Scherm hertekenen" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "De opdrachtregel openen" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "Een filter plaatsen" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "Selecteed een voorgedefinieerde filter" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "Huidige geselecteerde filter leegmaken" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "Zet een bladwijzer op huidig(e) link/artikel" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "Wijzig vlaggen" #: src/keymap.cpp:65 #, fuzzy msgid "Go to next feed" msgstr "Ga naar volgend ongelezen artikel" #: src/keymap.cpp:66 #, fuzzy msgid "Go to previous feed" msgstr "Ga naar vorig ongelezen artikel" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "Ga naar volgend ongelezen artikel" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "Ga naar vorig ongelezen artikel" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "Roep een macro op" #: src/keymap.cpp:70 msgid "Delete article" msgstr "Verwijder artikel" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "Verwijder verwijderde artikelen definitief" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "Wijzig geabonneerde URLs" #: src/keymap.cpp:73 msgid "Close currently selected dialog" msgstr "Huidig geselecteerd dialoogvenster sluiten" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "Bekijk lijst van open dialoogvensters" #: src/keymap.cpp:75 msgid "Go to next dialog" msgstr "Naar volgend dialoogvenster gaan" #: src/keymap.cpp:76 msgid "Go to previous dialog" msgstr "Terugkeren naar vorig dialoogvenster" #: src/keymap.cpp:77 msgid "Pipe article to command" msgstr "Pipe artikel naar opdracht" #: src/keymap.cpp:78 msgid "Sort current list" msgstr "Huidige lijst sorteren" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "Sorteer huidige lijst (omgekeerd)" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "Open URL 10" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "Open URL 1" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "Open URL 2" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "Open URL 3" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "Open URL 4" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "Open URL 5" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "Open URL 6" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "Open URL 7" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "Open URL 8" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "Open URL 9" #: src/keymap.cpp:92 msgid "Move to the previous entry" msgstr "Ga naar vorig ongelezen element" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "Ga naar volgend ongelezen element" #: src/keymap.cpp:94 msgid "Move to the previous page" msgstr "Terugkeren naar vorige pagina" #: src/keymap.cpp:95 msgid "Move to the next page" msgstr "Naar volgende pagina gaan" #: src/keymap.cpp:97 #, fuzzy msgid "Move to the start of page/list" msgstr "Naar volgende pagina gaan" #: src/keymap.cpp:98 #, fuzzy msgid "Move to the end of page/list" msgstr "Naar volgende pagina gaan" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "`%s' is geen geldige context" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "`%s' is geen geldig toetsenopdracht" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "Bezig met wachtrij op te kuisen..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "gebruik %s [-C ] [-q ] [-h]\n" "-C haal configuratie ui >configuratiebestand>\n" "-q gebruik als wachtrijbestand\n" "-a start download bij opstarten\n" "-h deze hulptekst\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr " - %u gelijktijdige downloads" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "Wachtrij (%u download bezig, %u totaal) - %.2f kb/s totaal%s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "Fout: kan niet afsluiten: download(s) bezig." #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "fout: download moet klaar zijn voor het bestand gespeeld kan worden." #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "Fout: kan deze opdracht niet uitvoeren: download(s) bezig." #: src/pb_view.cpp:276 msgid "Download" msgstr "Download" #: src/pb_view.cpp:278 msgid "Delete" msgstr "Verwijderen" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "Afgelopen weghalen" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "Automatisch Downloaden Schakelen" #: src/pb_view.cpp:281 msgid "Play" msgstr "Afspelen" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "`%s' is een ongelidg dialoogvenstertype" #: src/regexmanager.cpp:49 #, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "`%s' is geen geldige reguliere expressie: %s" #: src/rss.cpp:466 #, fuzzy msgid "too few arguments" msgstr "onvoldoende aantal parameters" #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "Fout: niet ondersteunde URL: %s" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "Tag Selecteren" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "Een filter selecteren" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "attribuut niet gevonden" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "EOF gevonden tijdens het lezen van XML tag" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "Geen link geselecteerd!" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "Sla Bladwijzer Op" #: src/urlview_formaction.cpp:146 msgid "URLs" msgstr "URLs" #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "Fout: toepassen van filter mislukt: %s" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "Fout: feed bevat geen items!" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "Bezig met feedvraag te updaten..." #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "XML root node is NULL" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "not libcurl niet initializeren" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "" "Fout: het proberen downloaden van feed `%s' resulteerde in HTTP status code " "%ld." #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "kon buffer niet ontleden" #: rss/parser.cpp:174 msgid "could not parse file" msgstr "kon bestand niet ontleden" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "geen RSS versie" #: rss/parser.cpp:211 msgid "invalid RSS version" msgstr "ongeldige RSS versie" #: rss/parser.cpp:226 rss/parser.cpp:233 msgid "invalid Atom version" msgstr "ongeldige Atom versie" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "geen Atim versie" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "niet ondersteund feedformaat" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "geen RSS kanaal gevonden" #~ msgid "" #~ "%s %s\n" #~ "usage: %s [-i |-e] [-u ] [-c ] [-x " #~ " ...] [-h]\n" #~ "-e export OPML feed to stdout\n" #~ "-r refresh feeds on start\n" #~ "-i import OPML file\n" #~ "-u read RSS feed URLs from \n" #~ "-c use as cache file\n" #~ "-C read configuration from \n" #~ "-v clean up cache thoroughly\n" #~ "-x ... execute list of commands\n" #~ "-o activate offline mode (only applies to bloglines " #~ "synchronization mode)\n" #~ "-V get version information\n" #~ "-l write a log with a certain loglevel (valid values: 1 to " #~ "6)\n" #~ "-d use as output log file\n" #~ "-E export list of read articles to \n" #~ "-I import list of read articles from \n" #~ "-h this help\n" #~ msgstr "" #~ "%s %s\n" #~ "gebruik: %s [-i |-e] [-u ] [-c ] [-h]\n" #~ "-e exporteer OPML feed naar stdout\n" #~ "-r ververs feeds bij het opstarten\n" #~ "-i importeer OPMLbestand\n" #~ "-u lees RSS feed URLs van \n" #~ "-c gebruik as cachebestand\n" #~ "-C lees configuratie in \n" #~ "-v maak cache grondig schoon\n" #~ "-x ... voer een lijst van opdrachten uit\n" #~ "-o activeer offline mode (geldt alleen voor bloglines " #~ "synchronisatiemode)\n" #~ "-V versie-informatie\n" #~ "-l schrijf een log met een zeker logniveau (geldige " #~ "waarden: 1 tot 6)\n" #~ "-d gebruik als output logbestand\n" #~ "-E exporteer lijst van gelezen artikels naar \n" #~ "-I importeer lijst van gelezen artikels van \n" #~ "-h deze hulptekst\n" newsbeuter-2.7/po/pl.po000066400000000000000000001210011220711462700151330ustar00rootroot00000000000000# Polish translation of newsbeuter. # Copyright (C) 2008 Maciej Delmanowski # This file is distributed under the same license as the newsbeuter package. # Maciej Delmanowski , 2008. # Michal Siemek , 2012. # msgid "" msgstr "" "Project-Id-Version: newsbeuter 2.5\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2008-04-18 20:10+0100\n" "Last-Translator: Maciej Delmanowski \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "`%s' nie jest poprawnym kolorem" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, c-format msgid "`%s' is not a valid attribute" msgstr "`%s' nie jest poprawnym atrybutem" #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "`%s' nie jest poprawnym elementem konfiguracji" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "" "newsbeuter: odświeżanie zakończone, %f nieprzeczytanych kanałów" "(%n nieprzeczytanych artykułów)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - Twoje kanały (%u nieprzeczytane, %t wszystkie)%?T? - tag '%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - Artykuły w kanale '%T' (%u nieprzeczytane, %t wszystkie) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - Wynik wyszukiwania (%u nieprzeczytane, %t wszystkie)" #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?Otwórz plik&Zapisz plik? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - Pomoc" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - Wybierz tag" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - Wybierz filtr" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - Artykuł '%T'" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - Odnośniki" #: src/configcontainer.cpp:111 msgid "%N %V - Dialogs" msgstr "%N %V - Okna dialogowe" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "oczekiwano wartości boolean, znaleziono `%s'" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "oczekiwano wartości integer, znaleziono `%s'" #: src/configcontainer.cpp:159 #, c-format msgid "invalid configuration value `%s'" msgstr "nieprawidłowa wartość konfiguracyjna `%s'" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "Błąd podczas przetwarzania komendy '%s' (%s linia %u): %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "nieznana komenda '%s'" #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "Błąd krytyczny: nie mogę znaleźć katalogu domowego!" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "" "Proszę ustawić zmienną środowiskową HOME lub dodać prawidłowego użytkownika " "o UID %u!" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: nieznana opcja - %c" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "Uruchamianie %s %s..." #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "Błąd: inny proces %s jest już uruchomiony (PID: %u)" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "Czytanie konfiguracji..." #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "gotowe." #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "Otwieram pamięć podręczną..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "Błąd: otwarcie pliku pamięci podręcznej '%s' nieudane: %s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "Czytanie odnośników z lokalnej pamięci podręcznej..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "Czytanie odnośników z %s..." #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "" "Błąd: brak skonfigurowanych odnośników. Dodaj do pliku %s kilka odnośników " "do kanałów RSS lub zaimportuj plik OPML." #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "" "Wygląda na to, że kanał OPML który subskrybujesz nie posiada żadnych kanałów." "Wypełnij go źródłami RSS i spróbuj ponownie." #: src/controller.cpp:392 msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" "Wygląda na to, że nie skonfigurowałeś żadnych kanałów na swoim koncie " "Google Reader. Wykonaj to proszę i spróbuj ponownie." #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "Wczytuję artykuły z pamięci podręcznej..." #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "Dokładne czyszczenie pamięci podręcznej..." #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "Błąd podczas wczytywania kanałów z bazy danych: " #: src/controller.cpp:430 #, c-format msgid "Error while loading feed '%s': %s" msgstr "Błąd podczas ładowania kanału: '%s': %s" #: src/controller.cpp:448 msgid "Prepopulating query feeds..." msgstr "Wstępne wypełnianie kanałów zapytań..." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "Importowanie listy przeczytanych artykułów..." #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "Eksportowanie listy przeczytanych artykułów..." #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "Czyszczenie pamięci podręcznej..." #: src/controller.cpp:523 msgid "failed: " msgstr "nieudane: " #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "Błąd: nie można zaznaczyć wszystkich kanałów jako przeczytanych: %s" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%sWczytywanie %s..." #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "Błąd podczas pobierania %s: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "Błąd: nieprawidłowy kanał!" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "nieprawidłowy indeks kanału (bug)" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "" "newsbeuter jest wolnym oprogramowaniem na licencji MIT/X Consortium License." #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "Wpisz `%s -vv' aby uzyskać więcej informacji" #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" "%s %s\n" "Składnia: %s [-i |-e] [-u ] [-c ] " "[-x ...]" "[-h]\n" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "wyeksportuj kanał OPML na standardowe wyjście" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "odśwież kanały przy starcie" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 msgid "" msgstr "" #: src/controller.cpp:842 msgid "import OPML file" msgstr "zaimportuj plik OPML" #: src/controller.cpp:843 msgid "" msgstr "" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "wczytaj adresy URL kanałów z " #: src/controller.cpp:844 msgid "" msgstr "" #: src/controller.cpp:844 msgid "use as cache file" msgstr "użyj jako pliku pamięci podręcznej" #: src/controller.cpp:845 msgid "" msgstr "" #: src/controller.cpp:845 msgid "read configuration from " msgstr "wczytaj konfiguracje z " #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "Dokładne czyszczenie pamięci podręcznej..." #: src/controller.cpp:847 msgid "..." msgstr "..." #: src/controller.cpp:847 msgid "execute list of commands" msgstr "wykonaj listę poleceń" #: src/controller.cpp:848 msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "" "aktywuj tryb offline (dotyczy trybu synchronizacji z Google Reader)" #: src/controller.cpp:849 msgid "quiet startup" msgstr "cichy start" #: src/controller.cpp:850 msgid "get version information" msgstr "pobierz informacje o wersji" #: src/controller.cpp:851 msgid "" msgstr "" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "utwórz log używając wybranego poziomu logowania" "(poprawne wartości: 1 do 6)" #: src/controller.cpp:852 msgid "" msgstr "" #: src/controller.cpp:852 msgid "use as output log file" msgstr "użyj jako wyjściowy plik z logami" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "eksport listy przeczytanych artykułów do " #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "import listy przeczytanych artykułów z " #: src/controller.cpp:855 msgid "this help" msgstr "ta strona pomocy" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "Wystąpił błąd podczas przetwarzania %s." #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "Import z %s zakończony." #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "" "obsługa zakładek nie jest skonfigurowana. Proszę odpowiednio ustawić zmienną " "'bookmark-cmd' w pliku konfiguracyjnym." #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u nieprzeczytanych artykułów" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "Tytuł: " #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "Autor: " #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "Data: " #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "Odsyłacz: " #: src/controller.cpp:1388 #, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "Błąd: nie można otworzyć pliku konfiguracyjnego `%s'!" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "Zamknij" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "Idź do" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "Zamknij okno" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "Nie wybrano żadnej pozycji!" #: src/dialogs_formaction.cpp:74 msgid "Error: you can't remove the feed list!" msgstr "Błąd: nie możesz usunąć listy kanałów" #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "Błędna pozycja!" #: src/download.cpp:42 msgid "queued" msgstr "zakolejkowany" #: src/download.cpp:44 msgid "downloading" msgstr "pobieranie" #: src/download.cpp:46 msgid "cancelled" msgstr "anulowany" #: src/download.cpp:48 msgid "deleted" msgstr "usunięty" #: src/download.cpp:50 msgid "finished" msgstr "zakończony" #: src/download.cpp:52 msgid "failed" msgstr "nieudany" #: src/download.cpp:54 msgid "incomplete" msgstr "niepełny" #: src/download.cpp:56 msgid "played" msgstr "odtworzony" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "nieznany (bug)." #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "atrybut '%s' nie jest dostępny." #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "wyrażenie regularne: '%s' jest nieprawidłowe: %s" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "nieprawidłowe parametry." #: src/exception.cpp:43 msgid "too few parameters." msgstr "zbyt mało parametrów." #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "nieznana komenda (bug)." #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "nie udało się otworzyć pliku" #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "nieznany błąd (bug)." #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "Nie wybrano żadnego kanału!" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "Sortuj wg (p)ierwszego taga/(t)ytułu/(l)iczby artykułów/liczby" "(n)ieprzeczytanych artykułów/(b)rak" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "ptlnb" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "p" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "t" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "l" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "n" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "b" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "Sortuj odwrotnie wg (p)ierwszego taga/(t)ytułu/(l)iczby artykułów/" "liczby (n)ieprzeczytanych artykułów/(b)rak" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "Oznaczam kanał jako przeczytany..." #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "Błąd: nie udało się oznaczyć kanału jako przeczytanego: %s" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "Brak kanałów z nieprzeczytanymi artykułami." #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 #, fuzzy msgid "Already on last feed." msgstr "To już ostatni kanał" #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 #, fuzzy msgid "Already on first feed." msgstr "To już pierwszy kanał" #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "Oznaczam wszystkie kanały jako przeczytane..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "Brak zdefiniowanych tagów" #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "Błąd składniowy komendy filtra `%s': %s" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "Brak zdefiniowanych filtrów." #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "Wyszukiwanie: " #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "Filtr: " #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "Czy na pewno chcesz wyjść (t:Tak n:Nie)? " #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "tn" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "t" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "Wyjście" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "Otwórz" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "Następny nieprzeczytany" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "Odśwież" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "Odśwież wszystkie" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "Oznacz jako przeczytane" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "Wyzeruj wszystkie" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "Szukaj" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "Pomoc" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "Błąd składniowy komendy filtra!" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "Wyszukiwanie..." #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "Błąd podczas wyszukiwania `%s': %s" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "Brak wyników." #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "Pozycja niewidoczna!" #: src/feedlist_formaction.cpp:774 #, c-format msgid "Feed List - %u unread, %u total" msgstr "Lista kanałów - %u nieprzeczytane, %u wszystkie" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "Czy na pewno chcesz nadpisać `%s' (t:Tak n:Nie)? " #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "Plik: " #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - Otwórz plik - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - Zapisz plik - %s" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "Anuluj" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "Zapisz" #: src/filebrowser_formaction.cpp:271 #, c-format msgid "Open File - %s" msgstr "Otwórz plik - %s" #: src/filebrowser_formaction.cpp:273 #, c-format msgid "Save File - %s" msgstr "Zapisz plik - %s" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "błąd składniowy komendy filtra `%s': %s" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "użycie: set [=]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "użycie: source [...]" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "użycie dumpconfig " #: src/formaction.cpp:231 #, c-format msgid "Saved configuration to %s" msgstr "Zapisano konfiguracje do %s" #: src/formaction.cpp:236 #, c-format msgid "Not a command: %s" msgstr "Nieznana komenda '%s'" #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "Zapisywanie zakładki..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "Zakładka zapisana." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "Błąd podczas zapisywania zakładki: " #: src/formaction.cpp:303 msgid "URL: " msgstr "Adres: " #: src/formaction.cpp:305 msgid "Description: " msgstr "Opis: " #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "Obserwowane osoby" #: src/googlereader_urlreader.cpp:34 msgid "Starred items" msgstr "Pozycje oznaczone gwiazdką" #: src/googlereader_urlreader.cpp:35 msgid "Shared items" msgstr "Pozycje współdzielone" #: src/googlereader_urlreader.cpp:36 msgid "Popular items" msgstr "Popularne pozycje" #: src/help_formaction.cpp:127 #, fuzzy msgid "Generic bindings:" msgstr "Ogólne dowiązania:" #: src/help_formaction.cpp:134 #, fuzzy msgid "Unbound functions:" msgstr "Niezwiązane funkcje:" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "Wyczyść" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "osadzony flash:" #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "obraz" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "Odsyłacze: " #: src/htmlrenderer.cpp:594 msgid "link" msgstr "odsyłacz" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "osadzony flash" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "nieznany (bug)" #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "Przełączam znacznik przeczytania dla artykułu..." #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "Błąd podczas przełączania znacznika przeczytania: %s" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "Lista adresów jest pusta." #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "Flagi: " #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "Błąd: nie wybrano żadnej pozycji!" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "Błąd: nie możesz odświeżyć wyników wyszukiwania." #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "Brak nieprzeczytanych pozycji." #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "To już ostatnia pozycja" #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "To już pierwsza pozycja" #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "Brak nieprzeczytanych kanałów." #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "Prześlij artykuł do polecenia: " #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "Sortuj wg (d)aty/(t)ytułu/(f)lag/(a)utora/(o)dnośnika/(g)uid" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 msgid "dtfalg" msgstr "dtfaog" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "d" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "o" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "g" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "Sortuj odwrotnie wg (d)aty/(t)ytułu/(f)lag/(a)utora/(o)dnośnika/(g)uid" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "Znaczniki uaktualnione." #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "Oznacz wszystkie jako przeczytane" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "Zapisywanie przerwane." #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "Zapisano artykuł do %s" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "Błąd: nie można zapisać artykułu do %s" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "Wyniki wyszukiwania - '%s'" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "Kanał zapytania - %s" #: src/itemlist_formaction.cpp:1004 #, c-format msgid "Article List - %s" msgstr "Lista artykułów - %s" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "Góra" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "Dół" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "Kanał: " #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "Adres podcastu: " #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "typ: " #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "Błąd podczas oznaczania artykułu jako przeczytanego: %s" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "Dodano %s do kolejki pobierania." #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "Niepoprawny adres URL: '%s'" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "Zapisano artykuł do %s." #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "Błąd: nie można zapisać artykułu do pliku %s" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "Uruchamiam przeglądarkę..." #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "Błąd podczas oznaczania artykułu jako nieprzeczytanego: %s" #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "Idź do adresu URL" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "Otwórz w przeglądarce" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "Zakolejkuj" #: src/itemview_formaction.cpp:586 #, c-format msgid "Article - %s" msgstr "Artykuł - %s" #: src/itemview_formaction.cpp:624 msgid "Error: invalid regular expression!" msgstr "Błąd: nieprawidłowe wyrażenie regularne!" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "Otwórz kanał/artykuł" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "Powrót do poprzedniego okna/Wyjście" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "Wyjście z programu, bez potwierdzenia" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "Odśwież aktualnie wybrany kanał" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "Odśwież wszystkie kanały" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "Oznacz kanał jako przeczytany" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "Oznacz wszystkie kanały jako przeczytane" #: src/keymap.cpp:30 msgid "Save article" msgstr "Zapisz artykuł" #: src/keymap.cpp:31 msgid "Go to next article" msgstr "Przejdź do następnego artykułu" #: src/keymap.cpp:32 msgid "Go to previous article" msgstr "Przejdź do poprzedniego artykułu" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "Przejdź do następnego nieprzeczytanego artykułu" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "Przejdź do poprzedniego nieprzeczytanego artykułu" #: src/keymap.cpp:35 msgid "Go to a random unread article" msgstr "Przejdź do losowo wybranego artykułu" #: src/keymap.cpp:36 msgid "Open article in browser and mark read" msgstr "Otwórz artykuł w przeglądarce i oznacz jako przeczytany" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "Otwórz artykuł w przeglądarce" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "Otwórz okno pomocy" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "Przełącz widok źródła" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "Przełącz status przeczytania artykułu" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "Przełącz pokazywanie przeczytanych kanałów/artykułów" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "Pokaż odnośniki w aktualnym artykule" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "Wyczyść aktualny tag" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "Wybierz tag" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "Otwórz dialog wyszukiwania" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "Dodaj pobieranie do kolejki" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "Odśwież listę adresów kanałów z pliku konfiguracyjnego" #: src/keymap.cpp:50 msgid "Download file" msgstr "Pobierz plik" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "Anuluj pobieranie" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "Oznacz pobieranie jako usunięte" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "Wyczyść zakończone i usunięte pobierania z kolejki" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "Przełącz automatyczne pobieranie" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "Uruchom odtwarzacz z wybranym pobieraniem" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "Zwiększ ilość równoczesnych pobierań" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "Zmniejsz ilość równoczesnych pobierań" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "Odśwież ekran" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "Otwórz linię poleceń" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "Ustaw filtr" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "Wybierz przygotowany filtr" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "Wyzeruj aktualny filtr" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "Dodaj aktualny odsyłacz/artykuł do zakładek" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "Edytuj znaczniki" #: src/keymap.cpp:65 msgid "Go to next feed" msgstr "Idź do następnego kanału" #: src/keymap.cpp:66 msgid "Go to previous feed" msgstr "Idź do poprzedniego kanału" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "Idź do następnego nieprzeczytanego kanału" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "Idź do poprzedniego nieprzeczytanego kanału" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "Wywołaj makro" #: src/keymap.cpp:70 msgid "Delete article" msgstr "Usuń artykuł" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "Wyczyść usunięte artykuły" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "Edytuj subskrybowane adresy URL" #: src/keymap.cpp:73 msgid "Close currently selected dialog" msgstr "Zamknij wybrane okno dialogowe" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "Pokaż listę otwartych okien dialogowych" #: src/keymap.cpp:75 msgid "Go to next dialog" msgstr "Przejdź do następnego okna dialogowego" #: src/keymap.cpp:76 msgid "Go to previous dialog" msgstr "Powrót do poprzedniego okna dialogowego" #: src/keymap.cpp:77 msgid "Pipe article to command" msgstr "Przekaż artykuł do polecenia" #: src/keymap.cpp:78 msgid "Sort current list" msgstr "Posortuj obecną listę" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "Posortuj obecną listę (odwrotnie)" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "Otwórz URL 10" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "Otwórz URL 1" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "Otwórz URL 2" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "Otwórz URL 3" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "Otwórz URL 4" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "Otwórz URL 5" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "Otwórz URL 6" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "Otwórz URL 7" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "Otwórz URL 8" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "Otwórz URL 9" #: src/keymap.cpp:92 msgid "Move to the previous entry" msgstr "Idź do poprzedniego wpisu" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "Przejdź do następnego wpisu" #: src/keymap.cpp:94 msgid "Move to the previous page" msgstr "Powrót do poprzedniej strony" #: src/keymap.cpp:95 msgid "Move to the next page" msgstr "Przejdź do następnej strony" #: src/keymap.cpp:97 msgid "Move to the start of page/list" msgstr "Przejdź do początku strony/listy" #: src/keymap.cpp:98 msgid "Move to the end of page/list" msgstr "Przejdź do końca strony/listy" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "`%s' nie jest dopuszczalnym kontekstem" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "`%s' nie jest dopuszczalnym poleceniem" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "Czyszczenie kolejki..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "składnia %s [-C ] [-q ] [-h]\n" "-C użyj konfiguracji z pliku \n" "-q użyj jako pliku kolejki\n" "-a uruchom pobieranie przy starcie\n" "-h ta pomoc\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr " - %u równoległych pobrań" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "Kolejka (%u pobieranych plików, %u wszystkich) - %.2f kb/s całość%s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "Błąd: nie można wyjść, pobieranie w toku." #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "" "Błąd: pobieranie musi być zakończone zanim plik będzie mógł być odtworzony." #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "Błąd: nie można wykonać operacji: pobieranie w toku." #: src/pb_view.cpp:276 msgid "Download" msgstr "Pobierz" #: src/pb_view.cpp:278 msgid "Delete" msgstr "Usuń" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "Wyczyść zakończone" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "Przełącz automatyczne pobieranie" #: src/pb_view.cpp:281 msgid "Play" msgstr "Odtwórz" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "`%s' nie jest dopuszczalnym typem dialogu" #: src/regexmanager.cpp:49 #, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "`%s' nie jest poprawnym wyrażeniem regularnym: %s" #: src/rss.cpp:466 msgid "too few arguments" msgstr "zbyt mało parametrów." #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "Błąd: nieobsługiwany adres: %s" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "Wybierz tag" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "Wybierz filtr" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "atrybut nie znaleziony" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "trafiono na koniec pliku podczas odczytu tagu XML" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "Brak wybranego odnośnika!" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "Zapisz zakładkę" #: src/urlview_formaction.cpp:146 msgid "URLs" msgstr "Adresy: " #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "Błąd: użycie filtra nie powiodło się: %s" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "Błąd: kanał jest pusty!" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "Odświeżam kanał kolejki..." #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "korzeń pliku XML ma wartość NULL" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "nie udało się zainicjować libcurl" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "Błąd: przy próbie pobrania kanału `%s' zwrócony został kod błędu" "HTML %ld." #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "nie udało się przetworzyć bufora" #: rss/parser.cpp:174 msgid "could not parse file" msgstr "nie udało się przetworzyć pliku" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "brak wersji RSS" #: rss/parser.cpp:211 msgid "invalid RSS version" msgstr "błędna wersja RSS" #: rss/parser.cpp:226 rss/parser.cpp:233 msgid "invalid Atom version" msgstr "błędna wersja Atom" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "brak wersji Atom" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "niewspierany format kanału" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "brak kanałów" #, fuzzy #~ msgid "" #~ "%s %s\n" #~ "usage: %s [-i |-e] [-u ] [-c ] [-x " #~ " ...] [-h]\n" #~ "-e export OPML feed to stdout\n" #~ "-r refresh feeds on start\n" #~ "-i import OPML file\n" #~ "-u read RSS feed URLs from \n" #~ "-c use as cache file\n" #~ "-C read configuration from \n" #~ "-v clean up cache thoroughly\n" #~ "-x ... execute list of commands\n" #~ "-o activate offline mode (only applies to bloglines " #~ "synchronization mode)\n" #~ "-V get version information\n" #~ "-l write a log with a certain loglevel (valid values: 1 to " #~ "6)\n" #~ "-d use as output log file\n" #~ "-E export list of read articles to \n" #~ "-I import list of read articles from \n" #~ "-h this help\n" #~ msgstr "" #~ "%s %s\n" #~ "Użycie: %s [-i |-e] [-u ] [-c ] [-x " #~ " ...] [-h]\n" #~ "-e eksport OPML na standardowe wyjście\n" #~ "-r odśwież kanały po starcie\n" #~ "-i import pliku OPML\n" #~ "-u wczytaj adresy kanałów RSS z \n" #~ "-c użyj plik jako pamięć podręczną\n" #~ "-C wczytaj konfigurację z \n" #~ "-v dokładnie wyczyść pamięć podręczną\n" #~ "-x ... uruchom podaną listę komend\n" #~ "-o włącz tryb offline (dotyczy tylko synchronizacji z " #~ "bloglines)\n" #~ "-V wyświetl informację o wersji\n" #~ "-h wyświetl tą pomoc\n" newsbeuter-2.7/po/pt_BR.po000066400000000000000000001153561220711462700155460ustar00rootroot00000000000000# translation of pt_BR.po to Português do Brasil # translation of new.po to # translation of pt_BR.po to # Adiel Mittmann , 2007, 2008, 2009, 2010. # <>, 2011. msgid "" msgstr "" "Project-Id-Version: pt_BR\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2011-01-01 06:56-0200\n" "Last-Translator: <>\n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Portuguese\n" "X-Poedit-Country: BRAZIL\n" "X-Generator: Lokalize 0.3\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%" "10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "'%s' não é uma cor válida" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, c-format msgid "`%s' is not a valid attribute" msgstr "'%s' não é um atributo válido" #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "'%s' não é um elemento de configuração válido" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "" "newsbeuter: recarregamento terminado, %f fontes não lidos (%n artigos não " "lidos no total)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - Suas fontes (%u não lidas, %t no total)%?T? - etiqueta '%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - Artigos na fonte '%T' (%u não lidos, %t no total) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - Resultado da busca (%u não lidos, %t no total)" #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?Abrir Arquivo&Salvar arquivo? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - Ajuda" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - Selecione a etiqueta" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - Selecione o Filtro" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - Artigo '%T'" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - URLs" #: src/configcontainer.cpp:111 msgid "%N %V - Dialogs" msgstr "%N %V - Telas" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "um valor booleano era esperado, mas '%s' foi encontrado" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "um valor inteiro era esperado, mas '%s' foi encontrado" #: src/configcontainer.cpp:159 #, c-format msgid "invalid configuration value `%s'" msgstr "Valer de configuração '%s' é inválido" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "Erro ao processar o comando '%s' (%s linha %u). %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "comando desconhecido '%s'" #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "Erro fatal: não foi possível determinar o diretório do usuário!" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "" "Por favor defina a variável de ambiente HOME ou adicione um usuário válido " "para o UID %u!" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: opção desconhecida - %c" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "Iniciando o %s %s..." #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "Erro: uma instância de %s já está sendo executada (PID: %u)" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "Carregando configuração..." #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "pronto." #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "Abrindo o cache..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "Erro: falha ao abrir o arquivo de cache '%s': %s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "Carregando URLs do cache local..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "Carregando URLS a partir de %s..." #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "" "Erro: nenhuma URL configurada. Por favor preencha o arquivo %s com URLs de " "fontes RSS ou importe um arquivo OPML." #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "" "Parece que a fonte OPML especificada não tem fontes RSS. Por favor, preencha-" "a com fontes RSS e tente novamente." #: src/controller.cpp:392 msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" "Parece que você não configurou nenhuma fonte não sua conta do Google Reader. " "Faça isso, e tente novamente." #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "Carregando artigos do cache..." #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "Limpando o cache completamente..." #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "Erro carregando as fontes do banco de dados: " #: src/controller.cpp:430 #, c-format msgid "Error while loading feed '%s': %s" msgstr "Erro carregando fonte '%s': %s" #: src/controller.cpp:448 msgid "Prepopulating query feeds..." msgstr "Pré-povoando fontes de consulta..." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "Importando lista de artigos lidos..." #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "Exportando lista de artigos lidos..." #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "Limpando o cache..." #: src/controller.cpp:523 msgid "failed: " msgstr "falha: " #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "Erro: não foi possível marcar todos artigos como lidos: %s" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%sCarregando %s..." #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "Erro ao tentar obter %s: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "Erro: fonte RSS inválida!" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "índice de fonte inválido (erro de software)" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "" "O newsbeuter é um software livre e está licenciado sob a MIT/X Consortium " "License." #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "Digite '%s -vv' para mais informações." #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" "%s %s\n" "uso: %s [-i |-e] [-u ] [-c ] [-x " " ...] [-h]\n" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "exportar fonte OPML para a saída padrão" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "recarregar fontes ao iniciar" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 msgid "" msgstr "" #: src/controller.cpp:842 msgid "import OPML file" msgstr "importar arquivo OPML" #: src/controller.cpp:843 msgid "" msgstr "" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "ler URLs de fontes RSS de " #: src/controller.cpp:844 msgid "" msgstr "" #: src/controller.cpp:844 msgid "use as cache file" msgstr "usar como arquivo de cache" #: src/controller.cpp:845 msgid "" msgstr "" #: src/controller.cpp:845 msgid "read configuration from " msgstr "ler configurações de " #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "limpar completamente o cache" #: src/controller.cpp:847 msgid "..." msgstr "..." #: src/controller.cpp:847 msgid "execute list of commands" msgstr "executar lista de comandos" #: src/controller.cpp:848 msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "" "ativar modo offline (aplica-se somente ao modo de sincronização do Google " "Reader)" #: src/controller.cpp:849 msgid "quiet startup" msgstr "início silencioso" #: src/controller.cpp:850 msgid "get version information" msgstr "obter informações sobre a versão" #: src/controller.cpp:851 msgid "" msgstr "" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "" "escrever arquivo de log com um determinado nível de log (valores válidos: 1 " "a 6)" #: src/controller.cpp:852 msgid "" msgstr "" #: src/controller.cpp:852 msgid "use as output log file" msgstr "usar como arquivo de log" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "exportar lista de artigos lidos para " #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "importar lista de artigos lidos de " #: src/controller.cpp:855 msgid "this help" msgstr "esta ajuda" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "Um erro ocorreu durante a análise de %s." #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "Importação de %s concluída." #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "" "o suporte a marcadores não está configurado. Por favor defina a variável de " "configuração 'bookmark-cmd' conforme necessário." #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u artigos não lidos" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "Título: " #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "Autor: " #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "Data: " #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "Link: " #: src/controller.cpp:1388 #, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "Erro: não foi possível abrir o arquivo de configuração '%s'!" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "Fechar" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "Pular para Tela" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "Fechar Tela" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "Nenhum item selecionado!" #: src/dialogs_formaction.cpp:74 msgid "Error: you can't remove the feed list!" msgstr "Erro: você não pode remover a lista de fontes!" #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "Posição inválida!" #: src/download.cpp:42 msgid "queued" msgstr "na fila" #: src/download.cpp:44 msgid "downloading" msgstr "baixando" #: src/download.cpp:46 msgid "cancelled" msgstr "cancelado" #: src/download.cpp:48 msgid "deleted" msgstr "excluído" #: src/download.cpp:50 msgid "finished" msgstr "terminado" #: src/download.cpp:52 msgid "failed" msgstr "falhou" #: src/download.cpp:54 msgid "incomplete" msgstr "incompleto" #: src/download.cpp:56 msgid "played" msgstr "tocado" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "desconhecido (erro de software)" #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "atributo '%s' não está disponível." #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "a expressão regular '%s' é inválida: %s" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "parâmetros inválidos." #: src/exception.cpp:43 msgid "too few parameters." msgstr "poucos parâmetros." #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "comando desconhecido (erro de software)." #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "o arquivo não pôde ser aberto." #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "erro desconhecido (erro de software)" #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "Nenhuma fonte RSS selecionada!" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "" "Classificar por (p)rimeiraetiqueta/(t)ítulo/(q)uantidadeartigos/" "quantidadeartigos(n)ãolidos/nenhu(m)?" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "ptqnm" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "p" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "t" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "q" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "n" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "m" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "" "Classificar inversamente por (p)rimeiraetiqueta/(t)ítulo/(q)uantidadeartigos/" "quantidadeartigos(n)ãolidos/nenhu(m)?" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "Marcando fonte como lida..." #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "Erro: não foi possível marcar fonte como lida: %s" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "Nenhuma fonte RSS com artigos não lidos." #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "Já na última fonte" #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "Já na primeira fonte" #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "Marcando todas fontes RSS como lidas..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "Nenhuma etiqueta definida." #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "Erro: não foi possível analisar o comando de filtro '%s': %s" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "Nenhum filtro definido." #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "Procurar por: " #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "Filtro: " #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "Tem certeza que deseja sair (s: Sim n: Não)?" #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "sn" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "s" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "Sair" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "Abrir" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "Próxima Não Lida" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "Recarregar" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "Recarregar Todas" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "Marcar como Lida" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "Marcar Todas como Lidas" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "Procurar" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "Ajuda" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "Erro: não foi possível analisar o comando de filtro!" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "Procurando..." #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "Erro procurando por '%s': %s" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "Nenhum resultado." #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "A posição não está visível!" #: src/feedlist_formaction.cpp:774 #, c-format msgid "Feed List - %u unread, %u total" msgstr "Lista de Fontes - %u não lidas, %u no total" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "Tem certeza que deseja sobrescrever '%s' (s: Sim n:Não)?" #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "Arquivo: " #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - Abrir Arquivo - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - Salvar arquivo - %s" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "Cancelar" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "Salvar" #: src/filebrowser_formaction.cpp:271 #, c-format msgid "Open File - %s" msgstr "Abrir Arquivo - %s" #: src/filebrowser_formaction.cpp:273 #, c-format msgid "Save File - %s" msgstr "Salvar Arquivo - %s" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "não foi possível analisar a expressão de filtro '%s': %s" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "uso: set [=]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "uso: source [...]" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "uso: dumpconfig " #: src/formaction.cpp:231 #, c-format msgid "Saved configuration to %s" msgstr "Configuração salva em %s" #: src/formaction.cpp:236 #, c-format msgid "Not a command: %s" msgstr "Não é um comando: %s" #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "Salvando marcador..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "Marcador salvo." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "Erro ao salvar marcador: " #: src/formaction.cpp:303 msgid "URL: " msgstr "URL: " #: src/formaction.cpp:305 msgid "Description: " msgstr "Descrição: " #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "Pessoas que você segue" #: src/googlereader_urlreader.cpp:34 msgid "Starred items" msgstr "Itens com estrela" #: src/googlereader_urlreader.cpp:35 msgid "Shared items" msgstr "Itens compartilhados" #: src/googlereader_urlreader.cpp:36 msgid "Popular items" msgstr "Itens populares" #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "Ligações genéricas:" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "Funções sem ligações:" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "Limpar" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "flash embutido:" #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "imagem" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "Links: " #: src/htmlrenderer.cpp:594 msgid "link" msgstr "link" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "flash embutido" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "desconhecido (erro de software)" #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "Alternando estado lido/não lido do artigo..." #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "Erro ao alternar estado lido/não lido do artigo: %s" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "A lista de URLs está vazia." #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "Sinalizações: " #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "Erro: nenhum item selecionado!" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "Erro: você não pode recarregar os resultados da busca." #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "Nenhum artigo não lido." #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "Já no último item" #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "Já no primeiro item" #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "Nenhuma fonte não lida." #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "Passar o artigo por pipe ao comando: " #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "Classificar por (d)ata/(t)ítulo/(s)inalizações/(a)utor/(l)ink/(g)uid?" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 msgid "dtfalg" msgstr "dtsalg" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "d" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "t" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "s" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" "Classificar inversamente por (d)ata/(t)ítulo/(s)inalizações/(a)utor/(l)ink/" "(g)uid?" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "Sinalizações atualizadas." #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "Marcar Todos como Lidos" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "Salvamento cancelado." #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "Artigo salvo em %s" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "Erro: não foi possível salvar artigo em %s" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "Resultado da Busca - '%s'" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "Fonte de Consulta - %s" #: src/itemlist_formaction.cpp:1004 #, c-format msgid "Article List - %s" msgstr "Lista de Artigos - %s" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "Início" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "Fim" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "Fonte: " #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "URL para baixar Podcast: " #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "tipo: " #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "Erro marcando artigo como lido: %s" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "%s foi adicionado à fila para ser baixado." #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "URL inválida: '%s'" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "Artigo salvo em %s." #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "Erro: não foi possível gravar o artigo no arquivo %s" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "Iniciando navegador..." #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "Erro marcando artigo como não lido: %s" #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "Ir para a URL #" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "Abrir no Navegador" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "Pôr na Fila" #: src/itemview_formaction.cpp:586 #, c-format msgid "Article - %s" msgstr "Artigo - %s" #: src/itemview_formaction.cpp:624 msgid "Error: invalid regular expression!" msgstr "Erro: expressão regular inválida!" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "Abrir fonte/artigo" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "Retornar à tela anterior/Sair" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "Fechar o programa, sem confirmação" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "Atualizar a fonte selecionada" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "Atualizar todas fontes" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "Marcar fonte como lida" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "Marcar todas fontes como lidas" #: src/keymap.cpp:30 msgid "Save article" msgstr "Salvar artigo" #: src/keymap.cpp:31 msgid "Go to next article" msgstr "Ir para o próximo artigo" #: src/keymap.cpp:32 msgid "Go to previous article" msgstr "Ir para o artigo anterior" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "Ir para o próximo artigo não lido" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "Ir para o artigo não lido anterior" #: src/keymap.cpp:35 msgid "Go to a random unread article" msgstr "Pular para um artigo não lido aleatório" #: src/keymap.cpp:36 msgid "Open article in browser and mark read" msgstr "Abrir artigo no navegador e marca-o como lido" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "Abrir artigo no navegador" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "Abrir a tela de ajuda" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "Alternar a visualização do código-fonte" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "Alternar o estado lido/não lido do artigo" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "Alternar a visualização de fontes RSS/artigos não lidos" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "Mostrar URLs no artigo atual" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "Limpar etiqueta atual" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "Selecionar etiqueta" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "Abrir tela de procura" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "Adicionar à fila para ser baixado" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "Atualizar a lista de URLs a partir da configuração" #: src/keymap.cpp:50 msgid "Download file" msgstr "Baixar arquivo" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "Cancelar a transferência" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "Marcar transferência como excluída" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "Eliminar transferências concluídas ou excluídas da fila" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "Ativar/desativar transferência automática" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "Iniciar tocador com a transferência selecionada" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "Aumentar número de transferências simultâneas" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "Diminuir o número de transferências simultâneas" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "Redesenhar tela" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "Abrir a linha de comando" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "Definir um filtro" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "Selecionar um filtro pré-definido" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "Limpar o filtro atual" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "Adicionar marcador ao link ou artigo atual" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "Editar sinalizações" #: src/keymap.cpp:65 msgid "Go to next feed" msgstr "Ir para a próxima fonte" #: src/keymap.cpp:66 msgid "Go to previous feed" msgstr "Ir para a fonte anterior" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "Ir para a próxima fonte não lida" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "Ir para a fonte não lida anterior" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "Chamar uma macro" #: src/keymap.cpp:70 msgid "Delete article" msgstr "Excluir artigo" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "Eliminar artigos excluídos" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "Editar lista de URLs assinadas" #: src/keymap.cpp:73 msgid "Close currently selected dialog" msgstr "Fechar a tela atualmente selecionada" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "Ver lista de telas abertos" #: src/keymap.cpp:75 msgid "Go to next dialog" msgstr "Ir para a próxima tela" #: src/keymap.cpp:76 msgid "Go to previous dialog" msgstr "Retornar à tela anterior" #: src/keymap.cpp:77 msgid "Pipe article to command" msgstr "Passar artigo por pipe a um comando" #: src/keymap.cpp:78 msgid "Sort current list" msgstr "Ordenar a lista atual" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "Ordenar a lista atual (inversamente)" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "Abrir URL 10" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "Abrir URL 1" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "Abrir URL 2" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "Abrir URL 3" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "Abrir URL 4" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "Abrir URL 5" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "Abrir URL 6" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "Abrir URL 7" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "Abrir URL 8" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "Abrir URL 9" #: src/keymap.cpp:92 msgid "Move to the previous entry" msgstr "Ir para o item anterior " #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "Ir para o próximo item" #: src/keymap.cpp:94 msgid "Move to the previous page" msgstr "Ir para a página anterior" #: src/keymap.cpp:95 msgid "Move to the next page" msgstr "Ir para a próxima página" #: src/keymap.cpp:97 msgid "Move to the start of page/list" msgstr "Ir para o início da página/lista" #: src/keymap.cpp:98 msgid "Move to the end of page/list" msgstr "Ir para o fim da página/lista" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "'%s' não é um contexto válido" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "'%s' não é um comando de tecla válido" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "Limpando fila..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "uso %s [-C ] [-q ] [-h]\n" "-C ler configuração do \n" "-q usar o como arquivo da fila\n" "-a começar a baixar já no início\n" "-h esta ajuda\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr " - %u transferências simultâneas" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "Fila (%u transferências em progresso, %u no total) - %.2f kb/s total%s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "Erro: não é possível sair: transferência(s) em progresso" #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "" "Erro: a transferência precisa ser concluída antes de o arquivo ser tocado." #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "" "Erro: não foi possível realizar a operação: transferência(s) em progresso." #: src/pb_view.cpp:276 msgid "Download" msgstr "Baixar" #: src/pb_view.cpp:278 msgid "Delete" msgstr "Excluir" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "Eliminar Concluídos" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "Alternar Transferência Automática" #: src/pb_view.cpp:281 msgid "Play" msgstr "Tocar" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "'%s' é um tipo inválido de tela" #: src/regexmanager.cpp:49 #, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "'%s' não é uma expressão regular válida: %s" #: src/rss.cpp:466 msgid "too few arguments" msgstr "poucos parâmetros" #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "Erro: URL não suportada: %s" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "Selecionar Etiqueta" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "Selecionar Filtro" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "atributo não encontrado" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "Fim de arquivo encontrado ao ler etiqueta XML" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "Nenhum link selecionado!" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "Salvar Marcador" #: src/urlview_formaction.cpp:146 msgid "URLs" msgstr "URLs" #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "Erro: aplicação do filtro falhou: %s" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "Erro: fonte não possui nenhum item!" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "Atualizando fonte de consulta..." #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "O nó raiz do XML é NULL" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "não foi possível inicializar a libcurl" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "" "Erro: ao tentar baixar a fonte '%s', o erro HTTP de código %ld foi retornado." #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "não foi possível analisar o buffer" #: rss/parser.cpp:174 msgid "could not parse file" msgstr "não foi possível analisar o arquivo" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "RSS sem versão" #: rss/parser.cpp:211 msgid "invalid RSS version" msgstr "versão de RSS inválida" #: rss/parser.cpp:226 rss/parser.cpp:233 msgid "invalid Atom version" msgstr "versão de Atom inválida" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "Atom sem versão" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "formato de fonte não suportado" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "nenhum canal RSS encontrado" #~ msgid "" #~ "It looks like you haven't configured any feeds in your bloglines account. " #~ "Please do so, and try again." #~ msgstr "" #~ "Parece que você não configurou nenhuma fonte não sua conta bloglines. " #~ "Faça isso, e tente novamente." newsbeuter-2.7/po/ru.po000066400000000000000000001312761220711462700151650ustar00rootroot00000000000000# Russian translation for newsbeuter. # Sergey Dryabzhinsky , 2008. # msgid "" msgstr "" "Project-Id-Version: newsbeuter 1.3\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2008-11-18 17:38+0300\n" "Last-Translator: Sergey Dryabzhinsky \n" "Language-Team: ru \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Russian\n" "X-Poedit-Country: RUSSIAN FEDERATION\n" "X-Poedit-SourceCharset: utf-8\n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "цвета `%s' не существует" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, c-format msgid "`%s' is not a valid attribute" msgstr "атрибута `%s' не существует" #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "элемента конфигурации `%s' не существует" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "" "newsbeuter: обновление завершено, %f не прочитанных лент (всего %n заметок " "не прочитано)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - Ваши ленты (непрочитанно %u, всего %t)%?T? - метка `%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - Заметок в ленте '%T' (непрочитанно %u, всего %t) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - Результаты поиска (непрчитанно %u, всего %t)" #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?Открыть файл&Сохранить файл? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - Помощь" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - Выбрать Метку" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - Выбрать Фильтр" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - Заметка '%T'" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - Ссылки" #: src/configcontainer.cpp:111 msgid "%N %V - Dialogs" msgstr "%N %V - Ссылки" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "ожидалось булево значение, обнаружилось `%s'" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "ожидалось целое число, обнаружилось `%s'" #: src/configcontainer.cpp:159 #, c-format msgid "invalid configuration value `%s'" msgstr "неверное значение конфигурации `%s'" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "Ошибка во время выполнения команды `%s' (%s строка %u): %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "неизвестная команда `%s'" #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "Фатальная ошибка: невозможно определить домашний каталог!" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "" "Пожалуйста, задайте значение переменной окружения HOME " "или добавьте подходящего пользователя для UID %u!" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: неизвестный параметр - %c" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "Запускаю %s %s..." #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "Ошибка: уже запущена копия %s (PID: %u)" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "Загружаю настройки..." #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "сделано." #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "Открываю кеш..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "Ошибка: попытка отрыть файл кэша `%s' завершилась неудачей: %s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "Загружаю ссылки из локального кеша..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "Загружаю ссылки из %s..." #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "" "Ошибка: не найдено ни одной ссылки. Пожалуйста, занесите в файл %s ссылкина " "RSS ленты или импортируйте файл OPML." #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "" "Похоже что лента OPML, на которую вы подписались не содержит лент новостей." "Пожалуйста заполните её лентами и попробуйте еще раз." #: src/controller.cpp:392 msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" "Похоже что вы не настроили ни одной ленты новостей в своей учётной записи в " "Google Reader. Сделайте это и попробуйте еще раз." #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "Загружаю заметки из кеша..." #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "Тщательно очищаю кеш..." #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "Ошибка во время загрузки лент новостей из базы: " #: src/controller.cpp:430 #, c-format msgid "Error while loading feed '%s': %s" msgstr "Ошибка во время загрузки ленты '%s': %s" #: src/controller.cpp:448 msgid "Prepopulating query feeds..." msgstr "Заполняю динамические ленты..." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "Импортирую список прочитанных заметок..." #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "Экспортирую список прочитанных заметок..." #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "Очищаю кеш..." #: src/controller.cpp:523 msgid "failed: " msgstr "не получилось: " #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "Ошибка: невозможно отметить все ленты как прочитанные: %s" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%sЗагружается %s..." #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "Ошибка во время получения %s: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "Ошибка: неправильная лента!" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "неверный индекс ленты (сбой)" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "" #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "" #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" "%s %s\n" "Использование: %s [-i <файл>|-e] [-u <файл с сылками>] [-c <файл кеша>] [-x " "<команда> ...] [-h]\n" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "экспорт ленты OPML в стандартный вывод" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "обновить ленты после запуска" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 msgid "" msgstr "<файл>" #: src/controller.cpp:842 msgid "import OPML file" msgstr "импортировать файл OPML" #: src/controller.cpp:843 msgid "" msgstr "<файл с ссылками>" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "загрузить список ссылок на ленты RSS из <файла ссылок>" #: src/controller.cpp:844 msgid "" msgstr "<файл кеша>" #: src/controller.cpp:844 msgid "use as cache file" msgstr "использовать <файл кеша> как файл для кеша" #: src/controller.cpp:845 msgid "" msgstr "<файл настроек>" #: src/controller.cpp:845 msgid "read configuration from " msgstr "считать настройки из <файла настроек>" #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "тщательно очищаю кэш..." #: src/controller.cpp:847 msgid "..." msgstr "<команда>..." #: src/controller.cpp:847 msgid "execute list of commands" msgstr "выполнить список команд" #: src/controller.cpp:848 msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "включить автономный режим (только для синхронизации Google Reader)" #: src/controller.cpp:849 msgid "quiet startup" msgstr "тихий запуск" #: src/controller.cpp:850 msgid "get version information" msgstr "получить информацию о версии" #: src/controller.cpp:851 msgid "" msgstr "<уровень>" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "записывать в журнал сообщения определенного уровня (от 1 до 6)" #: src/controller.cpp:852 msgid "" msgstr "<файл журнала>" #: src/controller.cpp:852 msgid "use as output log file" msgstr "использовать <файл журнала> как файл вывода для журнала" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "экспорт прочитанных заметок в <файл>" #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "импорт списка прочитанных заметок из <файла>" #: src/controller.cpp:855 msgid "this help" msgstr "эта помощь" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "При обработке %s возникла ошибка." #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "Импорт %s завершён." #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "" "поддержка закладок не настроена. Пожалуйста установите в настройках " "верноезначение переменной `bookmark-cmd'." #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u непрочитанных заметок" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "Заголовок: " #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "Автор: " #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "Дата: " #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "Ссылка: " #: src/controller.cpp:1388 #, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "Ошибка: невозможно открыть конфигурационный файл `%s'!" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "Закрыть" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "Открыть диалог" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "Закрыть диалог" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "Не выбранно ни одного элемента!" #: src/dialogs_formaction.cpp:74 msgid "Error: you can't remove the feed list!" msgstr "Ошибка: невозможно убрать список лент!" #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "Неверная позиция!" #: src/download.cpp:42 msgid "queued" msgstr "в очереди" #: src/download.cpp:44 msgid "downloading" msgstr "загружается" #: src/download.cpp:46 msgid "cancelled" msgstr "отменено" #: src/download.cpp:48 msgid "deleted" msgstr "удалено" #: src/download.cpp:50 msgid "finished" msgstr "закончено" #: src/download.cpp:52 msgid "failed" msgstr "неудачно" #: src/download.cpp:54 msgid "incomplete" msgstr "не полностью" #: src/download.cpp:56 msgid "played" msgstr "проиграно" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "неизвестно (сбой)." #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "атрибут `%s' недоступен." #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "регулярное выражение '%s' неверно: %s" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "неправильные параметры." #: src/exception.cpp:43 msgid "too few parameters." msgstr "слишком мало параметров." #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "неизвестная команда (сбой)." #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "файл невозможно открытым." #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "неизвестная ошибка (сбой)." #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "Не выбрано ни одной ленты!" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "Сотировать по первой метке (f)/заголовку (t)/количеству записей (a)/непрочитанным (u)/никак (n)?" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "n" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "Отмечаю ленту как прочитанную..." #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "Ошибка: невозможно отметить ленту как прочитанную: %s" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "Нет лент с непрочитанными элементами." #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "Уже на последней ленте." #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "Уже на первой ленте." #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "Отмечаю все ленты как прочитанные..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "Не определено ни одной метки." #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "Ошибка: невозможно разобрать команду фильтрации `%s': %s" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "Не определено ни одного фильтра." #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "Искать: " #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "Фильтр: " #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "Вы правда хотите выйти (y:Да n:Нет)? " #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "yn" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "y" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "Выход" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "Открыть" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "Следующая непрочитанная" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "Обновить" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "Обновить все" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "Отметить как прочитанную" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "Подхватить все" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "Искать" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "Помощь" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "Ошибка: невозможно разобрать команду фильтрации!" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "Ищу..." #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "Ошибка во время поиска `%s': %s" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "Нет результатов." #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "Позицию не видно!" #: src/feedlist_formaction.cpp:774 #, c-format msgid "Feed List - %u unread, %u total" msgstr "Список лент - %u непрочитанных, %u всего" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "Вы правда хотите перезаписать `%s' (y:Да n:Нет)? " #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "Файл: " #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - Открыть файл - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - Сохранить файл - %s" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "Отмена" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "Сохранить" #: src/filebrowser_formaction.cpp:271 #, c-format msgid "Open File - %s" msgstr "Открыть файл - %s" #: src/filebrowser_formaction.cpp:273 #, c-format msgid "Save File - %s" msgstr "Сохранить файл - %s" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "не удалось разобрать команду фильтрации `%s': %s" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "использование: set <переменная>[=<значение>]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "использование: source [...]" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "использование: dumpconfig <файл>" #: src/formaction.cpp:231 #, c-format msgid "Saved configuration to %s" msgstr "Конфигурация сохранена в %s" #: src/formaction.cpp:236 #, c-format msgid "Not a command: %s" msgstr "Неизвестная команда: %s" #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "Сохраняю закладку..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "Сохранённая закладка." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "Ошибка во время сохранения закладки: " #: src/formaction.cpp:303 msgid "URL: " msgstr "Источник: " #: src/formaction.cpp:305 msgid "Description: " msgstr "Описание: " #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "" #: src/googlereader_urlreader.cpp:34 msgid "Starred items" msgstr "Избранные элементы" #: src/googlereader_urlreader.cpp:35 msgid "Shared items" msgstr "Опубликованные элементы" #: src/googlereader_urlreader.cpp:36 msgid "Popular items" msgstr "Популярные элементы" #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "Общие привязки:" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "Отвязанные функции:" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "Чистый" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "встроенный flash:" #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "изображение" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "Ссылки: " #: src/htmlrenderer.cpp:594 msgid "link" msgstr "ссылка" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "встроенный flash:" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "неизвестно (сбой)" #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "Переключение флага прочтения у заметки..." #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "Ошибка во время переключения флага прочтения: %s" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "Список ссылок пуст." #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "Флаги: " #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "Ошибка: не выбранно ни одного элемента!" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "Ошибка: вы не можете обновить результаты поиска." #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "Непрочитанных элементов нет." #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "Уже на последней записи." #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "Уже на первой записи." #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "Непрочитанных лент нет." #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "Обработать заметку командой: " #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "Сортировать по дате (d)/заголовку (t)/флагам (f)/автору (a)/ссылке (l)/(g)uid?" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 msgid "dtfalg" msgstr "dtfalg" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "Флаги обновлены." #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "Отметить все как прочитанные" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "Прерванное сохранение." #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "Заметка сохранена в %s" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "Ошибка: невозможно сохранить заметку в %s" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "Результат поиска - '%s'" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "Лента по запросу - %s" #: src/itemlist_formaction.cpp:1004 #, c-format msgid "Article List - %s" msgstr "Список заметок - %s" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "Верх" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "Низ" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "Лента: " #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "Ссылка загрузки подкаста: " #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "тип: " #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "Ошибка во время потметки заметки как прочитанной: %s" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "Добавили %s в очередь загрузки." #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "Неверная ссылка: '%s'" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "Заметка сохранена в %s." #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "Ошибка: невозможно записать заметку в файл %s" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "Запускаю навигатор..." #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "Ошибка во время пометки заметки как прочитанной: %s" #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "Открыть ссылку №" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "Открыть в навигаторе" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "Поставить в очередь" #: src/itemview_formaction.cpp:586 #, c-format msgid "Article - %s" msgstr "Заметка - %s" #: src/itemview_formaction.cpp:624 msgid "Error: invalid regular expression!" msgstr "Ошибка: неправильное регулярное выражение!" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "Открыть ленту/заметку" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "Вернуться в предыдущий диалог/Выйти" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "Закрыть программу без подтверждения" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "Обновить выбранную ленту" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "Обновить все ленты" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "Отметить ленту как прочитанную" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "Отметить все ленты как прочитанные" #: src/keymap.cpp:30 msgid "Save article" msgstr "Сохранить заметку" #: src/keymap.cpp:31 msgid "Go to next article" msgstr "Перейти к следующей непрочитанной заметке" #: src/keymap.cpp:32 msgid "Go to previous article" msgstr "Перейти к предыдущей заметке" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "Перейти к следующей непрочитанной заметке" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "Перейти к предыдущей непрочитанной заметке" #: src/keymap.cpp:35 msgid "Go to a random unread article" msgstr "Перейти к случайной непрочитанной заметке" #: src/keymap.cpp:36 msgid "Open article in browser and mark read" msgstr "Открыть заметку в навигаторе и отметить прочитанной" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "Открыть заметку в навигаторе" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "Открыть диалог помощи" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "Переключиться на просмотр исходных данных" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "Переключить статус прочтения заметки" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "Включить показ прочитанных лент" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "Показывать ссылки в текущей заметке" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "Очистить текущую метку" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "Выбрать метку" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "Открыть диалог поиска" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "Добавить загрузку в очередь" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "Обновить список ссылок из файла настроек" #: src/keymap.cpp:50 msgid "Download file" msgstr "Загрузить файл" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "Отменить загрузку" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "Отметить загрузку как удаленную" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "Очистить очередь от законченных и удалённых загрузок" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "Переключить автоматическую загрузку вкл/выкл" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "Запустить проигрыватель с текущей выбранной закачкой" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "Увеличить количество одновременных загрузок" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "Уменьшить количество одновременных загрузок" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "Обновить экран" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "Открыть командную строку" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "Установить фильтр" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "Выбрать предопределённый фильтр" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "Очистить текущий фильтр" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "Занести в закладки текущую ссылку/заметку" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "Редактировать флаги" #: src/keymap.cpp:65 msgid "Go to next feed" msgstr "Перейти к следующей ленте" #: src/keymap.cpp:66 msgid "Go to previous feed" msgstr "Перейти к предыдущей ленте" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "Перейти к следующей непрочитанной ленте" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "Перейти к предыдущей непрочитанной ленте" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "Вызвать макрос" #: src/keymap.cpp:70 msgid "Delete article" msgstr "Удалить заметку" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "Очистить от удаленных заметок" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "Изменить подписанные ссылки" #: src/keymap.cpp:73 msgid "Close currently selected dialog" msgstr "Закрыть текущий диалог" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "Просмотреть список открытых окон" #: src/keymap.cpp:75 msgid "Go to next dialog" msgstr "Перейти к следующему диалогу" #: src/keymap.cpp:76 msgid "Go to previous dialog" msgstr "Вернуться в предыдущий диалог" #: src/keymap.cpp:77 msgid "Pipe article to command" msgstr "Обработать заметку командой" #: src/keymap.cpp:78 msgid "Sort current list" msgstr "Отсортировать текущий список" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "Отсортировать список в обратном порядке" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "Открыть ссылку 10" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "Открыть ссылку 1" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "Открыть ссылку 2" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "Открыть ссылку 3" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "Открыть ссылку 4" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "Открыть ссылку 5" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "Открыть ссылку 6" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "Открыть ссылку 7" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "Открыть ссылку 8" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "Открыть ссылку 9" #: src/keymap.cpp:92 msgid "Move to the previous entry" msgstr "Перейти к предыдущей заметке" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "Перейти к следующей заметке" #: src/keymap.cpp:94 msgid "Move to the previous page" msgstr "Вернуться на предыдущую страницу" #: src/keymap.cpp:95 msgid "Move to the next page" msgstr "Перейти к следующей странице" #: src/keymap.cpp:97 msgid "Move to the start of page/list" msgstr "Перейти к началу страницы/списка" #: src/keymap.cpp:98 msgid "Move to the end of page/list" msgstr "Перейти к концу страницы/списка" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "контекста `%s' не существует" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "команда `%s' не поддерживается" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "Очистищаю очередь..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "Использование: %s [-C <файл>] [-q <файл>] [-h]\n" "-C <файл настроек> читать настройки из <файла настроек>\n" "-q <файл очереди> использовать <файл очереди> как файл очереди\n" "-a продолжить загрузки после запуска программы\n" "-h показать эту справку\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr " - %u параллельных загрузок" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "Очередь (активных загрузок %u, всего %u) - %.2f кб/сек всего%s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "Ошибка: не могу выйти: загрузка(и) активна(ы)." #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "" "Ошибка: загрузка должна закончиться прежде чем файл может быть проигран." #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "Ошибка: невозможно выполнить действие: загрузка(и) активна(ы)." #: src/pb_view.cpp:276 msgid "Download" msgstr "Загрузить" #: src/pb_view.cpp:278 msgid "Delete" msgstr "Удалить" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "Очистить от завершённых" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "Переключить автоматическую загрузку" #: src/pb_view.cpp:281 msgid "Play" msgstr "Проиграть" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "" #: src/regexmanager.cpp:49 #, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "`%s' — неверное регулярное выражение:%s" #: src/rss.cpp:466 msgid "too few arguments" msgstr "слишком мало параметров" #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "Ошибка: ссылка не поддерживается: %s" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "Выбрать метку" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "Выбрать фильтр" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "атрибут не найден" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "Во время чтения тега XML обнаружен конец файла" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "Не выбрано ни одной ссылки!" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "Сохранить закладку" #: src/urlview_formaction.cpp:146 msgid "URLs" msgstr "Источники" #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "Ошибка: применение фильтра завершилось неудачей: %s" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "Ошибка: лента не содержит ни одного элемента!" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "Обновляю ленту очереди..." #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "Отсутствует корневой элемент XML документа" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "не удалось настроить libcurl" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "Ошибка: при загрузке ленты `%s' получен HTTP-код %ld." #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "не удалось разобрать буффер" #: rss/parser.cpp:174 msgid "could not parse file" msgstr "не удалось разобрать файл" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "нет версии RSS" #: rss/parser.cpp:211 msgid "invalid RSS version" msgstr "неверная версия RSS" #: rss/parser.cpp:226 rss/parser.cpp:233 msgid "invalid Atom version" msgstr "неверная версия Atom" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "нет версии Atom" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "неизвестный тип ленты" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "RSS-лента не найдена" newsbeuter-2.7/po/sv.po000066400000000000000000001130641220711462700151620ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: newsbeuter-1.4\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2009-03-16 21:29+0100\n" "Last-Translator: \n" "Language-Team: \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Swedish\n" "X-Poedit-Country: SWEDEN\n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "`%s' är inte en giltig färg" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, c-format msgid "`%s' is not a valid attribute" msgstr "`%s' är inte ett giltigt attribut" #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "`%s' är inte ett giltigt konfigurationselement" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "" "newsbeuter: omläsning färdig, %f olästa webbkanaler (%n olästa artiklar " "totalt)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - Dina webbkanaler (%u olästa, %t totalt)%?T? - tag `%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - Artiklar i webbkanal '%T' (%u olästa, %t totalt) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - Sökresultat (%u olästa, %t totalt)" #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?Öppna fil&Spara fil? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - Hjälp" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - Markera tagg" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - Markera filter" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - Artikel '%T'" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - Url:er" #: src/configcontainer.cpp:111 msgid "%N %V - Dialogs" msgstr "%N %V - Dialogrutor" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "boolean-värde förväntades, hittade `%s' istället" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "integer-värde förväntades, hittade `%s' istället" #: src/configcontainer.cpp:159 #, fuzzy, c-format msgid "invalid configuration value `%s'" msgstr "Sparade konfiguration till %s" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "Fel vid behandling av kommando `%s' (%s rad %u): %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "okänt kommando `%s'" #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "Allvarligt fel: kunde inte fastställa hemkatalog!" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "" "Var god ställ in HOME-miljövariabeln eller lägg till en giltig användare för " "UID %u!" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: okänt alternativ - %c" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "Startar %s %s..." #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "Fel: ett exemplar av %s körs redan (PID: %u)" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "Läser in konfiguration..." #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "färdig." #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "Öppnar cache..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "Fel: öppnande av cache-fil `%s' misslyckades: %s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "Läser in url:er från lokal cache..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "Läser in url:er från %s..." #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "" "Fel: inga url:er konfigurerade. Var god fyll filen %s med RSS-webbkanalsurl:" "er eller importera en OPML-fil." #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "" "Det ser ut som om OPML-webbkanalen som du valde att prenumerera på inte " "innehåller några webbkanaler. Var god fyll den med webbkanaler och prova " "igen." #: src/controller.cpp:392 #, fuzzy msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" "Det ser ut som om du inte har konfigurerat några webbkanaler i ditt " "bloglines-konto. Var god gör det och prova igen." #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "Läser in artiklar från cache..." #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "Tömmer noggrant cache..." #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "Fel inträffade vid inläsning av webbkanaler i databasen:" #: src/controller.cpp:430 #, fuzzy, c-format msgid "Error while loading feed '%s': %s" msgstr "Fel vid sökning efter `%s': %s" #: src/controller.cpp:448 msgid "Prepopulating query feeds..." msgstr "Förbefolkar webbkanalsförfrågningar..." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "Importerar lista över lästa artiklar..." #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "Exporterar lista över lästa artiklar..." #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "Tömmer cache..." #: src/controller.cpp:523 msgid "failed: " msgstr "misslyckades:" #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "Fel: kunde inte markera alla webbkanaler som lästa: %s" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%sLäser in %s..." #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "Fel vid hämtning av %s: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "Fel: ogiltig webbkanal!" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "ogiltigt webbkanalsindex (fel)" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "" "newsbeuter är fri programvara och licenserat under MIT/X Consortium-licensen." #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "Skriv `%s -vv' för mer information." #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" "%s %s\n" "användning: %s [-i |-e] [-u ] [-c ] [-x " " ...] [-h]\n" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "exportera OPML-webbkanal till stdout" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "uppdatera webbkanaler vid uppstart" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 msgid "" msgstr "" #: src/controller.cpp:842 msgid "import OPML file" msgstr "importera OPML-fil" #: src/controller.cpp:843 msgid "" msgstr "" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "läs in RSS-webbkanalsurl:er från " #: src/controller.cpp:844 msgid "" msgstr "" #: src/controller.cpp:844 msgid "use as cache file" msgstr "använd som cache-fil" #: src/controller.cpp:845 msgid "" msgstr "" #: src/controller.cpp:845 msgid "read configuration from " msgstr "läs in konfiguration från " #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "tömmer noggrant cache" #: src/controller.cpp:847 msgid "..." msgstr "..." #: src/controller.cpp:847 msgid "execute list of commands" msgstr "verkställ lista över kommandon" #: src/controller.cpp:848 #, fuzzy msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "" "aktivera frånkopplingsläge (verkställs bara till läge för bloglines-" "synkronisering)" #: src/controller.cpp:849 msgid "quiet startup" msgstr "" #: src/controller.cpp:850 msgid "get version information" msgstr "hämta versionsinformation" #: src/controller.cpp:851 msgid "" msgstr "" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "skriv en logg med en särskild loggnivå (giltiga värden: 1 till 6)" #: src/controller.cpp:852 msgid "" msgstr "" #: src/controller.cpp:852 msgid "use as output log file" msgstr "använd som loggfil för utdata" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "exportera lista över lästa artiklar till " #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "importera lista över lästa artiklar till " #: src/controller.cpp:855 msgid "this help" msgstr "denna hjälp" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "Ett fel inträffade vid tolkning av %s." #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "Importering av %s färdig" #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "" "Stöd för bokmarkering är inte konfigurerat. Var god ställ in " "konfigurationsvariablen `bookmark-cdm' korrekt." #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u olästa artiklar" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "Titel:" #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "Författare:" #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "Datum:" #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "Länk:" #: src/controller.cpp:1388 #, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "Fel: kunde inte öppna konfigurationsfil `%s'!" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "Stäng" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "Gå till-dialogruta" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "Stäng dialogruta" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "Ingen post markerad!" #: src/dialogs_formaction.cpp:74 msgid "Error: you can't remove the feed list!" msgstr "Fel: du kan inte ta bort webbkanalslistan!" #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "Ogiltig position!" #: src/download.cpp:42 msgid "queued" msgstr "kölagd" #: src/download.cpp:44 msgid "downloading" msgstr "hämtar" #: src/download.cpp:46 msgid "cancelled" msgstr "avbruten" #: src/download.cpp:48 msgid "deleted" msgstr "borttagen" #: src/download.cpp:50 msgid "finished" msgstr "färdiga" #: src/download.cpp:52 msgid "failed" msgstr "misslyckade" #: src/download.cpp:54 msgid "incomplete" msgstr "ofullständiga" #: src/download.cpp:56 msgid "played" msgstr "uppspelat" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "okänt (fel)." #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "attribut `%s' är inte tillgängligt." #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "reguljärt uttryck '%s' är ogiltigt: %s" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "ogiltiga parametrar." #: src/exception.cpp:43 msgid "too few parameters." msgstr "för få parametrar." #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "okänt kommando (fel)." #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "fil kunde inte öppnas." #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "okänt fel (fel)." #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "Ingen kanal markerad!" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "" "Sortera utifrån (f)örstatagg/(t)itel/(a)rtikelmängd/(o)lästartikelmängd/(i)" "nget?" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "ftaun" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "f" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "t" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "a" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "u" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "n" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "" "Sortera omvänt utifrån (f)örstatagg/(t)itel/a)rtikelmängd/(o)" "lästartikelmängd/(i)nget?" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "Markerar webbkanal som läst..." #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "Fel: kunde inte markera webbkanal som läst: %s" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "Inga webbkanaler med olästa poster." #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "" #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "" #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "Markerar alla webbkanaler som lästa..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "Inga taggar definierade." #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "Fel: kunde inte tolka filterkommando `%s': %s" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "Inga filter definierade." #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "Sök efter:" #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "Filter: " #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "Vill du verkligen avsluta (j:Ja n:Nej)?" #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "jn" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "j" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "Avsluta" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "Öppna" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "Nästa olästa" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "Läs om" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "Läs om alla" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "Markera som läst" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "Catchup All" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "Sök" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "Hjälp" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "Fel: kunde inte tolka filterkommando!" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "Söker..." #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "Fel vid sökning efter `%s': %s" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "Inga resultat." #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "Position syns inte!" #: src/feedlist_formaction.cpp:774 #, c-format msgid "Feed List - %u unread, %u total" msgstr "Webbkanalslista - %u olästa, %u totalt" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "Vill du verkligen skriva över %s' (j:Ja n:Nej)?" #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "Fil:" #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - Öppna fil - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - Spara fil - %s" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "Avbryt" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "Spara" #: src/filebrowser_formaction.cpp:271 #, c-format msgid "Open File - %s" msgstr "Öppna fil - %s" #: src/filebrowser_formaction.cpp:273 #, c-format msgid "Save File - %s" msgstr "Spara fil - %s" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "kunde inte tolka filteruttryck `%s': %s" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "användning: ställ in [=]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "användning: source [...]" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "användning: dumpconfig " #: src/formaction.cpp:231 #, c-format msgid "Saved configuration to %s" msgstr "Sparade konfiguration till %s" #: src/formaction.cpp:236 #, c-format msgid "Not a command: %s" msgstr "Inte ett kommando: %s" #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "Sparar bokmärke..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "Sparade bokmärke." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "Fel vid sparande av bokmärke:" #: src/formaction.cpp:303 msgid "URL: " msgstr "Url:" #: src/formaction.cpp:305 msgid "Description: " msgstr "Beskrivning:" #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "" #: src/googlereader_urlreader.cpp:34 #, fuzzy msgid "Starred items" msgstr "Inga olästa poster." #: src/googlereader_urlreader.cpp:35 #, fuzzy msgid "Shared items" msgstr "Inga olästa poster." #: src/googlereader_urlreader.cpp:36 #, fuzzy msgid "Popular items" msgstr "Inga olästa poster." #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "Allmänna bindningar:" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "Lösgör funktioner:" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "Töm" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "inbäddat flash:" #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "bild" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "Länkar:" #: src/htmlrenderer.cpp:594 msgid "link" msgstr "länk" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "inbäddat flash" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "okänt (fel)" #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "Växlar läsflagg för artikel..." #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "Fel vid växling av läsflagg: %s" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "Url-lista tom." #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "Flaggor:" #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "Fel: ingen post markerad!" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "Fel: du kan inte läsa om sökresultat." #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "Inga olästa poster." #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "" #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "" #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "Inga olästa webbkanaler." #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "Överför artikel till kommando:" #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "Sortera utifrån (d)atum/(t)itel/(f)laggor/(f)örfattare/(l)änk/(g)uid?" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 msgid "dtfalg" msgstr "dtfalg" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "d" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "l" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "g" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" "Sortera omvänt utifrån (d)atum/(t)itel/(f)laggor/(f)örfattare/(l)änk/(g)uid?" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "Flaggor uppdaterade." #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "Markera alla som läst" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "Avbröt sparande." #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "Sparade artikel till %s" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "Fel: kunde inte spara artikel till %s" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "Sökresultat - '%s'" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "Webbkanalsförfrågan - %s" #: src/itemlist_formaction.cpp:1004 #, c-format msgid "Article List - %s" msgstr "Artikellista - %s" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "Överkant" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "Nederkant" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "Webbkanal:" #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "Hämtningsurl för podsändning:" #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "typ:" #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "Fel vid markering av artikel som läst: %s" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "Lägg till %s i hämtningskölista" #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "Sparade artikel till %s." #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "Fel: kunde inte skriva artikel till fil %s" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "Startar webbläsare..." #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "Fel vid markering av artikel som läst: %s" #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "Öppna i webbläsare" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "Kölägg" #: src/itemview_formaction.cpp:586 #, c-format msgid "Article - %s" msgstr "Artikel - %s" #: src/itemview_formaction.cpp:624 msgid "Error: invalid regular expression!" msgstr "Fel: ogiltigt reguljärt uttryck!" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "Öppna webbkanal/artikel" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "Återvänd till föregående dialogruta/Avsluta" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "Läs om aktuell markerad webbkanal" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "Läs om alla webbkanaler" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "Markera webbkanal som läst" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "Markera alla webbkanaler som lästa" #: src/keymap.cpp:30 msgid "Save article" msgstr "Spara artikel" #: src/keymap.cpp:31 #, fuzzy msgid "Go to next article" msgstr "Gå till nästa olästa artikel" #: src/keymap.cpp:32 #, fuzzy msgid "Go to previous article" msgstr "Gå till föregående olästa artikel" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "Gå till nästa olästa artikel" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "Gå till föregående olästa artikel" #: src/keymap.cpp:35 msgid "Go to a random unread article" msgstr "Gå till en " #: src/keymap.cpp:36 #, fuzzy msgid "Open article in browser and mark read" msgstr "Öppna artikel i webbläsare" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "Öppna artikel i webbläsare" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "Öppna hjälpdialogruta" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "Växla källvy" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "Växla lässtatus för artikel" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "Växla visa lästa webbkanaler/artiklar" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "Visa url:er i nuvarande artikel" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "Töm nuvarande tagg" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "Markera tagg" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "Öppna sökdialogrutan" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "Lägg till hämtning i kölista" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "Läs om url:ernas lista ifrån konfigurationen" #: src/keymap.cpp:50 msgid "Download file" msgstr "Hämta fil" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "Avbryt hämtning" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "Markera hämtning som borttagen" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "Rensa färdiga och borttagna hämtningar från kölista" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "Växla automatisk hämtning på/av" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "Starta spelaren med den aktuella markerade hämtningen" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "Öka antalet samtidiga hämtningar" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "Minska antalet samtidiga hämtningar" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "Rita om skärm" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "Öppna kommandoraden" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "Ställ in ett filter" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "Markera ett förinställt filter" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "Töm aktuellt inställt filter" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "Bokmarkera aktuell länk/artikel" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "Redigera flaggor" #: src/keymap.cpp:65 #, fuzzy msgid "Go to next feed" msgstr "Gå till nästa olästa webbkanal" #: src/keymap.cpp:66 #, fuzzy msgid "Go to previous feed" msgstr "Gå till föregående olästa webbkanal" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "Gå till nästa olästa webbkanal" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "Gå till föregående olästa webbkanal" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "Anropa en makrot" #: src/keymap.cpp:70 msgid "Delete article" msgstr "Ta bort artikel" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "Rensa borttagna artiklar" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "Redigera prenumererade url:er" #: src/keymap.cpp:73 msgid "Close currently selected dialog" msgstr "Stäng aktuell markerad dialogruta" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "Se lista över öppna dialogrutor" #: src/keymap.cpp:75 msgid "Go to next dialog" msgstr "Gå till nästa dialogruta" #: src/keymap.cpp:76 msgid "Go to previous dialog" msgstr "Gå till föregående dialogruta" #: src/keymap.cpp:77 msgid "Pipe article to command" msgstr "Överför artikel till kommando" #: src/keymap.cpp:78 msgid "Sort current list" msgstr "Sortera aktuell lista" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "Sortera aktuell lista (omvänt)" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "Öppna url 0" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "Öppna url 1" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "Öppna url 2" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "Öppna url 3" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "Öppna url 4" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "Öppna url 5" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "Öppna url 6" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "Öppna url 7" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "Öppna url 8" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "Öppna url 9" #: src/keymap.cpp:92 msgid "Move to the previous entry" msgstr "Flytta till föregående post" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "Flytta till nästa post" #: src/keymap.cpp:94 msgid "Move to the previous page" msgstr "Flytta till föregående sida" #: src/keymap.cpp:95 msgid "Move to the next page" msgstr "Flytta till nästa sida" #: src/keymap.cpp:97 #, fuzzy msgid "Move to the start of page/list" msgstr "Flytta till nästa sida" #: src/keymap.cpp:98 #, fuzzy msgid "Move to the end of page/list" msgstr "Flytta till nästa sida" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "`%s' är inte ett giltigt innehåll" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "`%s' är inte ett giltigt tangentkommando" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "Tömmer kölista..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "användning %s [-C ] [-q ] [-h]\n" "-C läs in konfiguration från \n" "-q använd som kölistefil\n" "-a starta hämtning vid uppstart\n" "-h denna hjälp\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr "- %u parallella hämtningar" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "Kölista (%u pågående hämtningar, %u totalt) - %.2f kb/s totalt%s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "Fel: kan inte avsluta: hämtning(ar) pågår." #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "Fel: hämtning måste färdigställas innan filen kan spelas upp." #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "Fel: kan inte utföra åtgärd: hämtning(ar) pågår." #: src/pb_view.cpp:276 msgid "Download" msgstr "Hämta" #: src/pb_view.cpp:278 msgid "Delete" msgstr "Ta bort" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "Rensa färdiga" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "Växla automatisk hämtning" #: src/pb_view.cpp:281 msgid "Play" msgstr "Spela upp" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "`%s' är en ogiltig typ av dialogruta" #: src/regexmanager.cpp:49 #, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "`%s' är inte ett giltigt reguljärt uttryck: %s" #: src/rss.cpp:466 #, fuzzy msgid "too few arguments" msgstr "för få parametrar." #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "Fel: url stöds inte: %s" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "Markera tagg" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "Markera filter" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "attribut hittades inte" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "EOF hittades vid inläsning av XML-tagg" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "Ingen länk markerad!" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "Spara bokmärke" #: src/urlview_formaction.cpp:146 msgid "URLs" msgstr "Url:er" #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "Fel: verkställande av filtret misslyckades: %s" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "Fel: kanal innehåller inga poster!" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "Uppdaterar webbkanalsförfrågan..." #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "XML root node är NULL" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "kunde inte initialisera libcurl" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "Fel: vid försök med att hämta webbkanal `%s' gav HTTP-statuskod %ld." #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "kunde inte tolka buffer" #: rss/parser.cpp:174 msgid "could not parse file" msgstr "kunde inte tolka fil" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "ingen RSS-version" #: rss/parser.cpp:211 msgid "invalid RSS version" msgstr "Ogiltig RSS-version!" #: rss/parser.cpp:226 rss/parser.cpp:233 msgid "invalid Atom version" msgstr "Ogiltig Atom-version!" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "ingen Atom-version" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "webbkanalsformat stöds inte" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "ingen RSS-kanal hittades" newsbeuter-2.7/po/tr.po000066400000000000000000001144001220711462700151520ustar00rootroot00000000000000# translation of tr.po to Türkçe # Copyright (C) 2008 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # H.Gökhan SARI , 2008. msgid "" msgstr "" "Project-Id-Version: tr\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2008-11-18 14:41+0200\n" "Last-Translator: H.Gökhan SARI \n" "Language-Team: Türkçe \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Language: tr_TR\n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "`%s' geçerli bir renk değil" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, c-format msgid "`%s' is not a valid attribute" msgstr "`%s' geçersiz bir özellik" #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "" "newsbeuter: yeniden yükleme tamamlandı, %f okunmamış besleme (%n okunmamış " "toplam yazı)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - Beslemeler (%u okunmamış, %t toplam)%?T? - tag `%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - '%T' yazı (%u okunmamış, %t toplam) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - Arama sonucu (%u okunmamış, %t toplam)" #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?Aç&Kaydet? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - Yardım" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - Etiket Seç" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - Filtre Seç" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - Yazı '%T'" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - Adres" #: src/configcontainer.cpp:111 msgid "%N %V - Dialogs" msgstr "%N %V - Diyalog" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "" #: src/configcontainer.cpp:159 #, fuzzy, c-format msgid "invalid configuration value `%s'" msgstr "Ayarlar %s 'e kaydedildi" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "`%s' komutu çalıştırılırken hata (%s %u. satır): %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "bilinmeyen komut `%s'" #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "Ölümcül hata: ev dizini tanımlanamadı!" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "" "Ev dizini değişkenini ayarlayın ya da %u UID'i için geçerli bir kullanıcı " "ekleyin!" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: bilinmeyen seçenek - %c" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "%s %s başlatılıyor..." #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "Hata: %s zaten çalışıyor (PID: %u)" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "Ayarlar yükleniyor..." #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "tamamlandı." #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "Önbellek açılıyor..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "Hata: `%s' önbellek dosyası açılamadı: %s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "Yerel önbellekten adresler yükleniyor..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "%s kaynağından adresler yükleniyor..." #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "" "Hata: hiçbir adres ayarlanmamış. Lütfen %s içine RSS besleme kaynakları " "ekleyin ya da bir OPML dosyasını içeri aktarın." #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "" "Belirttiğiniz OPML dosyası herhangi bir kaynak içermiyor. Lütfen besleme " "kaynaklarını doğru biçimde bu dosyaya ekleyin ve tekrar deneyin." #: src/controller.cpp:392 #, fuzzy msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" "Bloglines hesabınızda herhangi bir besleme ayarlamamışsınız. Lütfen gerekli " "ayarlamayı yaptıktan sonra tekrar deneyin." #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "Yazılar önbellekten yükleniyor..." #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "Önbellek boşaltılıyor..." #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "Veritabanından beslemeler alınırken hata oluştu: " #: src/controller.cpp:430 #, fuzzy, c-format msgid "Error while loading feed '%s': %s" msgstr "`%s' aranırken hata: %s" #: src/controller.cpp:448 msgid "Prepopulating query feeds..." msgstr "Sorgu beslemesi güncelleniyor..." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "Okunmuş yazıların listesi içe aktarılıyor..." #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "Okunmuş yazıların listesi dışa aktarılıyor..." #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "Önbellek temizleniyor..." #: src/controller.cpp:523 msgid "failed: " msgstr "başarız: " #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "Hata: tüm beslemeler okundu olarak işaretlenemedi: %s" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%sYükleniyor %s..." #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "%s alınırken hata oluştu: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "Hata: geçersiz besleme!" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "geçersiz besleme indeksi (bug)" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "" #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "" #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" "%s %s\n" "kullanım: %s [-i |-e] [-u ] [-c <önbellek_dosyası>] [-x " " ...] [-h]\n" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "beslemeleri OPML olarak çıktıla" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "beslemeleri başlangıçta yenile" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 msgid "" msgstr "" #: src/controller.cpp:842 msgid "import OPML file" msgstr "OPML dosyasını içe aktar" #: src/controller.cpp:843 msgid "" msgstr "" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "RSS beslemeleri adreslerini ndan oku" #: src/controller.cpp:844 msgid "" msgstr "<önbellek_dosyası>" #: src/controller.cpp:844 msgid "use as cache file" msgstr "<önbellek_dosyası>nı önbellek dosyası olarak kullan" #: src/controller.cpp:845 msgid "" msgstr "" #: src/controller.cpp:845 msgid "read configuration from " msgstr "ayarları ndan oku" #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "önbelleği bütünüyle temizle" #: src/controller.cpp:847 msgid "..." msgstr "..." #: src/controller.cpp:847 msgid "execute list of commands" msgstr "bir dizi komut çalıştır" #: src/controller.cpp:848 #, fuzzy msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "" "çevrimdışı modunu aktifleştir (sadece bloglines eşleştirme modunu etkiler)" #: src/controller.cpp:849 msgid "quiet startup" msgstr "" #: src/controller.cpp:850 msgid "get version information" msgstr "sürüm bilgisini al" #: src/controller.cpp:851 msgid "" msgstr "" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "kayıt tutarken seviye belirle (geçerli seviyeler: 1 - 6)" #: src/controller.cpp:852 msgid "" msgstr "" #: src/controller.cpp:852 msgid "use as output log file" msgstr "nı çıktı kaydı için kullan" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "okunmuş yazıların listesini ya aktar" #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "okunmuş yazıları dan aktar" #: src/controller.cpp:855 msgid "this help" msgstr "bu yardım" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "" #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "%s'in içeri aktarımı tamamlandı." #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "" "yer imleme desteği ayarlanmadı. Ayar değişkenini `bookmark-cmd'ye göre " "ayarlayın." #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u okunmamış yazı" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "Başlık: " #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "Yazar: " #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "Tarih: " #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "Bağlantı: " #: src/controller.cpp:1388 #, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "Hata: ayar dosyası `%s' kaydedilemedi!" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "Hiçbiri seçilmedi!" #: src/dialogs_formaction.cpp:74 msgid "Error: you can't remove the feed list!" msgstr "Hata: besleme listesini silemezsiniz!" #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "Geçersiz konum!" #: src/download.cpp:42 msgid "queued" msgstr "kuyruğa eklendi" #: src/download.cpp:44 msgid "downloading" msgstr "indiriliyor" #: src/download.cpp:46 msgid "cancelled" msgstr "iptal edildi" #: src/download.cpp:48 msgid "deleted" msgstr "silindi" #: src/download.cpp:50 msgid "finished" msgstr "tamamlandı" #: src/download.cpp:52 msgid "failed" msgstr "tamamlanamadı" #: src/download.cpp:54 msgid "incomplete" msgstr "eksik" #: src/download.cpp:56 msgid "played" msgstr "oynatıldı" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "bilinmiyor (bug) " #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "`%s' özelliği mevcut değil." #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "Geçersiz parametre." #: src/exception.cpp:43 msgid "too few parameters." msgstr "yetersiz parametre" #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "bilinmeyen komut (bug)." #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "dosya açılamadı." #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "bilinmeyen hata (bug)." #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "Hiçbir besleme seçilmedi!" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "h" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "Besleme okundu olarak işaretleniyor..." #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "Hata: besleme okundu olarak işaretlenemedi: %s" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "Okunmamış besleme yok." #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "" #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "" #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "Tüm beslemeler okundu olarak işaretleniyor..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "Hiçbir etiket tanımlanmadı." #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "Hata: filtre komutu `%s' ayrıştırılamadı: %s" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "Hiçbir filtre tanımlanmadı." #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "Ara: " #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "Filtre: " #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "Çıkmak istediğinize emin misiniz (e:Evet h:Hayır)? " #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "eh" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "e" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "Çık" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "Aç" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "Sonraki Okunmamış" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "Yeniden Yükle" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "Tümünü Yeniden Yükle" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "Okundu olarak işaretle" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "Tümünü Eşitle" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "Ara" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "Yardım" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "Hata: filtre komutu ayrıştırılamadı!" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "Aranıyor..." #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "`%s' aranırken hata: %s" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "Sonuç yok." #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "Konum görünür değil!" #: src/feedlist_formaction.cpp:774 #, c-format msgid "Feed List - %u unread, %u total" msgstr "Besleme Listesi %u okunmamuş, %u toplam" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "`%s'in üzerine yazmak istediğinize emin misiniz (e:Evet h:Hayır)? " #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "Dosya: " #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - Dosya Aç - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - Dosya Kaydet - %s" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "İptal" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "Kaydet" #: src/filebrowser_formaction.cpp:271 #, c-format msgid "Open File - %s" msgstr "Dosya aç - %s" #: src/filebrowser_formaction.cpp:273 #, c-format msgid "Save File - %s" msgstr "Kaydet - %s" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "filtre ifadesi `%s' ayrıştırılamadı: %s" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "kullanım: set [=]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "kullanım: dumpconfig " #: src/formaction.cpp:231 #, c-format msgid "Saved configuration to %s" msgstr "Ayarlar %s 'e kaydedildi" #: src/formaction.cpp:236 #, c-format msgid "Not a command: %s" msgstr "bilinmeyen komut: %s" #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "Yerimi kaydediliyor..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "Yerimi kaydedildi." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "Yerimi kaydedilirken hata oluştu: " #: src/formaction.cpp:303 msgid "URL: " msgstr "Adres: " #: src/formaction.cpp:305 msgid "Description: " msgstr "Açıklama: " #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "" #: src/googlereader_urlreader.cpp:34 #, fuzzy msgid "Starred items" msgstr "Okunmamış yok." #: src/googlereader_urlreader.cpp:35 #, fuzzy msgid "Shared items" msgstr "Okunmamış yok." #: src/googlereader_urlreader.cpp:36 #, fuzzy msgid "Popular items" msgstr "Okunmamış yok." #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "Temizle" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "gömülmüş flash:" #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "resim" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "Bağlantılar: " #: src/htmlrenderer.cpp:594 msgid "link" msgstr "bağlantı" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "gömülmüş flash" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "bilinmiyor (bug)" #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "Bayrak okuma açılıyor/kapatılıyor..." #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "Hata: %s" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "Adres listesi boş." #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "Bayraklar: " #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "Hata: hiçbiri seçilmedi!" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "Hata: arama sonuçlarını yeniden yükleyemezsiniz." #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "Okunmamış yok." #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "" #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "" #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "Okunmamış besleme yok." #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "" #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 msgid "dtfalg" msgstr "dtfalg" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "Bayraklar güncellendi." #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "Tümünü Okundu Olarak İşaretle" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "Kayıt işlemi iptal edildi." #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "Yazı %s'e kaydedildi" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "Hata: yazı %s'e kaydedilemedi" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "" #: src/itemlist_formaction.cpp:1004 #, c-format msgid "Article List - %s" msgstr "Yazı Listesi - %s" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "Yukarı" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "Aşağı" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "Besleme: " #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "Podcast İndirme Adresi: " #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "biçim: " #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "Yazı okundu olarak işaretlenirken hata oluştu: %s" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "%s indirme kuyruğuna eklendi." #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "Yazı %s'e kaydedildi." #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "Hata: yazı %s'e kaydedilemedi" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "Tarayıcı başlatılıyor..." #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "Yazı yeni olarak işaretlenirken hata oluştu: %s" #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "Tarayıcıda Görüntüle" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "Kuyruktan Çıkar" #: src/itemview_formaction.cpp:586 #, c-format msgid "Article - %s" msgstr "Yazı - %s" #: src/itemview_formaction.cpp:624 msgid "Error: invalid regular expression!" msgstr "Hata: geçersiz düzenli ifade!" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "Beslemeyi/Yazıyı aç" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "Önceki diyaloğa dön/Çık" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "Seçilen beslemeyi yeniden yükle" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "Tüm beslemeleri yeniden yükle" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "Beslemeyi okundu olarak işaretle" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "Tüm beslemeleri okundu olarak işaretle" #: src/keymap.cpp:30 msgid "Save article" msgstr "Yazıyı kaydet" #: src/keymap.cpp:31 #, fuzzy msgid "Go to next article" msgstr "Sonraki okunmamış yazıya git" #: src/keymap.cpp:32 #, fuzzy msgid "Go to previous article" msgstr "Önceki okunmamış yazıya git" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "Sonraki okunmamış yazıya git" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "Önceki okunmamış yazıya git" #: src/keymap.cpp:35 msgid "Go to a random unread article" msgstr "Rastgele okunmamış bir yazıya git" #: src/keymap.cpp:36 #, fuzzy msgid "Open article in browser and mark read" msgstr "Yazıyı tarayıcıda aç" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "Yazıyı tarayıcıda aç" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "Yardım diyaloğunu aç" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "Kaynak gösterimini aç/kapat" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "Durum okuma özelliğini aç/kapat" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "Yazı okumayı aç/kapat" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "Adresleri mevcut yazı içinde göster" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "Mevcut etiketi temizle" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "Etiket seç" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "Arama diyaloğunu aç" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "İndirmeyi kuyruğa ekle" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "Ayar dosyasında adreslerin listesini yeniden yükle" #: src/keymap.cpp:50 msgid "Download file" msgstr "Dosyayı indir" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "İndirmeyi iptal et" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "İndirmeyi silindi olarak işaretle" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "Tamamlanan ve silinen indirmeleri kuyruktan temizle" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "Otomatik indirmeyi aç/kapat" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "Oynatıcı seçilen indirme ile başlat" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "Eşzamanlı indirmelerin sayısını artır" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "Eşzamanlı indirmelerin sayısını azalt" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "Ekranı yeniden çiz" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "Komut satırını aç" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "Filtre ayarla" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "Önceden tanımlanmış bir filtre seç" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "Mevcut filtreyi temizle" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "Mevcut yazıyı yerimlerine ekle" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "Bayrakları düzenle" #: src/keymap.cpp:65 #, fuzzy msgid "Go to next feed" msgstr "Sonraki okunmamış beslemeye git" #: src/keymap.cpp:66 #, fuzzy msgid "Go to previous feed" msgstr "Önceki okunmamış beslemeye git" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "Sonraki okunmamış beslemeye git" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "Önceki okunmamış beslemeye git" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "Makro çağır" #: src/keymap.cpp:70 msgid "Delete article" msgstr "Yazıyı sil" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "Silinen yazıları temizle" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "Abone olunan adresleri düzenle" #: src/keymap.cpp:73 msgid "Close currently selected dialog" msgstr "Seçilen diyalogu kapat" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "" #: src/keymap.cpp:75 msgid "Go to next dialog" msgstr "Sonraki diyaloga git" #: src/keymap.cpp:76 msgid "Go to previous dialog" msgstr "Önceki diyaloğa dön/Çık" #: src/keymap.cpp:77 msgid "Pipe article to command" msgstr "" #: src/keymap.cpp:78 msgid "Sort current list" msgstr "Mevcut listeyi sırala" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "Mevcut listeyi sırala (tersten)" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "URL 10'u aç" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "URL 1'i aç" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "URL 2'yi aç" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "URL 3'ü aç" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "URL 4'ü aç" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "URL 5'i aç" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "URL 6'yı aç" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "URL 7'yi aç" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "URL 8'i aç" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "URL 9'u aç" #: src/keymap.cpp:92 msgid "Move to the previous entry" msgstr "Önceki girdiye taşı" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "" #: src/keymap.cpp:94 msgid "Move to the previous page" msgstr "Önceki sayfaya taşı" #: src/keymap.cpp:95 msgid "Move to the next page" msgstr "Sonraki sayfaya taşı" #: src/keymap.cpp:97 #, fuzzy msgid "Move to the start of page/list" msgstr "Sonraki sayfaya taşı" #: src/keymap.cpp:98 #, fuzzy msgid "Move to the end of page/list" msgstr "Sonraki sayfaya taşı" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "Kuyruk temizleniyor..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "kullanım %s [-C ] [-q ] [-h]\n" "-C ayarları 'ndan oku\n" "-q nı kuyruk olarak kullan\n" "-a başlangıçta indirmeyi başlat\n" "-h bu yardım metnini göster\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr " - %u paralel indirme" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "Kuyruk (%u indirme sürüyor, %u toplam) - %.2f kb/s toplam%s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "Hata: çıkılamadı: devam eden indirme(ler) var." #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "" "Hata: dosya oynatılmadan önce indirme işleminin tamamlanması gerekiyor." #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "Hata: işlem gerçekleştirilemedi: devam eden indirme(ler) var." #: src/pb_view.cpp:276 msgid "Download" msgstr "İndir" #: src/pb_view.cpp:278 msgid "Delete" msgstr "Sil" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "Tamamlananları Temizle" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "Otomatik İndirmeyi Aç/Kapat" #: src/pb_view.cpp:281 msgid "Play" msgstr "Oynat" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "" #: src/regexmanager.cpp:49 #, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "`%s' geçerli bir düzenli ifade değil: %s" #: src/rss.cpp:466 #, fuzzy msgid "too few arguments" msgstr "yetersiz parametre" #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "Hata: desteklenmeyen adres: %s" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "Etiket Seç" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "Filtre Seç" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "özellik bulunamadı" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "XML etiketi okunurken EOF (dosya sonu) bulundu" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "Hiçbir bağlantı seçilmedi!" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "Yerimlerine Ekle" #: src/urlview_formaction.cpp:146 msgid "URLs" msgstr "Adresler" #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "Hata: filtre uygulanırken hata oluştu: %s" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "Hata: besleme boş!" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "Sorgu beslemesi güncelleniyor..." #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "" #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "" #: rss/parser.cpp:174 msgid "could not parse file" msgstr "dosya ayrıştırılamadı" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "" #: rss/parser.cpp:211 msgid "invalid RSS version" msgstr "geçersiz RSS sürümü" #: rss/parser.cpp:226 rss/parser.cpp:233 msgid "invalid Atom version" msgstr "geçersiz Atom sürümü" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "" #~ msgid "" #~ "%s %s\n" #~ "usage: %s [-i |-e] [-u ] [-c ] [-x " #~ " ...] [-h]\n" #~ "-e export OPML feed to stdout\n" #~ "-r refresh feeds on start\n" #~ "-i import OPML file\n" #~ "-u read RSS feed URLs from \n" #~ "-c use as cache file\n" #~ "-C read configuration from \n" #~ "-v clean up cache thoroughly\n" #~ "-x ... execute list of commands\n" #~ "-o activate offline mode (only applies to bloglines " #~ "synchronization mode)\n" #~ "-V get version information\n" #~ "-l write a log with a certain loglevel (valid values: 1 to " #~ "6)\n" #~ "-d use as output log file\n" #~ "-E export list of read articles to \n" #~ "-I import list of read articles from \n" #~ "-h this help\n" #~ msgstr "" #~ "%s %s\n" #~ "usage: %s [-i |-e] [-u ] [-c <önbellekdosyası>] [-x " #~ " ...] [-h]\n" #~ "-e OPML dosya içeriğini görüntüle\n" #~ "-r açılışta beslemeleri yenile\n" #~ "-i bir OPML dosyasını içe aktar\n" #~ "-u 'ndan besleme adreslerini oku\n" #~ "-c <önbellekdosyası> <önbellekdosyası>'nı önbellek dosyası olarak " #~ "kullan\n" #~ "-C 'ndan ayarları oku\n" #~ "-v önbelleği boşalt\n" #~ "-x ... komutların listesi çalıştır\n" #~ "-o çevrimdışı moda geç\n" #~ "-V version bilgisini göster\n" #~ "-h bu yardım metnini göster\n" newsbeuter-2.7/po/uk.po000066400000000000000000001303301220711462700151440ustar00rootroot00000000000000# Ukrainian translation for newsbeuter. # Copyright (C) 2010 # This file is distributed under the same license as the newsbeuter package. # Ivan Kovnatsky , 2010. # msgid "" msgstr "" "Project-Id-Version: newsbeuter 0.9\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2008-08-02 15:32+0400\n" "Last-Translator: Ivan Kovnatsky \n" "Language-Team: Uk \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "`%s' недійсний колір" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, c-format msgid "`%s' is not a valid attribute" msgstr "атрибут `%s' не доступний." #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "`%s' недійсний елемент конфігурації" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "" "newsbeuter: завантаження завершено, %f непрочитаних тем (%n всього " "непрочитаних статей)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - Ваші новини (%u непрочитано, всього %t)%?T? - мітка `%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - '%T' Статей у темі (%u непрочитано, всього %t) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - Результат пошуку (%u непрочитано, всього %t)" #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?Відкрити Файл&Зберегти Файл? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - Довідка" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - Вибрати Мітку" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - Вибрати Фільтер" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - Стаття '%T'" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - URLs" #: src/configcontainer.cpp:111 msgid "%N %V - Dialogs" msgstr "%N %V - Діалоги" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "потрібно вказати boolean тип, натомість `%s'" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "потрібно вказати integer тип, натомість `%s'" #: src/configcontainer.cpp:159 #, c-format msgid "invalid configuration value `%s'" msgstr "невірне значення налаштунку %s" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "Помилка при виконанні команди `%s' (%s рядок %u): %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "невідома команда `%s'" #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "Критична помилка: неможливо визначити домашню директорію!" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "" "Будь-ласка налашуйте змінну HOME, або додайте користувача, що відповідає UID " "%u!" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: невідомий параметр - %c" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "Запускаю %s %s..." #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "Помилка: вже працює копія %s (PID: %u)" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "Завантаження налаштувань..." #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "готово." #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "Відкриваю кеш..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "Помилка: при відкритті файлу кеша `%s' виникла %s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "Завантажую URLs з локального кешу..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "Завантажую URLs з %s..." #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "" "Помилка: не вказано URLs. Будь-ласка, додайте RSS URLs у файл %s " "чиімпортуйте файл OPML." #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "" "Схоже на те, що OPML тема, на яку ви підписалися не містить тем. Будь-ласка, " "заповніть її темами, та спробуйте знову." #: src/controller.cpp:392 msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" "Схоже не те, що ви не налаштували ні одної теми у аккаунті Google Reader." "Будь-ласка зробіть це, і спробуйте знову." #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "Завантаження статей з кешу..." #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "Ретельне очищення кешу..." #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "Помилка при завантаженні тем з бази даних:" #: src/controller.cpp:430 #, c-format msgid "Error while loading feed '%s': %s" msgstr "Помилка при завантаженні теми `%s': %s" #: src/controller.cpp:448 msgid "Prepopulating query feeds..." msgstr "Поновлюю дані теми..." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "Імпортую список прочитаних статей..." #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "Зберігаю список прочитаних статей..." #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "Очищення кешу..." #: src/controller.cpp:523 msgid "failed: " msgstr "невдало: " #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "Помилка: не можу позначити всі теми як прочитані: %s " #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%sЗавантаження %s..." #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "Помилка при стягненні %s: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "Помилка: непрацездатна тема!" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "непрацездатний індекс теми (помилка)" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "" "newsbeuter - це вільне програмне забезпечення, що ліцензоване під MIT/X " "Consortium License." #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "Тип `%s -vv' для додаткової інформації." #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" "%s %s\n" "використання: %s [-i <файл>|-e] [-u <файлпосилання>] [-c <файлкешу>] [-x " "<команда> ...] [-h]\n" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "експорт теми OPML до стандартного виводу" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "оновити теми при старті" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 msgid "" msgstr "<файл>" #: src/controller.cpp:842 msgid "import OPML file" msgstr "імпортувати файл OPML" #: src/controller.cpp:843 msgid "" msgstr "<файлпосилання>" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "читати посилання на RSS теми з <файлпосилання>" #: src/controller.cpp:844 msgid "" msgstr "<файлкешу>" #: src/controller.cpp:844 msgid "use as cache file" msgstr "використайте <файлкешу> як файл кешу" #: src/controller.cpp:845 msgid "" msgstr "<файлналаштування>" #: src/controller.cpp:845 msgid "read configuration from " msgstr "читати налаштування з <файлналаштування>" #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "ретельно очищистити кеш" #: src/controller.cpp:847 msgid "..." msgstr "<команда>..." #: src/controller.cpp:847 msgid "execute list of commands" msgstr "виконати список команд" #: src/controller.cpp:848 #, fuzzy msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "" "актувувати режим поза мережею (застосовує тільки синхронізацію з блоґом)" #: src/controller.cpp:849 msgid "quiet startup" msgstr "" #: src/controller.cpp:850 msgid "get version information" msgstr "отримати інформацію про версію" #: src/controller.cpp:851 msgid "" msgstr "<рівеньлогу>" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "записувати лог з визначеним рівнем (дійсні значення: від 1 до 6)" #: src/controller.cpp:852 msgid "" msgstr "<файллогу>" #: src/controller.cpp:852 msgid "use as output log file" msgstr "використовуйте <файллогу> як вихідний файл логу" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "експортувати список прочитаних статей у <файл>" #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "імпортувати список прочитаних статей з <файл>" #: src/controller.cpp:855 msgid "this help" msgstr "ця довідка" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "Виникла помилка при парсуванні %s" #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "Імпорт %s завершено." #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "" "підтримка закладок не налаштована. Будь-ласка встановіть змінну `bookmark-" "cmd' відповідно." #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u непрочитаних статей" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "Назва: " #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "Автор: " #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "Дата: " #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "Посилання: " #: src/controller.cpp:1388 #, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "Помилка: не можу відкрити файл конфігурації `%s'!" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "Закрити" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "Йти до Діалогу" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "Закрити Діалог" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "Не вибрано нічого!" #: src/dialogs_formaction.cpp:74 msgid "Error: you can't remove the feed list!" msgstr "Помилка: ви не можете видаляти список тем" #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "Непрацездатна позиція!" #: src/download.cpp:42 msgid "queued" msgstr "у черзі" #: src/download.cpp:44 msgid "downloading" msgstr "завантажую" #: src/download.cpp:46 msgid "cancelled" msgstr "відмінено" #: src/download.cpp:48 msgid "deleted" msgstr "видалено" #: src/download.cpp:50 msgid "finished" msgstr "закінчено" #: src/download.cpp:52 msgid "failed" msgstr "невдало" #: src/download.cpp:54 msgid "incomplete" msgstr "незавершено" #: src/download.cpp:56 msgid "played" msgstr "програно" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "невідомо (помилка)." #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "атрибут `%s' не доступний." #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "вживаний вираз '%s' неправильний %s" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "Параметри невірні." #: src/exception.cpp:43 msgid "too few parameters." msgstr "замало параметрів" #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "невідома команда (помилка)." #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "файл неможливо відкрити." #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "невідома помилка (помилка)." #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "Не вибрано тем!" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "" "Сортувати за (f)першимТаґом/(t)назвою/(a)кількістьСтатей/(u)" "кількістьНепрочитанихСтатей/(n)ніяк?" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "ftaun" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "f" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "t" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "a" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "u" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "n" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "" "Сортувати реверсно за (f)першимТаґом/(t)назвою/(a)кількістьСтатей/(u)" "кількістьНепрочитанихСтатей/(n)ніяк?" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "Позначаю теми як прочитані..." #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "Помилка: не можу позначити тему: %s як прочитану" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "Немає тем з непрочитаними статтями." #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "" #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "" #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "Позначаю всі теми як прочитані..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "Не визначено жодної мітки." #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "Помилка: неможливо парсувати команду фільтра `%s': %s" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "Не визначено фільтри." #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "Шукати: " #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "Фільтр: " #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "Ви впевнені, що хочете вийти (y:Так n:Ні)?" #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "yn" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "y" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "Вихід" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "Відкрити" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "Наступна непрочитана" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "Перезавантажити" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "Перезавантажити усі" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "Позначити як прочитано" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "Підхватити усі" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "Пошук" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "Довідка" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "Помилка: неможливо розібрати помилку фільтра!" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "Шукаю..." #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "Помилка при пошуку `%s': %s" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "Безрезультатно." #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "Не видно позицію!" #: src/feedlist_formaction.cpp:774 #, c-format msgid "Feed List - %u unread, %u total" msgstr "Список Тем - %u непрочитано, загалом - %u" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "Ви впевнені, що хочете перезаписати `%s' (y:Так n:Ні)?" #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "Файл: " #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - Відкрити файл - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - Зберегти файл - %s" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "Відміна" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "Зберегти" #: src/filebrowser_formaction.cpp:271 #, c-format msgid "Open File - %s" msgstr "Відкрити Файл - %s" #: src/filebrowser_formaction.cpp:273 #, c-format msgid "Save File - %s" msgstr "Зберегти Файл - %s" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "неможливо парсувати вираз фільра `%s': %s" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "використання: set <змінна>[=<значення>]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "використання: <файл> [...]" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "використання: конфігурація дампу <файл>" #: src/formaction.cpp:231 #, c-format msgid "Saved configuration to %s" msgstr "Конфігурацію збережено у %s" #: src/formaction.cpp:236 #, c-format msgid "Not a command: %s" msgstr "Не є командою: `%s'" #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "Зберігаю закладки..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "Збережені закладки." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "Помилка при зберіганні закладок: " #: src/formaction.cpp:303 msgid "URL: " msgstr "URL: " #: src/formaction.cpp:305 msgid "Description: " msgstr "Опис: " #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "" #: src/googlereader_urlreader.cpp:34 msgid "Starred items" msgstr "Відмічені статті." #: src/googlereader_urlreader.cpp:35 msgid "Shared items" msgstr "Загальні статті." #: src/googlereader_urlreader.cpp:36 msgid "Popular items" msgstr "Популярні статті." #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "Загальні клавіші" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "Незастосовані функції" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "Очистити" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "вбудований флеш:" #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "зображення" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "Посилання: " #: src/htmlrenderer.cpp:594 msgid "link" msgstr "посилання" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "вбудований флеш" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "невідомо (помилка)" #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "Переключення флагу прочитано для статей..." #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "Помилка при переключенні флагу прочитано: %s" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "Список URL пустий." #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "Флаги: " #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "Помилка: нічого не вибрано!" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "Помилка: ви не можете перезавантажувати результати пошуку" #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "Немає непрочитаних статей." #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "" #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "" #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "Немає непрочитаних тем." #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "Пайпувати статтю до каманди: " #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" "Сортувати за (d)датою/(t)назвою/(f)флагами/(a)автором/(l)посиланням/(g)uid?" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 msgid "dtfalg" msgstr "dtfalg" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "d" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "l" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "g" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" "Сортувати реверсно за (d)датою/(t)назвою/(f)флагами/(a)автором/(l)посиланням/" "(g)uid?" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "Флаги поновлено." #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "Позначити всі як прочитані" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "Збереження перервано." #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "Стаття збережена у %s" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "Помилка: не можу зберегти у %s" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "Результати Пошуку - '%s'" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "Теми у черці - %s" #: src/itemlist_formaction.cpp:1004 #, c-format msgid "Article List - %s" msgstr "Список Статей - %s" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "Вершина" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "Низ" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "Тема: " #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "Посилання на завантаження Podcast: " #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "тип: " #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "Помилка при позначенні статті як прочитано: %s" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "Додано %s до черги завантаження." #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "Збережено статтю у %s." #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "Помилка: не можу записати статтю у файл %s" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "Запускаю браузер..." #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "Помилка при позначенні статті як непрочитано: %s" #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "Відкрити у браузері" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "Поставити у чергу" #: src/itemview_formaction.cpp:586 #, c-format msgid "Article - %s" msgstr "Стаття - %s" #: src/itemview_formaction.cpp:624 msgid "Error: invalid regular expression!" msgstr "Помилка: неправильний вираз!" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "Відкрити тему/статтю" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "Повернутись до попереднього діалогу/Вийти" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "Перезавантажити вибрану тему" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "Перезавантажити усі теми" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "Позначити теми як прочитані" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "Позначити усі теми як прочитані" #: src/keymap.cpp:30 msgid "Save article" msgstr "Зберегти статтю" #: src/keymap.cpp:31 #, fuzzy msgid "Go to next article" msgstr "Йти до наступної непрочитаної статті" #: src/keymap.cpp:32 #, fuzzy msgid "Go to previous article" msgstr "Йти до попередньої непрочитаної статті" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "Йти до наступної непрочитаної статті" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "Йти до попередньої непрочитаної статті" #: src/keymap.cpp:35 msgid "Go to a random unread article" msgstr "Йти до будь-якої непрочитаної статті" #: src/keymap.cpp:36 #, fuzzy msgid "Open article in browser and mark read" msgstr "Відкрити статтю у браузері" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "Відкрити статтю у браузері" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "Відкрити діалог довідки" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "Переключитись на перегляд сирців" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "Переключити статус прочитано для статті" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "Переключити перегляд прочитаних тем/статей" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "Показати URLs в поточній статті" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "Очистити поточну мітку" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "Вибрати мітку" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "Відкрити діалог пошуку" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "Додати завантаження у чергу" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "Перезавантажити список URLs з налаштувань" #: src/keymap.cpp:50 msgid "Download file" msgstr "Завантажити файл" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "Відмінити завантаження" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "Позначити завантаження як видалено" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "Очистити закінчені та видалені завантаження з черги" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "Переключити автоматичне завантаження Ув/В" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "Запустити програвач з вибраним завантаженням" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "Збільшити число одночасних завантажень" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "Зменшити число одночасних завантажень" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "Поновити екран" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "Відкрити командний рядок" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "Встановити фільтр" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "Вибрати попередньо визначений фільтр" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "Очистити поточно встановлений фільтр" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "Додати закладку на посилання/статтю" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "Редагувати флаги" #: src/keymap.cpp:65 #, fuzzy msgid "Go to next feed" msgstr "Йти до наступної непрочитаної теми" #: src/keymap.cpp:66 #, fuzzy msgid "Go to previous feed" msgstr "Йти до попередньої непрочитаної теми" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "Йти до наступної непрочитаної теми" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "Йти до попередньої непрочитаної теми" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "Викликати макрос" #: src/keymap.cpp:70 msgid "Delete article" msgstr "Видалити статтю" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "Очистити видалені статті" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "Редагувати підписані URLs" #: src/keymap.cpp:73 msgid "Close currently selected dialog" msgstr "Закрити вибране меню" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "Дивитись список відкритих меню" #: src/keymap.cpp:75 msgid "Go to next dialog" msgstr "Йти до наступного меню" #: src/keymap.cpp:76 msgid "Go to previous dialog" msgstr "Повернутись до попереднього меню" #: src/keymap.cpp:77 msgid "Pipe article to command" msgstr "Пайпувати статтю до каманди" #: src/keymap.cpp:78 msgid "Sort current list" msgstr "Сортувати поточний список" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "Сортувати поточний список (реверсно)" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "Відкрити URL 10" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "Відкрити URL 1" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "Відкрити URL 2" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "Відкрити URL 3" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "Відкрити URL 4" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "Відкрити URL 5" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "Відкрити URL 6" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "Відкрити URL 7" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "Відкрити URL 8" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "Відкрити URL 9" #: src/keymap.cpp:92 msgid "Move to the previous entry" msgstr "Йти до попереднього рядка" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "Перемістити до наступного рядка" #: src/keymap.cpp:94 msgid "Move to the previous page" msgstr "Перемістити до попередньої сторінки" #: src/keymap.cpp:95 msgid "Move to the next page" msgstr "Перемістити до наступної сторінки" #: src/keymap.cpp:97 msgid "Move to the start of page/list" msgstr "Перемістити до початку сторінки/списку" #: src/keymap.cpp:98 msgid "Move to the end of page/list" msgstr "Перемістити до кінця сторінки/списку" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "`%s' недійсний контекст" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "`%s' недійсна ключова команда" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "Очищую чергу..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "використання %s [-C <файл>] [-q <файл>] [-h]\n" "-C <файлналаштувань> читити файл конфігурацію з <файлналаштувань>\n" "-q <файлчерги> використати <файлчерги> як файл черги\n" "-a починати завантаження при старті\n" "-h ця довідка\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr " - %u паралельних завантажень" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "Черга (%u активних завантажень, всього %u) - %.2f kb/s всього%s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "Помилка: неможливо вийти: активне(і) завантаження" #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "" "Помилка: для того, щоб програти файл, завантаження повинні бути завершені." #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "Помилка: неможливо виконати операцію: активне(і) завантаження." #: src/pb_view.cpp:276 msgid "Download" msgstr "Завантаження" #: src/pb_view.cpp:278 msgid "Delete" msgstr "Видалити" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "Очищення закінчено" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "Увімкнути автоматичне завантаження" #: src/pb_view.cpp:281 msgid "Play" msgstr "Програти" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "`%s' недійсний тип діалогу" #: src/regexmanager.cpp:49 #, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "`%s' неправильний вираз" #: src/rss.cpp:466 msgid "too few arguments" msgstr "замало параметрів" #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "Помилка: посилання не підтримується: %s" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "Виберіть мітку" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "Виберіть фільтр" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "атрибут не знайдено" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "При читанні мітки з XML був виявлений кінець файлу" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "Не вибрано посилання!" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "Зберегти закладку" #: src/urlview_formaction.cpp:146 msgid "URLs" msgstr "URLs: " #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "Помилка: примінення фільтру невдале: %s" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "Помилка: теми не містять елементів!" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "Поновлюю дану тему..." #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "XML root node is NULL" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "не можу ініціялізувати libcurl" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "" "Помилка: намагаюсь завантажити тему `%s' оновленого статус коду HTTP %ld" #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "не можу парсувати буфер" #: rss/parser.cpp:174 msgid "could not parse file" msgstr "не можу парсувати файл" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "нема версії RSS" #: rss/parser.cpp:211 msgid "invalid RSS version" msgstr "недійсна версія RSS" #: rss/parser.cpp:226 rss/parser.cpp:233 msgid "invalid Atom version" msgstr "недійсна версія Atom" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "нема версії Atom" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "формат теми не підтримується" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "не знайдено каналу RSS" newsbeuter-2.7/po/zh.po000066400000000000000000001136111220711462700151510ustar00rootroot00000000000000# Chinese translation for newsbeuter # Copyright (C) 2007 # This file is distributed under the same license as the newsbeuter package # joshyu , 2007. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: newsbeuter 0.7\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2007-11-21 22:51+0100\n" "Last-Translator: josh yu \n" "Language-Team: Chinese \n" "Language: zh\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, fuzzy, c-format msgid "`%s' is not a valid attribute" msgstr "无效的属性索引" #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "newsbeuter:重新加载完毕, %f个种子含未读文章(共有 %n 篇未读文章)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - 你的种子 (%u 篇未读, 共有 %t 篇)%?T? - 标签 `%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - 种子 '%T' 里的文章(%u 未读, 共有 %t 篇) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - 查找结果 (%u 未读, 共有 %t)" #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?打开文件&保存文件? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - 帮助" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - 选择标签" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - 选择过滤器" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - 文章 '%T'" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - 链接" #: src/configcontainer.cpp:111 #, fuzzy msgid "%N %V - Dialogs" msgstr "%N %V - 链接" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "" #: src/configcontainer.cpp:159 #, fuzzy, c-format msgid "invalid configuration value `%s'" msgstr "把文章保存到 %s" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "当处理命令`%s'(%s 第 %n 行)时出错: %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "未知的命令 `%s' " #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "致命错误:无法确定主目录!" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "请设置主目录的环境变量,或者添加一个有效的用户其UID为 %u!" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: 未知的选项 - %c" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "启动 %s %s..." #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "错误:%s的一个进程已经在运行中(PID: %u)" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "加载配置文件..." #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "完毕." #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "打开缓存..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "错误:打开缓存文件`%s' 失败:%s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "从本地缓存中加载链接..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "从 %s 文件加载链接..." #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "错误:没有配置链接。请用RSS种子的链接替换 %s 或者导入一个OPML文件." #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "看起来你订阅的OPML种子没有包含任何种子请更正之后再尝试一下。" #: src/controller.cpp:392 #, fuzzy msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" "看起来你还没有在bloglines账户里配置任何种子 请先配置种子,然后再尝试一下。" #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "从缓存中加载文章" #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "彻底清除缓存" #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "当从数据库中加载种子的时候出错:" #: src/controller.cpp:430 #, fuzzy, c-format msgid "Error while loading feed '%s': %s" msgstr "当调用`%s'的时候出错: %s" #: src/controller.cpp:448 #, fuzzy msgid "Prepopulating query feeds..." msgstr "更新查询种子..." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "导入阅读文章列表" #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "导出阅读文章列表" #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "清空缓存..." #: src/controller.cpp:523 msgid "failed: " msgstr "失败: " #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "错误:无法将所有种子都标记为已读: %s" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%s加载中 %s..." #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "当抓取%s的时候出错: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "错误:无效的种子!" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "无效的种子索引(bug)" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "" #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "" #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" "%s %s\n" "用法: %s [-i |-e] [-u ] [-c ] [-x ...] [-" "h]\n" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "导出OPML种子列表到控制台" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "在本软件启动之初刷新种子列表" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 msgid "" msgstr "文件" #: src/controller.cpp:842 msgid "import OPML file" msgstr "导入opml文件" #: src/controller.cpp:843 msgid "" msgstr "<超链文件>" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "从超链文件里读取RSS种子列表" #: src/controller.cpp:844 msgid "" msgstr "缓存文件" #: src/controller.cpp:844 msgid "use as cache file" msgstr "使用作为保存缓存数据的文件" #: src/controller.cpp:845 msgid "" msgstr "<配置文件>" #: src/controller.cpp:845 msgid "read configuration from " msgstr "从<配置文件>里读取配置信息" #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "彻底清除缓存" #: src/controller.cpp:847 msgid "..." msgstr "命令 ..." #: src/controller.cpp:847 msgid "execute list of commands" msgstr "执行一系列命令" #: src/controller.cpp:848 #, fuzzy msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "激活离线模式(只对bloglines同步模式有效)" #: src/controller.cpp:849 msgid "quiet startup" msgstr "" #: src/controller.cpp:850 msgid "get version information" msgstr "获得版本信息" #: src/controller.cpp:851 msgid "" msgstr "记录等级" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "以某一等级做记录(有效值:1 - 6)" #: src/controller.cpp:852 msgid "" msgstr "<记录文件>" #: src/controller.cpp:852 msgid "use as output log file" msgstr "使用<记录文件>作为导出记录的文件" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "将已阅读文章导出到<文件>" #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "从<文件>里导入阅读的文章列表" #: src/controller.cpp:855 msgid "this help" msgstr "该帮助" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "" #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "%s 导入完毕" #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "书签支持尚未配置,请在配置文件里设置相应变量 `bookmark-cmd' " #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u 篇未读文章" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "标题: " #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "作者: " #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "日期: " #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "链接: " #: src/controller.cpp:1388 #, fuzzy, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "错误:无法将文章写至 %s" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "没有选择任何项目" #: src/dialogs_formaction.cpp:74 #, fuzzy msgid "Error: you can't remove the feed list!" msgstr "错误:你不能重新加载所选项目" #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "无效位置!" #: src/download.cpp:42 msgid "queued" msgstr "队列" #: src/download.cpp:44 msgid "downloading" msgstr "下载中" #: src/download.cpp:46 msgid "cancelled" msgstr "已取消" #: src/download.cpp:48 msgid "deleted" msgstr "已删除" #: src/download.cpp:50 msgid "finished" msgstr "已完毕" #: src/download.cpp:52 msgid "failed" msgstr "已失败" #: src/download.cpp:54 msgid "incomplete" msgstr "未完毕" #: src/download.cpp:56 msgid "played" msgstr "已播放" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "未知(bug)" #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "无效属性 `%s'" #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "无效参数" #: src/exception.cpp:43 msgid "too few parameters." msgstr "参数太少" #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "未知的命令(bug)" #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "无法打开文件" #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "未知的错误(bug)" #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "没有选择种子" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "n" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "标记该种子已读" #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "错误:无法将种子标记为已读" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "任何种子里都没有未读的文章" #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "" #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "" #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "将所有种子都标记为已读..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "没有定义任何标签" #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, fuzzy, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "错误:无法分析过滤器(filter)命令" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "没有定义任何过滤器(filter)" #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "查找: " #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "过滤器: " #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "你真的想离开么(y:是的 n:不是)?" #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "yn" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "y" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "放弃" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "打开" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "下一篇未读" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "重新加载当前种子" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "重新加载所有种子" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "标记为已读" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "抓取所有" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "查找" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "帮助" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "错误:无法分析过滤器(filter)命令" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "查找..." #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "当查找 `%s'的时候出错: %s" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "没有结果" #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "找不到这个位置" #: src/feedlist_formaction.cpp:774 #, fuzzy, c-format msgid "Feed List - %u unread, %u total" msgstr "%N %V - 查找结果 (%u 未读, 共有 %t)" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "你真的想覆盖 `%s'么(y:是的 n:不是)?" #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "文件: " #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - 打开文件 - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - 保存文件 - %s" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "取消" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "保存" #: src/filebrowser_formaction.cpp:271 #, fuzzy, c-format msgid "Open File - %s" msgstr "%s %s - 打开文件 - %s" #: src/filebrowser_formaction.cpp:273 #, fuzzy, c-format msgid "Save File - %s" msgstr "%s %s - 保存文件 - %s" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, fuzzy, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "错误:无法分析过滤器(filter)命令" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "用法: set <变量>[=<值>]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "" #: src/formaction.cpp:228 #, fuzzy msgid "usage: dumpconfig " msgstr "<配置文件>" #: src/formaction.cpp:231 #, fuzzy, c-format msgid "Saved configuration to %s" msgstr "把文章保存到 %s" #: src/formaction.cpp:236 #, fuzzy, c-format msgid "Not a command: %s" msgstr "未知的命令 `%s' " #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "保存书签..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "已保存的书签." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "当保存书签时出错:" #: src/formaction.cpp:303 msgid "URL: " msgstr "链接: " #: src/formaction.cpp:305 msgid "Description: " msgstr "描述: " #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "" #: src/googlereader_urlreader.cpp:34 #, fuzzy msgid "Starred items" msgstr "没有未读的文章" #: src/googlereader_urlreader.cpp:35 #, fuzzy msgid "Shared items" msgstr "没有未读的文章" #: src/googlereader_urlreader.cpp:36 #, fuzzy msgid "Popular items" msgstr "没有未读的文章" #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "清空" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "内嵌flash" #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "图片" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "所有链接" #: src/htmlrenderer.cpp:594 msgid "link" msgstr "链接" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "内嵌flash" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "未知(bug)" #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "切换文章阅读标记(已读/未读)" #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "当切换阅读标记(已读/未读)时出错: %s" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "空空如也的链接列表" #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "标记: " #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "错误:没有选择任何项目!" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "错误:你不能重新加载所选项目" #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "没有未读的文章" #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "" #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "" #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "没有未读的种子" #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "" #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 #, fuzzy msgid "dtfalg" msgstr "编辑标记" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "标记已更新" #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "将所有都标记为已读" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "放弃保存" #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "把文章保存到 %s" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "错误:无法保存文章到 %s" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "" #: src/itemlist_formaction.cpp:1004 #, fuzzy, c-format msgid "Article List - %s" msgstr "把文章保存到 %s" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "顶部" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "底部" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "种子: " #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "播客下载的地址: " #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "类型: " #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "当标记文章为已读的时候出错: %s" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "将 %s 加入下载队列" #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "将文章保存至 %s " #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "错误:无法将文章写至 %s" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "启动浏览器..." #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "当标记文章为未读的时候出错: %s" #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "在浏览器里打开" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "加入队列" #: src/itemview_formaction.cpp:586 #, fuzzy, c-format msgid "Article - %s" msgstr "把文章保存到 %s" #: src/itemview_formaction.cpp:624 #, fuzzy msgid "Error: invalid regular expression!" msgstr "错误:无效的种子!" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "打开种子/文章" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "返回到前一个对话框/退出" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "重新加载当前选择的种子" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "重新加载所有种子" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "标记当前种子为已读" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "标记所有种子为已读" #: src/keymap.cpp:30 msgid "Save article" msgstr "保存文章" #: src/keymap.cpp:31 #, fuzzy msgid "Go to next article" msgstr "转到下一篇未读文章" #: src/keymap.cpp:32 #, fuzzy msgid "Go to previous article" msgstr "转到前一篇未读文章" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "转到下一篇未读文章" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "转到前一篇未读文章" #: src/keymap.cpp:35 #, fuzzy msgid "Go to a random unread article" msgstr "转到下一篇未读文章" #: src/keymap.cpp:36 #, fuzzy msgid "Open article in browser and mark read" msgstr "在浏览器里打开文章" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "在浏览器里打开文章" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "打开帮助对话框" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "切换源代码显示" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "切换文章的阅读状态(已读/未读)" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "切换显示已读种子/文章" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "列出当前文章里的所有链接" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "清除当前标签" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "选择标签" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "打开搜索对话框" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "将该下载项目加入队列" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "重新加载配置文件里的链接列表" #: src/keymap.cpp:50 msgid "Download file" msgstr "下载文件" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "取消下载" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "将下载的项目标记为已删除" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "清除队列中已完成的和已删除的下载项目" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "切换是否自动下载" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "播放当前所选的下载项目" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "增加同步下载的进程数目" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "减少同步下载的进程数目" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "刷新屏显" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "打开命令行" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "设置一个过滤器" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "选择一个预设置的过滤器" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "清除当前所选的过滤器" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "将当前文章/链接加入书签" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "编辑标记" #: src/keymap.cpp:65 #, fuzzy msgid "Go to next feed" msgstr "转到下一篇未读的种子" #: src/keymap.cpp:66 #, fuzzy msgid "Go to previous feed" msgstr "转到前一篇未读的种子" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "转到下一篇未读的种子" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "转到前一篇未读的种子" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "调用一个宏命令" #: src/keymap.cpp:70 msgid "Delete article" msgstr "删除文章" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "压缩已删除文章" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "编辑已提交链接" #: src/keymap.cpp:73 #, fuzzy msgid "Close currently selected dialog" msgstr "重新加载当前选择的种子" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "" #: src/keymap.cpp:75 #, fuzzy msgid "Go to next dialog" msgstr "转到下一篇未读文章" #: src/keymap.cpp:76 #, fuzzy msgid "Go to previous dialog" msgstr "返回到前一个对话框/退出" #: src/keymap.cpp:77 #, fuzzy msgid "Pipe article to command" msgstr "把文章保存到 %s" #: src/keymap.cpp:78 #, fuzzy msgid "Sort current list" msgstr "清除当前标签" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "打开链接10" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "打开链接1" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "打开链接2" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "打开链接3" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "打开链接4" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "打开链接5" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "打开链接6" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "打开链接7" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "打开链接8" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "打开链接9" #: src/keymap.cpp:92 #, fuzzy msgid "Move to the previous entry" msgstr "转到前一篇未读的种子" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "" #: src/keymap.cpp:94 #, fuzzy msgid "Move to the previous page" msgstr "返回到前一个对话框/退出" #: src/keymap.cpp:95 #, fuzzy msgid "Move to the next page" msgstr "转到下一篇未读文章" #: src/keymap.cpp:97 #, fuzzy msgid "Move to the start of page/list" msgstr "转到下一篇未读文章" #: src/keymap.cpp:98 #, fuzzy msgid "Move to the end of page/list" msgstr "转到下一篇未读文章" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "清空队列..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C 里读取配置信息\n" "-q 使用作为队列文件\n" "-a 在一开始就启动下载\n" "-h 显示当前帮助列表\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr " - %u 个并行下载" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "队列 (%u 个下载项目在进行,共有 %u 个下载项目) - 总共 %.2f kb/s %s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "错误: 无法取消: 还有项目在下载" #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "错误:下载项目必须下载完毕才可以播放" #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "错误:无法执行操作:有项目在下载中" #: src/pb_view.cpp:276 msgid "Download" msgstr "下载" #: src/pb_view.cpp:278 msgid "Delete" msgstr "删除" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "清除完毕的项目" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "切换自动下载" #: src/pb_view.cpp:281 msgid "Play" msgstr "播放" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "" #: src/regexmanager.cpp:49 #, fuzzy, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "错误:无效的种子!" #: src/rss.cpp:466 #, fuzzy msgid "too few arguments" msgstr "参数太少" #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "错误:不支持的链接: %s" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "选择标签" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "选择过滤器" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "属性没有发现" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "当读取XML标签时遇到EOF标记" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "没有选择任何链接!" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "保存书签" #: src/urlview_formaction.cpp:146 #, fuzzy msgid "URLs" msgstr "链接: " #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "错误: 应用过滤器失败: %s" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "错误: 种子里没有包含任何项目!" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "更新查询种子..." #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "" #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "" #: rss/parser.cpp:174 #, fuzzy msgid "could not parse file" msgstr "错误:无法分析过滤器(filter)命令" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "" #: rss/parser.cpp:211 #, fuzzy msgid "invalid RSS version" msgstr "无效位置!" #: rss/parser.cpp:226 rss/parser.cpp:233 #, fuzzy msgid "invalid Atom version" msgstr "无效位置!" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "" #~ msgid "" #~ "%s %s\n" #~ "usage: %s [-i |-e] [-u ] [-c ] [-x " #~ " ...] [-h]\n" #~ "-e export OPML feed to stdout\n" #~ "-r refresh feeds on start\n" #~ "-i import OPML file\n" #~ "-u read RSS feed URLs from \n" #~ "-c use as cache file\n" #~ "-C read configuration from \n" #~ "-v clean up cache thoroughly\n" #~ "-x ... execute list of commands\n" #~ "-o activate offline mode (only applies to bloglines " #~ "synchronization mode)\n" #~ "-V get version information\n" #~ "-l write a log with a certain loglevel (valid values: 1 to " #~ "6)\n" #~ "-d use as output log file\n" #~ "-E export list of read articles to \n" #~ "-I import list of read articles from \n" #~ "-h this help\n" #~ msgstr "" #~ "%s %s\n" #~ "usage: %s [-i |-e] [-u ] [-c ] [-h]\n" #~ "-e 导出OPML种子,并将之写至标准输入设备(stdout)\n" #~ "-r 在启动之初刷新种子列表\n" #~ "-i 导入OPML文件\n" #~ "-u 链接读取RSS种子列表\n" #~ "-c 使用作为缓存文件\n" #~ "-C 读取配置信息\n" #~ "-v 彻底清空缓存\n" #~ "-x ... 执行一系列命令\n" #~ "-o 激活离线模式(只对bloglines同步模式有效)\n" #~ "-V 显示版本信息\n" #~ "-l 以某一等级做记录(有效值:1 - 6)\n" #~ " -d 使用<记录文件>作为导出记录的文件\n" #~ "-E 将已阅读文章导出到<文件>\n" #~ "-I 从<文件>里导入阅读的文章列表\n" #~ "-h 显示这个帮助列表\n" newsbeuter-2.7/po/zh_TW.po000066400000000000000000001151401220711462700155620ustar00rootroot00000000000000# Traditional Chinese translation for newsbeuter # Copyright (C) 2008 # This file is distributed under the same license as the newsbeuter package # aeglos , 2008. # msgid "" msgstr "" "Project-Id-Version: newsbeuter 1.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-09-14 17:33+0200\n" "PO-Revision-Date: 2010-03-03 16:55+0800\n" "Last-Translator: Aeglos \n" "Language-Team: Traditional Chinese \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Traditional Chinese\n" "X-Poedit-Country: Taiwan\n" "X-Poedit-SourceCharset: UTF-8\n" #: src/colormanager.cpp:44 src/colormanager.cpp:46 src/regexmanager.cpp:55 #: src/regexmanager.cpp:64 src/regexmanager.cpp:113 src/regexmanager.cpp:121 #, c-format msgid "`%s' is not a valid color" msgstr "`%s'不是有效的顏色" #: src/colormanager.cpp:51 src/regexmanager.cpp:73 src/regexmanager.cpp:131 #, c-format msgid "`%s' is not a valid attribute" msgstr "`%s' 不是有效的屬性" #: src/colormanager.cpp:62 #, c-format msgid "`%s' is not a valid configuration element" msgstr "`%s'不是一個有效的組態項目" #: src/configcontainer.cpp:64 #, c-format msgid "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" msgstr "newsbeuter:重新載入完成, %f個來源含未讀文章(共有 %n 篇未讀文章)" #: src/configcontainer.cpp:102 msgid "%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?" msgstr "%N %V - 你的來源 (%u 篇未讀, 共有 %t 篇)%?T? - 標籤 `%T'&?" #: src/configcontainer.cpp:103 msgid "%N %V - Articles in feed '%T' (%u unread, %t total) - %U" msgstr "%N %V - 來源 '%T' 裡的文章(%u 未讀, 共有 %t 篇) - %U" #: src/configcontainer.cpp:104 msgid "%N %V - Search result (%u unread, %t total)" msgstr "%N %V - 搜尋結果 (%u 未讀, 共有 %t)" #: src/configcontainer.cpp:105 msgid "%N %V - %?O?Open File&Save File? - %f" msgstr "%N %V - %?O?打開檔案&儲存檔案? - %f" #: src/configcontainer.cpp:106 msgid "%N %V - Help" msgstr "%N %V - 說明" #: src/configcontainer.cpp:107 msgid "%N %V - Select Tag" msgstr "%N %V - 選擇標籤" #: src/configcontainer.cpp:108 msgid "%N %V - Select Filter" msgstr "%N %V - 選擇過濾器" #: src/configcontainer.cpp:109 msgid "%N %V - Article '%T'" msgstr "%N %V - 文章 '%T'" #: src/configcontainer.cpp:110 msgid "%N %V - URLs" msgstr "%N %V - 網址" #: src/configcontainer.cpp:111 msgid "%N %V - Dialogs" msgstr "%N %V - 對話窗" #: src/configcontainer.cpp:147 #, c-format msgid "expected boolean value, found `%s' instead" msgstr "預期的布林變數被`%s'取代" #: src/configcontainer.cpp:153 #, c-format msgid "expected integer value, found `%s' instead" msgstr "預期的整數變數被`%s'取代" #: src/configcontainer.cpp:159 #, c-format msgid "invalid configuration value `%s'" msgstr "無效的組態值 `%s'" #: src/configparser.cpp:80 #, c-format msgid "Error while processing command `%s' (%s line %u): %s" msgstr "在處理命令`%s'(%s 第 %u 行)時發生錯誤: %s" #: src/configparser.cpp:83 #, c-format msgid "unknown command `%s'" msgstr "未知的命令 `%s' " #: src/controller.cpp:90 src/pb_controller.cpp:43 msgid "Fatal error: couldn't determine home directory!" msgstr "嚴重錯誤:無法確認主目錄!" #: src/controller.cpp:91 src/pb_controller.cpp:44 #, c-format msgid "" "Please set the HOME environment variable or add a valid user for UID %u!" msgstr "請設定主目錄的環境變數,或者增加一個UID為 %u的有效使用者!" #: src/controller.cpp:226 src/pb_controller.cpp:102 #, c-format msgid "%s: unknown option - %c" msgstr "%s: 未知的選項 - %c" #: src/controller.cpp:250 src/pb_controller.cpp:108 #, c-format msgid "Starting %s %s..." msgstr "啟動 %s %s..." #: src/controller.cpp:260 src/controller.cpp:319 src/pb_controller.cpp:112 #, c-format msgid "Error: an instance of %s is already running (PID: %u)" msgstr "錯誤:已有一個%s程序在執行中(PID: %u)" #: src/controller.cpp:267 src/pb_controller.cpp:116 msgid "Loading configuration..." msgstr "載入設定檔..." #: src/controller.cpp:299 src/controller.cpp:337 src/controller.cpp:364 #: src/controller.cpp:380 src/controller.cpp:408 src/controller.cpp:412 #: src/controller.cpp:444 src/controller.cpp:456 src/controller.cpp:470 #: src/controller.cpp:479 src/controller.cpp:518 src/pb_controller.cpp:153 #: src/pb_controller.cpp:170 msgid "done." msgstr "完成。" #: src/controller.cpp:325 src/controller.cpp:403 msgid "Opening cache..." msgstr "打開快取中..." #: src/controller.cpp:331 #, c-format msgid "Error: opening the cache file `%s' failed: %s" msgstr "錯誤:打開快取檔案`%s' 失敗:%s" #: src/controller.cpp:358 msgid "Loading URLs from local cache..." msgstr "從本地快取中載入鏈結..." #: src/controller.cpp:368 #, c-format msgid "Loading URLs from %s..." msgstr "從 %s 中載入鏈結..." #: src/controller.cpp:388 #, c-format msgid "" "Error: no URLs configured. Please fill the file %s with RSS feed URLs or " "import an OPML file." msgstr "錯誤:沒有設置鏈結。請用RSS來源的鏈結替換 %s 或者匯入一個OPML檔案" #: src/controller.cpp:390 msgid "" "It looks like the OPML feed you subscribed contains no feeds. Please fill it " "with feeds, and try again." msgstr "看起來你訂閱的OPML沒有任何來源。請先加入來源,然後再試一次。" #: src/controller.cpp:392 msgid "" "It looks like you haven't configured any feeds in your Google Reader " "account. Please do so, and try again." msgstr "" "看來你還沒有在Google Reader帳號裡配置任何來源。請先配置來源,然後再試一次。" #: src/controller.cpp:401 msgid "Loading articles from cache..." msgstr "從快取中載入文章" #: src/controller.cpp:409 msgid "Cleaning up cache thoroughly..." msgstr "徹底清空快取" #: src/controller.cpp:426 msgid "Error while loading feeds from database: " msgstr "從資料庫中載入來源時發生錯誤:" #: src/controller.cpp:430 #, c-format msgid "Error while loading feed '%s': %s" msgstr "載入 `%s'的時候發生錯誤: %s" #: src/controller.cpp:448 msgid "Prepopulating query feeds..." msgstr "更新查詢來源..." #: src/controller.cpp:467 msgid "Importing list of read articles..." msgstr "匯入已閱讀文章列表..." #: src/controller.cpp:476 msgid "Exporting list of read articles..." msgstr "匯出已閱讀文章列表..." #: src/controller.cpp:511 msgid "Cleaning up cache..." msgstr "清空快取..." #: src/controller.cpp:523 msgid "failed: " msgstr "失敗: " #: src/controller.cpp:544 #, c-format msgid "Error: couldn't mark all feeds read: %s" msgstr "錯誤:無法將所有來源標為已讀: %s" #: src/controller.cpp:600 #, c-format msgid "%sLoading %s..." msgstr "%s載入中 %s..." #: src/controller.cpp:622 src/controller.cpp:624 src/controller.cpp:626 #, c-format msgid "Error while retrieving %s: %s" msgstr "在抓取%s的時候發生錯誤: %s" #: src/controller.cpp:634 msgid "Error: invalid feed!" msgstr "錯誤:無效的來源!" #: src/controller.cpp:641 msgid "invalid feed index (bug)" msgstr "無效的來源索引(bug)" #: src/controller.cpp:803 msgid "" "newsbeuter is free software and licensed under the MIT/X Consortium License." msgstr "newsbeuter是基於MIT/X Consortium License發佈的自由軟體" #: src/controller.cpp:804 #, c-format msgid "Type `%s -vv' for more information." msgstr "輸入`%s -vv'以取得更多資訊" #: src/controller.cpp:833 #, c-format msgid "" "%s %s\n" "usage: %s [-i |-e] [-u ] [-c ] [-x ...] " "[-h]\n" msgstr "" "%s %s\n" "使用方法: %s [-i |-e] [-u <網址檔案>] [-c <快取檔案>] [-x <命令> ...] " "[-h]\n" #: src/controller.cpp:840 msgid "export OPML feed to stdout" msgstr "匯出OPML來源到標準輸出" #: src/controller.cpp:841 msgid "refresh feeds on start" msgstr "啟動時更新文件" #: src/controller.cpp:842 src/controller.cpp:853 src/controller.cpp:854 msgid "" msgstr "<檔案>" #: src/controller.cpp:842 msgid "import OPML file" msgstr "匯入OPML檔案" #: src/controller.cpp:843 msgid "" msgstr "<網址檔案>" #: src/controller.cpp:843 msgid "read RSS feed URLs from " msgstr "從<網址檔案>讀取RSS來源的網址" #: src/controller.cpp:844 msgid "" msgstr "<快取檔案>" #: src/controller.cpp:844 msgid "use as cache file" msgstr "使用<快取檔案>作為快取檔案" #: src/controller.cpp:845 msgid "" msgstr "<組態檔案>" #: src/controller.cpp:845 msgid "read configuration from " msgstr "從<組態檔案>讀取組態" #: src/controller.cpp:846 msgid "clean up cache thoroughly" msgstr "徹底清除快取" #: src/controller.cpp:847 msgid "..." msgstr "<命令>..." #: src/controller.cpp:847 msgid "execute list of commands" msgstr "執行列出的命令" #: src/controller.cpp:848 #, fuzzy msgid "" "activate offline mode (only applies to Google Reader synchronization mode)" msgstr "啟動離線模式((只套用到bloglines synchronization mode)" #: src/controller.cpp:849 msgid "quiet startup" msgstr "" #: src/controller.cpp:850 msgid "get version information" msgstr "取得版本資訊" #: src/controller.cpp:851 msgid "" msgstr "<記錄層級>" #: src/controller.cpp:851 msgid "write a log with a certain loglevel (valid values: 1 to 6)" msgstr "依記錄層級(有效值:1到6)進行記錄" #: src/controller.cpp:852 msgid "" msgstr "<記錄檔案>" #: src/controller.cpp:852 msgid "use as output log file" msgstr "使用<記錄檔案>作為輸出的記錄檔" #: src/controller.cpp:853 msgid "export list of read articles to " msgstr "匯出已閱讀文章列表至<檔案>" #: src/controller.cpp:854 msgid "import list of read articles from " msgstr "由<檔案>匯入閱讀文章列表..." #: src/controller.cpp:855 msgid "this help" msgstr "這份說明" #: src/controller.cpp:873 #, c-format msgid "An error occured while parsing %s." msgstr "在分析%s時發生錯誤" #: src/controller.cpp:888 #, c-format msgid "Import of %s finished." msgstr "%s 匯入完畢" #: src/controller.cpp:1120 msgid "" "bookmarking support is not configured. Please set the configuration variable " "`bookmark-cmd' accordingly." msgstr "書籤功能還未設定,請在設定檔中設定變數 `bookmark-cmd' " #: src/controller.cpp:1133 #, c-format msgid "%u unread articles" msgstr "%u篇未讀文章" #: src/controller.cpp:1164 src/formaction.cpp:304 #: src/itemview_formaction.cpp:85 msgid "Title: " msgstr "標題: " #: src/controller.cpp:1168 src/itemview_formaction.cpp:90 msgid "Author: " msgstr "作者: " #: src/controller.cpp:1172 src/itemview_formaction.cpp:99 msgid "Date: " msgstr "日期: " #: src/controller.cpp:1176 src/itemview_formaction.cpp:95 msgid "Link: " msgstr "鏈結: " #: src/controller.cpp:1388 #, c-format msgid "Error: couldn't open configuration file `%s'!" msgstr "錯誤:無法開啟組態檔案`%s'!" #: src/dialogs_formaction.cpp:46 msgid "Close" msgstr "關閉" #: src/dialogs_formaction.cpp:47 msgid "Goto Dialog" msgstr "前往對話窗" #: src/dialogs_formaction.cpp:48 msgid "Close Dialog" msgstr "關閉對話窗" #: src/dialogs_formaction.cpp:62 src/dialogs_formaction.cpp:77 #: src/itemlist_formaction.cpp:53 src/itemlist_formaction.cpp:70 #: src/itemlist_formaction.cpp:93 src/itemlist_formaction.cpp:105 #: src/itemlist_formaction.cpp:149 src/itemlist_formaction.cpp:167 #: src/itemlist_formaction.cpp:187 src/itemlist_formaction.cpp:344 #: src/itemlist_formaction.cpp:527 msgid "No item selected!" msgstr "沒有選擇任何項目" #: src/dialogs_formaction.cpp:74 msgid "Error: you can't remove the feed list!" msgstr "錯誤:你不能移除來源列表!" #: src/dialogs_formaction.cpp:99 src/feedlist_formaction.cpp:726 #: src/itemlist_formaction.cpp:858 src/urlview_formaction.cpp:136 msgid "Invalid position!" msgstr "無效位置!" #: src/download.cpp:42 msgid "queued" msgstr "隊列" #: src/download.cpp:44 msgid "downloading" msgstr "下載中" #: src/download.cpp:46 msgid "cancelled" msgstr "已取消" #: src/download.cpp:48 msgid "deleted" msgstr "已刪除" #: src/download.cpp:50 msgid "finished" msgstr "已完畢" #: src/download.cpp:52 msgid "failed" msgstr "已失敗" #: src/download.cpp:54 msgid "incomplete" msgstr "未完畢" #: src/download.cpp:56 msgid "played" msgstr "已播放" #: src/download.cpp:58 msgid "unknown (bug)." msgstr "未知(bug)" #: src/exception.cpp:23 #, c-format msgid "attribute `%s' is not available." msgstr "無效屬性 `%s'" #: src/exception.cpp:26 #, c-format msgid "regular expression '%s' is invalid: %s" msgstr "正規表示式 '%s' 是無效的: %s" #: src/exception.cpp:41 msgid "invalid parameters." msgstr "無效參數" #: src/exception.cpp:43 msgid "too few parameters." msgstr "參數過少" #: src/exception.cpp:45 msgid "unknown command (bug)." msgstr "未知的命令(bug)" #: src/exception.cpp:47 msgid "file couldn't be opened." msgstr "無法打開檔案" #: src/exception.cpp:49 msgid "unknown error (bug)." msgstr "未知的錯誤(bug)" #: src/feedlist_formaction.cpp:99 src/feedlist_formaction.cpp:109 #: src/feedlist_formaction.cpp:187 msgid "No feed selected!" msgstr "沒有選擇的來源!" #: src/feedlist_formaction.cpp:120 msgid "Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?" msgstr "排序依照:(f)第一項Tag/(t)標題/(a)文章數量/(u)未讀文章數量/(n)無?" #: src/feedlist_formaction.cpp:120 src/feedlist_formaction.cpp:137 msgid "ftaun" msgstr "ftaun" #: src/feedlist_formaction.cpp:123 src/feedlist_formaction.cpp:140 #: src/itemlist_formaction.cpp:420 src/itemlist_formaction.cpp:439 msgid "f" msgstr "f" #: src/feedlist_formaction.cpp:125 src/feedlist_formaction.cpp:142 #: src/itemlist_formaction.cpp:418 src/itemlist_formaction.cpp:437 msgid "t" msgstr "t" #: src/feedlist_formaction.cpp:127 src/feedlist_formaction.cpp:144 #: src/itemlist_formaction.cpp:422 src/itemlist_formaction.cpp:441 msgid "a" msgstr "a" #: src/feedlist_formaction.cpp:129 src/feedlist_formaction.cpp:146 msgid "u" msgstr "u" #: src/feedlist_formaction.cpp:131 src/feedlist_formaction.cpp:148 #: src/filebrowser_formaction.cpp:102 msgid "n" msgstr "n" #: src/feedlist_formaction.cpp:137 msgid "" "Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)" "one?" msgstr "排序依照:(f)第一項Tag/(t)標題/(a)文章數量/(u)未讀文章數量/(n)無?" #: src/feedlist_formaction.cpp:175 src/itemlist_formaction.cpp:296 msgid "Marking feed read..." msgstr "將來源標為已讀..." #: src/feedlist_formaction.cpp:184 src/itemlist_formaction.cpp:313 #, c-format msgid "Error: couldn't mark feed read: %s" msgstr "錯誤:無法將來源%s標記為已讀" #: src/feedlist_formaction.cpp:208 src/feedlist_formaction.cpp:216 #: src/feedlist_formaction.cpp:240 msgid "No feeds with unread items." msgstr "沒有含未讀文章的來源" #: src/feedlist_formaction.cpp:224 src/itemlist_formaction.cpp:286 msgid "Already on last feed." msgstr "" #: src/feedlist_formaction.cpp:232 src/itemlist_formaction.cpp:291 msgid "Already on first feed." msgstr "" #: src/feedlist_formaction.cpp:246 msgid "Marking all feeds read..." msgstr "將所有來源標為已讀..." #: src/feedlist_formaction.cpp:270 msgid "No tags defined." msgstr "沒有定義任何標籤" #: src/feedlist_formaction.cpp:285 src/itemlist_formaction.cpp:378 #, c-format msgid "Error: couldn't parse filter command `%s': %s" msgstr "錯誤:無法分析過濾的命令 `%s': %s" #: src/feedlist_formaction.cpp:295 src/itemlist_formaction.cpp:389 msgid "No filters defined." msgstr "沒有定義任何過濾器(filter)" #: src/feedlist_formaction.cpp:308 src/help_formaction.cpp:30 #: src/itemlist_formaction.cpp:356 src/itemview_formaction.cpp:231 msgid "Search for: " msgstr "搜尋: " #: src/feedlist_formaction.cpp:325 src/itemlist_formaction.cpp:402 msgid "Filter: " msgstr "過濾器: " #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "Do you really want to quit (y:Yes n:No)? " msgstr "你確定要離開嗎(y:是的 n:不是)?" #: src/feedlist_formaction.cpp:334 src/filebrowser_formaction.cpp:102 #: src/view.cpp:184 msgid "yn" msgstr "yn" #: src/feedlist_formaction.cpp:334 src/view.cpp:184 msgid "y" msgstr "y" #: src/feedlist_formaction.cpp:416 src/help_formaction.cpp:154 #: src/itemlist_formaction.cpp:836 src/itemview_formaction.cpp:393 #: src/pb_view.cpp:266 src/pb_view.cpp:275 src/urlview_formaction.cpp:124 msgid "Quit" msgstr "放棄" #: src/feedlist_formaction.cpp:417 src/itemlist_formaction.cpp:837 msgid "Open" msgstr "打開" #: src/feedlist_formaction.cpp:418 src/itemlist_formaction.cpp:840 #: src/itemview_formaction.cpp:395 msgid "Next Unread" msgstr "下一篇未讀" #: src/feedlist_formaction.cpp:419 src/itemlist_formaction.cpp:839 msgid "Reload" msgstr "重新載入" #: src/feedlist_formaction.cpp:420 msgid "Reload All" msgstr "全部重新載入" #: src/feedlist_formaction.cpp:421 msgid "Mark Read" msgstr "標為已讀" #: src/feedlist_formaction.cpp:422 msgid "Catchup All" msgstr "抓取所有" #: src/feedlist_formaction.cpp:423 src/help_formaction.cpp:155 #: src/itemlist_formaction.cpp:842 msgid "Search" msgstr "搜尋" #: src/feedlist_formaction.cpp:424 src/help_formaction.cpp:182 #: src/itemlist_formaction.cpp:843 src/itemview_formaction.cpp:398 #: src/pb_view.cpp:208 src/pb_view.cpp:282 msgid "Help" msgstr "說明" #: src/feedlist_formaction.cpp:681 src/itemlist_formaction.cpp:513 msgid "Error: couldn't parse filter command!" msgstr "錯誤:無法分析過濾器(filter)命令" #: src/feedlist_formaction.cpp:696 src/itemlist_formaction.cpp:548 msgid "Searching..." msgstr "搜尋中..." #: src/feedlist_formaction.cpp:703 src/itemlist_formaction.cpp:559 #, c-format msgid "Error while searching for `%s': %s" msgstr "在搜尋 `%s'的時候出錯: %s" #: src/feedlist_formaction.cpp:712 src/itemlist_formaction.cpp:564 msgid "No results." msgstr "沒有結果" #: src/feedlist_formaction.cpp:721 src/itemlist_formaction.cpp:853 msgid "Position not visible!" msgstr "找不到這個位置" #: src/feedlist_formaction.cpp:774 #, c-format msgid "Feed List - %u unread, %u total" msgstr "來源列表 - %u 未讀, 總共 %u" #: src/filebrowser_formaction.cpp:102 #, c-format msgid "Do you really want to overwrite `%s' (y:Yes n:No)? " msgstr "你確定要覆蓋 `%s'嗎(y:是的 n:不是)?" #: src/filebrowser_formaction.cpp:166 msgid "File: " msgstr "檔案: " #: src/filebrowser_formaction.cpp:185 #, c-format msgid "%s %s - Open File - %s" msgstr "%s %s - 打開檔案 - %s" #: src/filebrowser_formaction.cpp:187 #, c-format msgid "%s %s - Save File - %s" msgstr "%s %s - 儲存檔案 - %s" #: src/filebrowser_formaction.cpp:194 src/pb_view.cpp:277 #: src/select_formaction.cpp:145 src/select_formaction.cpp:150 msgid "Cancel" msgstr "取消" #: src/filebrowser_formaction.cpp:195 src/itemlist_formaction.cpp:838 #: src/itemview_formaction.cpp:394 msgid "Save" msgstr "儲存" #: src/filebrowser_formaction.cpp:271 #, c-format msgid "Open File - %s" msgstr "打開檔案 - %s" #: src/filebrowser_formaction.cpp:273 #, c-format msgid "Save File - %s" msgstr "儲存檔案 - %s" #: src/filtercontainer.cpp:22 src/regexmanager.cpp:138 src/rss.cpp:355 #, c-format msgid "couldn't parse filter expression `%s': %s" msgstr "無法分析過濾的表示式 `%s': %s" #: src/formaction.cpp:186 src/formaction.cpp:207 msgid "usage: set [=]" msgstr "用法: set <變數>[=<值>]" #: src/formaction.cpp:215 msgid "usage: source [...]" msgstr "使用方式:source <檔案> [...]" #: src/formaction.cpp:228 msgid "usage: dumpconfig " msgstr "使用方式: dumpconfig <檔案>" #: src/formaction.cpp:231 #, c-format msgid "Saved configuration to %s" msgstr "把組態儲存到 %s" #: src/formaction.cpp:236 #, c-format msgid "Not a command: %s" msgstr "未知的命令: `%s' " #: src/formaction.cpp:275 msgid "Saving bookmark..." msgstr "儲存書籤..." #: src/formaction.cpp:278 msgid "Saved bookmark." msgstr "已儲存的書籤." #: src/formaction.cpp:280 msgid "Error while saving bookmark: " msgstr "在儲存書籤時發生錯誤:" #: src/formaction.cpp:303 msgid "URL: " msgstr "鏈結: " #: src/formaction.cpp:305 msgid "Description: " msgstr "描述: " #: src/googlereader_urlreader.cpp:33 msgid "People you follow" msgstr "你追蹤的人" #: src/googlereader_urlreader.cpp:34 msgid "Starred items" msgstr "星號的文章" #: src/googlereader_urlreader.cpp:35 msgid "Shared items" msgstr "分享的文章" #: src/googlereader_urlreader.cpp:36 msgid "Popular items" msgstr "熱門的文章" #: src/help_formaction.cpp:127 msgid "Generic bindings:" msgstr "一般的綁定方式:" #: src/help_formaction.cpp:134 msgid "Unbound functions:" msgstr "未綁定的功能:" #: src/help_formaction.cpp:156 msgid "Clear" msgstr "清除" #: src/htmlrenderer.cpp:145 msgid "embedded flash:" msgstr "內嵌的flash" #: src/htmlrenderer.cpp:176 src/htmlrenderer.cpp:595 msgid "image" msgstr "圖片" #: src/htmlrenderer.cpp:585 msgid "Links: " msgstr "所有鏈結" #: src/htmlrenderer.cpp:594 msgid "link" msgstr "鏈結" #: src/htmlrenderer.cpp:596 msgid "embedded flash" msgstr "內嵌的flash" #: src/htmlrenderer.cpp:597 msgid "unknown (bug)" msgstr "未知(bug)" #: src/itemlist_formaction.cpp:112 src/itemview_formaction.cpp:323 msgid "Toggling read flag for article..." msgstr "切換文章閱讀標記(已讀/未讀)" #: src/itemlist_formaction.cpp:126 #, c-format msgid "Error while toggling read flag: %s" msgstr "當切換閱讀標記(已讀/未讀)時出錯: %s" #: src/itemlist_formaction.cpp:145 src/itemview_formaction.cpp:268 msgid "URL list empty." msgstr "空白的鏈結列表" #: src/itemlist_formaction.cpp:182 src/itemview_formaction.cpp:103 #: src/itemview_formaction.cpp:259 msgid "Flags: " msgstr "標記: " #: src/itemlist_formaction.cpp:205 src/itemlist_formaction.cpp:881 msgid "Error: no item selected!" msgstr "錯誤:沒有選擇任何項目!" #: src/itemlist_formaction.cpp:219 msgid "Error: you can't reload search results." msgstr "錯誤:你不能重新載入所選項目" #: src/itemlist_formaction.cpp:239 src/itemlist_formaction.cpp:247 #: src/itemlist_formaction.cpp:270 src/itemview_formaction.cpp:282 #: src/itemview_formaction.cpp:291 src/itemview_formaction.cpp:318 #: src/view.cpp:626 src/view.cpp:684 msgid "No unread items." msgstr "沒有未讀的文章" #: src/itemlist_formaction.cpp:255 src/itemview_formaction.cpp:300 #: src/view.cpp:746 msgid "Already on last item." msgstr "" #: src/itemlist_formaction.cpp:263 src/itemview_formaction.cpp:309 #: src/view.cpp:715 msgid "Already on first item." msgstr "" #: src/itemlist_formaction.cpp:276 src/itemlist_formaction.cpp:281 msgid "No unread feeds." msgstr "沒有未讀的來源" #: src/itemlist_formaction.cpp:340 src/itemview_formaction.cpp:245 msgid "Pipe article to command: " msgstr "Pipe article to command: " #: src/itemlist_formaction.cpp:413 msgid "Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "排序依照:(d)日期/(t)標題/(f)" #: src/itemlist_formaction.cpp:413 src/itemlist_formaction.cpp:432 msgid "dtfalg" msgstr "dtfalg" #: src/itemlist_formaction.cpp:416 src/itemlist_formaction.cpp:435 msgid "d" msgstr "d" #: src/itemlist_formaction.cpp:424 src/itemlist_formaction.cpp:443 msgid "l" msgstr "l" #: src/itemlist_formaction.cpp:426 src/itemlist_formaction.cpp:445 msgid "g" msgstr "g" #: src/itemlist_formaction.cpp:432 msgid "Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?" msgstr "反向排序依(d)日期/(t)標題/(f)標誌/(a)作者/(l)連結/(g)用戶號碼" #: src/itemlist_formaction.cpp:537 src/itemview_formaction.cpp:484 msgid "Flags updated." msgstr "標記已更新" #: src/itemlist_formaction.cpp:841 msgid "Mark All Read" msgstr "標記全部為已讀" #: src/itemlist_formaction.cpp:917 src/itemview_formaction.cpp:195 #: src/itemview_formaction.cpp:459 msgid "Aborted saving." msgstr "放棄儲存" #: src/itemlist_formaction.cpp:921 src/itemview_formaction.cpp:463 #, c-format msgid "Saved article to %s" msgstr "把文章儲存到 %s" #: src/itemlist_formaction.cpp:923 src/itemview_formaction.cpp:465 #, c-format msgid "Error: couldn't save article to %s" msgstr "錯誤:無法儲存文章到 %s" #: src/itemlist_formaction.cpp:999 #, c-format msgid "Search Result - '%s'" msgstr "搜尋結果 - '%s'" #: src/itemlist_formaction.cpp:1002 #, c-format msgid "Query Feed - %s" msgstr "查詢來源 - %s" #: src/itemlist_formaction.cpp:1004 #, c-format msgid "Article List - %s" msgstr "文章列表 %s" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:575 msgid "Top" msgstr "頂端" #: src/itemview_formaction.cpp:34 src/itemview_formaction.cpp:577 msgid "Bottom" msgstr "底端" #: src/itemview_formaction.cpp:80 msgid "Feed: " msgstr "來源: " #: src/itemview_formaction.cpp:108 msgid "Podcast Download URL: " msgstr "Pocast下載網址: " #: src/itemview_formaction.cpp:110 msgid "type: " msgstr "類型: " #: src/itemview_formaction.cpp:166 #, c-format msgid "Error while marking article as read: %s" msgstr "當標記文章為已讀的時候發生錯誤: %s" #: src/itemview_formaction.cpp:178 #, c-format msgid "Added %s to download queue." msgstr "將 %s 加入下載隊列" #: src/itemview_formaction.cpp:180 #, c-format msgid "Invalid URL: '%s'" msgstr "無效的網址:'%s'" #: src/itemview_formaction.cpp:199 #, c-format msgid "Saved article to %s." msgstr "將文章保存至 %s " #: src/itemview_formaction.cpp:201 #, c-format msgid "Error: couldn't write article to file %s" msgstr "錯誤:無法將文章寫至 %s" #: src/itemview_formaction.cpp:208 src/itemview_formaction.cpp:357 #: src/itemview_formaction.cpp:509 src/urlview_formaction.cpp:34 #: src/urlview_formaction.cpp:69 msgid "Starting browser..." msgstr "啟動瀏覽器..." #: src/itemview_formaction.cpp:328 #, c-format msgid "Error while marking article as unread: %s" msgstr "將文章標為未讀時發生錯誤: %s" #: src/itemview_formaction.cpp:372 src/keymap.cpp:47 msgid "Goto URL #" msgstr "前往網址 #" #: src/itemview_formaction.cpp:396 src/urlview_formaction.cpp:125 msgid "Open in Browser" msgstr "在瀏覽器裡打開" #: src/itemview_formaction.cpp:397 msgid "Enqueue" msgstr "加入隊列" #: src/itemview_formaction.cpp:586 #, c-format msgid "Article - %s" msgstr "文章 - %s" #: src/itemview_formaction.cpp:624 msgid "Error: invalid regular expression!" msgstr "錯誤:無效的正規表示式!" #: src/keymap.cpp:23 msgid "Open feed/article" msgstr "打開來源/文章" #: src/keymap.cpp:24 msgid "Return to previous dialog/Quit" msgstr "返回到前一個對話框/退出" #: src/keymap.cpp:25 msgid "Quit program, no confirmation" msgstr "不經確認,直接離開程式" #: src/keymap.cpp:26 msgid "Reload currently selected feed" msgstr "重新載入選擇的來源" #: src/keymap.cpp:27 msgid "Reload all feeds" msgstr "重新載入所有來源" #: src/keymap.cpp:28 msgid "Mark feed read" msgstr "將來源標為已讀" #: src/keymap.cpp:29 msgid "Mark all feeds read" msgstr "將所有來源標為已讀" #: src/keymap.cpp:30 msgid "Save article" msgstr "保存文章" #: src/keymap.cpp:31 #, fuzzy msgid "Go to next article" msgstr "轉到下一篇未讀文章" #: src/keymap.cpp:32 #, fuzzy msgid "Go to previous article" msgstr "轉到前一篇未讀文章" #: src/keymap.cpp:33 msgid "Go to next unread article" msgstr "轉到下一篇未讀文章" #: src/keymap.cpp:34 msgid "Go to previous unread article" msgstr "轉到前一篇未讀文章" #: src/keymap.cpp:35 msgid "Go to a random unread article" msgstr "隨機跳到未讀的文章" #: src/keymap.cpp:36 #, fuzzy msgid "Open article in browser and mark read" msgstr "在瀏覽器裡打開文章" #: src/keymap.cpp:37 msgid "Open article in browser" msgstr "在瀏覽器裡打開文章" #: src/keymap.cpp:38 msgid "Open help dialog" msgstr "打開說明對話框" #: src/keymap.cpp:39 msgid "Toggle source view" msgstr "切換原始碼顯示" #: src/keymap.cpp:40 msgid "Toggle read status for article" msgstr "切換文章的閱讀狀態(已讀/未讀)" #: src/keymap.cpp:41 msgid "Toggle show read feeds/articles" msgstr "切換顯示已讀來源/文章" #: src/keymap.cpp:42 msgid "Show URLs in current article" msgstr "列出當前文章裡的所有鏈結" #: src/keymap.cpp:43 msgid "Clear current tag" msgstr "清除當前標籤" #: src/keymap.cpp:44 src/keymap.cpp:45 msgid "Select tag" msgstr "選擇標籤" #: src/keymap.cpp:46 msgid "Open search dialog" msgstr "打開搜尋對話框" #: src/keymap.cpp:48 msgid "Add download to queue" msgstr "將該下載項目加入隊列" #: src/keymap.cpp:49 msgid "Reload the list of URLs from the configuration" msgstr "重新載入配置文件裡的鏈結列表" #: src/keymap.cpp:50 msgid "Download file" msgstr "下載檔案" #: src/keymap.cpp:51 msgid "Cancel download" msgstr "取消下載" #: src/keymap.cpp:52 msgid "Mark download as deleted" msgstr "將下載的項目標記為已刪除" #: src/keymap.cpp:53 msgid "Purge finished and deleted downloads from queue" msgstr "清除隊列中已完成的和已刪除的下載項目" #: src/keymap.cpp:54 msgid "Toggle automatic download on/off" msgstr "切換是否自動下載" #: src/keymap.cpp:55 msgid "Start player with currently selected download" msgstr "播放當前所選的下載項目" #: src/keymap.cpp:56 msgid "Increase the number of concurrent downloads" msgstr "增加同時下載的數目" #: src/keymap.cpp:57 msgid "Decrease the number of concurrent downloads" msgstr "減少同時下載的數目" #: src/keymap.cpp:58 msgid "Redraw screen" msgstr "更新畫面" #: src/keymap.cpp:59 msgid "Open the commandline" msgstr "打開命令列" #: src/keymap.cpp:60 msgid "Set a filter" msgstr "設置一個過濾器" #: src/keymap.cpp:61 msgid "Select a predefined filter" msgstr "選擇一個預先設定的過濾器" #: src/keymap.cpp:62 msgid "Clear currently set filter" msgstr "清除目前的過濾器" #: src/keymap.cpp:63 msgid "Bookmark current link/article" msgstr "將目前的文章/鏈結加入書籤" #: src/keymap.cpp:64 msgid "Edit flags" msgstr "編輯標記" #: src/keymap.cpp:65 #, fuzzy msgid "Go to next feed" msgstr "跳到下一篇未讀文章" #: src/keymap.cpp:66 #, fuzzy msgid "Go to previous feed" msgstr "跳到前一篇未讀文章" #: src/keymap.cpp:67 msgid "Go to next unread feed" msgstr "跳到下一篇未讀文章" #: src/keymap.cpp:68 msgid "Go to previous unread feed" msgstr "跳到前一篇未讀文章" #: src/keymap.cpp:69 msgid "Call a macro" msgstr "呼叫巨集" #: src/keymap.cpp:70 msgid "Delete article" msgstr "刪除文章" #: src/keymap.cpp:71 msgid "Purge deleted articles" msgstr "清空被刪除的文章" #: src/keymap.cpp:72 msgid "Edit subscribed URLs" msgstr "編緝已訂閱的鏈結" #: src/keymap.cpp:73 msgid "Close currently selected dialog" msgstr "關閉目前選擇的對話窗" #: src/keymap.cpp:74 msgid "View list of open dialogs" msgstr "檢視已開啟對話窗列表" #: src/keymap.cpp:75 msgid "Go to next dialog" msgstr "跳到下一個對話窗" #: src/keymap.cpp:76 msgid "Go to previous dialog" msgstr "跳到前一個對話窗" #: src/keymap.cpp:77 msgid "Pipe article to command" msgstr "Pipe article to command" #: src/keymap.cpp:78 msgid "Sort current list" msgstr "排序列表" #: src/keymap.cpp:79 msgid "Sort current list (reverse)" msgstr "排序列表(反向)" #: src/keymap.cpp:81 msgid "Open URL 10" msgstr "打開網址10" #: src/keymap.cpp:82 msgid "Open URL 1" msgstr "打開網址1" #: src/keymap.cpp:83 msgid "Open URL 2" msgstr "打開網址2" #: src/keymap.cpp:84 msgid "Open URL 3" msgstr "打開網址3" #: src/keymap.cpp:85 msgid "Open URL 4" msgstr "打開網址4" #: src/keymap.cpp:86 msgid "Open URL 5" msgstr "打開網址5" #: src/keymap.cpp:87 msgid "Open URL 6" msgstr "打開網址6" #: src/keymap.cpp:88 msgid "Open URL 7" msgstr "打開網址7" #: src/keymap.cpp:89 msgid "Open URL 8" msgstr "打開網址8" #: src/keymap.cpp:90 msgid "Open URL 9" msgstr "打開網址9" #: src/keymap.cpp:92 msgid "Move to the previous entry" msgstr "跳到前一項" #: src/keymap.cpp:93 msgid "Move to the next entry" msgstr "跳到下一項" #: src/keymap.cpp:94 msgid "Move to the previous page" msgstr "回到前一頁" #: src/keymap.cpp:95 msgid "Move to the next page" msgstr "跳到下一頁" #: src/keymap.cpp:97 msgid "Move to the start of page/list" msgstr "跳到頁面/列表的開始" #: src/keymap.cpp:98 msgid "Move to the end of page/list" msgstr "跳到頁面/列表的最後" #: src/keymap.cpp:294 #, c-format msgid "`%s' is not a valid context" msgstr "`%s' 不是有效的內容" #: src/keymap.cpp:322 #, c-format msgid "`%s' is not a valid key command" msgstr "`%s' 不是有效的按鍵命令" #: src/pb_controller.cpp:164 msgid "Cleaning up queue..." msgstr "清空隊列..." #: src/pb_controller.cpp:177 #, c-format msgid "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n" msgstr "" "%s %s\n" "usage %s [-C ] [-q ] [-h]\n" "-C 裡讀取設定\n" "-q 使用作為隊列檔案\n" "-a 啟動時開始下載\n" "-h 顯示此說明\n" #: src/pb_view.cpp:40 #, c-format msgid " - %u parallel downloads" msgstr " - %u 個平行下載" #: src/pb_view.cpp:44 #, c-format msgid "Queue (%u downloads in progress, %u total) - %.2f kb/s total%s" msgstr "隊列 (%u 個下載在進行中,共有 %u 個下載項目) - 總共 %.2f kb/s %s" #: src/pb_view.cpp:95 msgid "Error: can't quit: download(s) in progress." msgstr "錯誤: 無法取消: 還有下載在進行中" #: src/pb_view.cpp:129 msgid "Error: download needs to be finished before the file can be played." msgstr "錯誤:必須下載完畢才可以播放" #: src/pb_view.cpp:158 msgid "Error: unable to perform operation: download(s) in progress." msgstr "錯誤:無法執行操作:還有下載在進行中" #: src/pb_view.cpp:276 msgid "Download" msgstr "下載" #: src/pb_view.cpp:278 msgid "Delete" msgstr "刪除" #: src/pb_view.cpp:279 msgid "Purge Finished" msgstr "清除完畢的項目" #: src/pb_view.cpp:280 msgid "Toggle Automatic Download" msgstr "切換自動下載" #: src/pb_view.cpp:281 msgid "Play" msgstr "播放" #: src/regexmanager.cpp:41 #, c-format msgid "`%s' is an invalid dialog type" msgstr "`%s' 不是有效的對話類別" #: src/regexmanager.cpp:49 #, c-format msgid "`%s' is not a valid regular expression: %s" msgstr "`%s' 不是一個有效的正規表示式: %s" #: src/rss.cpp:466 msgid "too few arguments" msgstr "參數過少" #: src/rss_parser.cpp:141 #, c-format msgid "Error: unsupported URL: %s" msgstr "錯誤:不支持的鏈結: %s" #: src/select_formaction.cpp:146 src/select_formaction.cpp:166 msgid "Select Tag" msgstr "選擇標籤" #: src/select_formaction.cpp:151 src/select_formaction.cpp:168 msgid "Select Filter" msgstr "選擇過濾器" #: src/tagsouppullparser.cpp:41 msgid "attribute not found" msgstr "未發現屬性" #: src/tagsouppullparser.cpp:123 msgid "EOF found while reading XML tag" msgstr "當讀取XML標籤時遇到EOF標記" #: src/urlview_formaction.cpp:38 src/urlview_formaction.cpp:52 msgid "No link selected!" msgstr "沒有選擇任何鏈結!" #: src/urlview_formaction.cpp:126 msgid "Save Bookmark" msgstr "儲存書籤" #: src/urlview_formaction.cpp:146 msgid "URLs" msgstr "網址" #: src/view.cpp:366 src/view.cpp:386 #, c-format msgid "Error: applying the filter failed: %s" msgstr "錯誤: 套用過濾器失敗: %s" #: src/view.cpp:412 src/view.cpp:439 msgid "Error: feed contains no items!" msgstr "錯誤: 來源裡沒有任何項目!" #: src/view.cpp:421 msgid "Updating query feed..." msgstr "更新查詢的來源..." #: rss/atom_parser.cpp:16 rss/parser.cpp:250 rss/rss_09x_parser.cpp:17 #: rss/rss_09x_parser.cpp:32 rss/rss_10_parser.cpp:15 msgid "XML root node is NULL" msgstr "XML的根節點為無效" #: rss/parser.cpp:69 msgid "couldn't initialize libcurl" msgstr "無法初始化libcurl" #: rss/parser.cpp:132 #, c-format msgid "Error: trying to download feed `%s' returned HTTP status code %ld." msgstr "錯誤:嘗試下載來源`%s' 傳回HTTP狀態代碼 %ld." #: rss/parser.cpp:155 msgid "could not parse buffer" msgstr "無法分析緩衝區" #: rss/parser.cpp:174 msgid "could not parse file" msgstr "無法分析檔案" #: rss/parser.cpp:199 msgid "no RSS version" msgstr "沒有RSS版本" #: rss/parser.cpp:211 msgid "invalid RSS version" msgstr "無效的RSS版本!" #: rss/parser.cpp:226 rss/parser.cpp:233 msgid "invalid Atom version" msgstr "無效的Atom版本!" #: rss/parser.cpp:237 msgid "no Atom version" msgstr "沒有Atom版本" #: rss/parser_factory.cpp:27 msgid "unsupported feed format" msgstr "不支援的來源格式" #: rss/rss_09x_parser.cpp:39 msgid "no RSS channel found" msgstr "找不到RSS頻道" #~ msgid "" #~ "%s %s\n" #~ "usage: %s [-i |-e] [-u ] [-c ] [-x " #~ " ...] [-h]\n" #~ "-e export OPML feed to stdout\n" #~ "-r refresh feeds on start\n" #~ "-i import OPML file\n" #~ "-u read RSS feed URLs from \n" #~ "-c use as cache file\n" #~ "-C read configuration from \n" #~ "-v clean up cache thoroughly\n" #~ "-x ... execute list of commands\n" #~ "-o activate offline mode (only applies to bloglines " #~ "synchronization mode)\n" #~ "-V get version information\n" #~ "-l write a log with a certain loglevel (valid values: 1 to " #~ "6)\n" #~ "-d use as output log file\n" #~ "-E export list of read articles to \n" #~ "-I import list of read articles from \n" #~ "-h this help\n" #~ msgstr "" #~ "%s %s\n" #~ "usage: %s [-i |-e] [-u ] [-c ] [-h]\n" #~ "-e 匯出OPML種子到標準輸出\n" #~ "-r 啟動時更新種子列表\n" #~ "-i 匯入OPML檔案\n" #~ "-u 讀取RSS種子鏈結\n" #~ "-c 使用作為快取檔案\n" #~ "-C 讀取設定\n" #~ "-v 徹底清空快取\n" #~ "-x ... 執行\n" #~ "-o 啟動離線模式(只對bloglines同步模式有效)\n" #~ "-V 顯示版本資訊\n" #~ "-l (有效數值: 1 to 6)記錄日誌\n" #~ "-d 做為輸出的日誌檔\n" #~ "-E 匯出已閱讀文章列表到\n" #~ "-I 匯入已閱讀文章列表\n" #~ "-h 顯示說明\n" newsbeuter-2.7/podbeuter.cpp000066400000000000000000000010571220711462700162470ustar00rootroot00000000000000#include #include #include #include #include #include #include using namespace podbeuter; int main(int argc, char * argv[]) { utils::initialize_ssl_implementation(); if (!setlocale(LC_CTYPE,"") || !setlocale(LC_MESSAGES,"")) { std::cerr << "setlocale failed: " << strerror(errno) << std::endl; return 1; } bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); pb_controller c; podbeuter::pb_view v(&c); c.set_view(&v); c.run(argc, argv); return 0; } newsbeuter-2.7/rss/000077500000000000000000000000001220711462700143565ustar00rootroot00000000000000newsbeuter-2.7/rss/atom_parser.cpp000066400000000000000000000100431220711462700173740ustar00rootroot00000000000000/* rsspp - Copyright (C) 2008-2012 Andreas Krennmair * Licensed under the MIT/X Consortium License. See file LICENSE * for more information. */ #include #include #include #include namespace rsspp { void atom_parser::parse_feed(feed& f, xmlNode * rootNode) { if (!rootNode) throw exception(_("XML root node is NULL")); switch (f.rss_version) { case ATOM_0_3: ns = ATOM_0_3_URI; break; case ATOM_1_0: ns = ATOM_1_0_URI; break; case ATOM_0_3_NONS: ns = NULL; break; default: ns = NULL; break; } f.language = get_prop(rootNode, "lang"); globalbase = get_prop(rootNode, "base", XML_URI); for (xmlNode * node = rootNode->children; node != NULL; node = node->next) { if (node_is(node, "title", ns)) { f.title = get_content(node); f.title_type = get_prop(node, "type"); if (f.title_type == "") f.title_type = "text"; } else if (node_is(node, "subtitle", ns)) { f.description = get_content(node); } else if (node_is(node, "link", ns)) { std::string rel = get_prop(node, "rel"); if (rel == "alternate") { f.link = newsbeuter::utils::absolute_url(globalbase, get_prop(node, "href")); } } else if (node_is(node, "updated", ns)) { f.pubDate = w3cdtf_to_rfc822(get_content(node)); } else if (node_is(node, "entry", ns)) { f.items.push_back(parse_entry(node)); } } } item atom_parser::parse_entry(xmlNode * entryNode) { item it; std::string summary; std::string summary_type; std::string updated; std::string base = get_prop(entryNode, "base", XML_URI); if (base == "") base = globalbase; for (xmlNode * node = entryNode->children; node != NULL; node = node->next) { if (node_is(node, "author", ns)) { for (xmlNode * authornode = node->children; authornode != NULL; authornode = authornode->next) { if (node_is(authornode, "name", ns)) { it.author = get_content(authornode); } // TODO: is there more? } } else if (node_is(node, "title", ns)) { it.title = get_content(node); it.title_type = get_prop(node, "type"); if (it.title_type == "") it.title_type = "text"; } else if (node_is(node, "content", ns)) { std::string mode = get_prop(node, "mode"); std::string type = get_prop(node, "type"); if (mode == "xml" || mode == "") { if (type == "html" || type == "text") { it.description = get_content(node); } else { it.description = get_xml_content(node); } } else if (mode == "escaped") { it.description = get_content(node); } it.description_type = type; if (it.description_type == "") it.description_type = "text"; it.base = get_prop(node, "base", XML_URI); } else if (node_is(node, "id", ns)) { it.guid = get_content(node); it.guid_isPermaLink = false; } else if (node_is(node, "published", ns)) { it.pubDate = w3cdtf_to_rfc822(get_content(node)); } else if (node_is(node, "updated", ns)) { updated = w3cdtf_to_rfc822(get_content(node)); } else if (node_is(node, "link", ns)) { std::string rel = get_prop(node, "rel"); if (rel == "" || rel == "alternate") { it.link = newsbeuter::utils::absolute_url(base, get_prop(node, "href")); } else if (rel == "enclosure") { it.enclosure_url = get_prop(node, "href"); it.enclosure_type = get_prop(node, "type"); } } else if (node_is(node, "summary", ns)) { std::string mode = get_prop(node, "mode"); summary_type = get_prop(node, "type"); if (mode == "xml" || mode == "") { if (summary_type == "html" || summary_type == "text") { summary = get_content(node); } else { summary = get_xml_content(node); } } else if (mode == "escaped") { summary = get_content(node); } if (summary_type == "") summary_type = "text"; } else if (node_is(node, "category", ns) && get_prop(node, "scheme")=="http://www.google.com/reader/") { it.labels.push_back(get_prop(node, "label")); } } // for if (it.description == "") { it.description = summary; it.description_type = summary_type; } if (it.pubDate == "") { it.pubDate = updated; } return it; } } newsbeuter-2.7/rss/exception.cpp000066400000000000000000000006271220711462700170650ustar00rootroot00000000000000/* rsspp - Copyright (C) 2008-2012 Andreas Krennmair * Licensed under the MIT/X Consortium License. See file LICENSE * for more information. */ #include #include namespace rsspp { exception::exception(const std::string& errmsg) : emsg(errmsg) { } exception::~exception() throw() { } const char* exception::what() const throw() { return emsg.c_str(); } } newsbeuter-2.7/rss/parser.cpp000066400000000000000000000200241220711462700163540ustar00rootroot00000000000000/* rsspp - Copyright (C) 2008-2012 Andreas Krennmair * Licensed under the MIT/X Consortium License. See file LICENSE * for more information. */ #include #include #include #include #include #include #include #include #include #include #include using namespace newsbeuter; static size_t my_write_data(void *buffer, size_t size, size_t nmemb, void *userp) { std::string * pbuf = static_cast(userp); pbuf->append(static_cast(buffer), size * nmemb); return size * nmemb; } namespace rsspp { parser::parser(unsigned int timeout, const char * user_agent, const char * proxy, const char * proxy_auth, curl_proxytype proxy_type) : to(timeout), ua(user_agent), prx(proxy), prxauth(proxy_auth), prxtype(proxy_type), doc(0), lm(0) { } parser::~parser() { if (doc) xmlFreeDoc(doc); } struct header_values { time_t lastmodified; std::string etag; header_values() : lastmodified(0) { } }; static size_t handle_headers(void * ptr, size_t size, size_t nmemb, void * data) { char * header = new char[size*nmemb + 1]; header_values * values = (header_values *)data; memcpy(header, ptr, size*nmemb); header[size*nmemb] = '\0'; if (!strncasecmp("Last-Modified:", header, 14)) { time_t r = curl_getdate(header+14, NULL); if (r == -1) { LOG(LOG_DEBUG, "handle_headers: last-modified %s (curl_getdate FAILED)", header+14); } else { values->lastmodified = curl_getdate(header+14, NULL); LOG(LOG_DEBUG, "handle_headers: got last-modified %s (%d)", header+14, values->lastmodified); } } else if (!strncasecmp("ETag:",header, 5)) { values->etag = std::string(header+5); utils::trim(values->etag); LOG(LOG_DEBUG, "handle_headers: got etag %s", values->etag.c_str()); } delete[] header; return size * nmemb; } feed parser::parse_url(const std::string& url, time_t lastmodified, const std::string& etag, newsbeuter::remote_api * api, const std::string& cookie_cache, CURL *ehandle) { std::string buf; CURLcode ret; CURL * easyhandle = ehandle; if (!easyhandle) { easyhandle = curl_easy_init(); if (!easyhandle) { throw exception(_("couldn't initialize libcurl")); } } if (ua) { curl_easy_setopt(easyhandle, CURLOPT_USERAGENT, ua); } if (api) { api->configure_handle(easyhandle); } curl_easy_setopt(easyhandle, CURLOPT_URL, url.c_str()); curl_easy_setopt(easyhandle, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, my_write_data); curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, &buf); curl_easy_setopt(easyhandle, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(easyhandle, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(easyhandle, CURLOPT_MAXREDIRS, 10); curl_easy_setopt(easyhandle, CURLOPT_FAILONERROR, 1); curl_easy_setopt(easyhandle, CURLOPT_ENCODING, "gzip, deflate"); if (cookie_cache != "") { curl_easy_setopt(easyhandle, CURLOPT_COOKIEFILE, cookie_cache.c_str()); curl_easy_setopt(easyhandle, CURLOPT_COOKIEJAR, cookie_cache.c_str()); } if (to != 0) curl_easy_setopt(easyhandle, CURLOPT_TIMEOUT, to); if (prx) curl_easy_setopt(easyhandle, CURLOPT_PROXY, prx); if (prxauth) { curl_easy_setopt(easyhandle, CURLOPT_PROXYAUTH, CURLAUTH_ANY); curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, prxauth); } curl_easy_setopt(easyhandle, CURLOPT_PROXYTYPE, prxtype); header_values hdrs; curl_easy_setopt(easyhandle, CURLOPT_HEADERDATA, &hdrs); curl_easy_setopt(easyhandle, CURLOPT_HEADERFUNCTION, handle_headers); curl_easy_setopt(easyhandle, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE); if (lastmodified != 0) curl_easy_setopt(easyhandle, CURLOPT_TIMEVALUE, lastmodified); else curl_easy_setopt(easyhandle, CURLOPT_TIMEVALUE, 0); curl_slist * custom_headers = NULL; if (etag.length() > 0) { custom_headers = curl_slist_append(custom_headers, utils::strprintf("If-None-Match: %s", etag.c_str()).c_str()); curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, custom_headers); } ret = curl_easy_perform(easyhandle); lm = hdrs.lastmodified; et = hdrs.etag; if (custom_headers) { curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, 0); curl_slist_free_all(custom_headers); } LOG(LOG_DEBUG, "rsspp::parser::parse_url: ret = %d", ret); long status; curl_easy_getinfo(easyhandle, CURLINFO_HTTP_CONNECTCODE, &status); if (status >= 400) { LOG(LOG_USERERROR, _("Error: trying to download feed `%s' returned HTTP status code %ld."), url.c_str(), status); } if (!ehandle) curl_easy_cleanup(easyhandle); if (ret != 0) { LOG(LOG_ERROR, "rsspp::parser::parse_url: curl_easy_perform returned err %d: %s", ret, curl_easy_strerror(ret)); throw exception(curl_easy_strerror(ret)); } LOG(LOG_INFO, "parser::parse_url: retrieved data for %s: %s", url.c_str(), buf.c_str()); if (buf.length() > 0) { LOG(LOG_DEBUG, "parser::parse_url: handing over data to parse_buffer()"); return parse_buffer(buf.c_str(), buf.length(), url.c_str()); } return feed(); } feed parser::parse_buffer(const char * buffer, size_t size, const char * url) { doc = xmlReadMemory(buffer, size, url, NULL, XML_PARSE_RECOVER | XML_PARSE_NOERROR | XML_PARSE_NOWARNING); if (doc == NULL) { throw exception(_("could not parse buffer")); } xmlNode* root_element = xmlDocGetRootElement(doc); feed f = parse_xmlnode(root_element); if (doc->encoding) { f.encoding = (const char *)doc->encoding; } LOG(LOG_INFO, "parser::parse_buffer: encoding = %s", f.encoding.c_str()); return f; } feed parser::parse_file(const std::string& filename) { doc = xmlReadFile(filename.c_str(), NULL, XML_PARSE_RECOVER | XML_PARSE_NOERROR | XML_PARSE_NOWARNING); if (doc == NULL) { throw exception(_("could not parse file")); } xmlNode* root_element = xmlDocGetRootElement(doc); feed f = parse_xmlnode(root_element); if (doc->encoding) { f.encoding = (const char *)doc->encoding; } LOG(LOG_INFO, "parser::parse_file: encoding = %s", f.encoding.c_str()); return f; } feed parser::parse_xmlnode(xmlNode* node) { feed f; if (node) { if (node->name && node->type == XML_ELEMENT_NODE) { if (strcmp((const char *)node->name, "rss")==0) { const char * version = (const char *)xmlGetProp(node, (const xmlChar *)"version"); if (!version) { xmlFree((void *)version); throw exception(_("no RSS version")); } if (strcmp(version, "0.91")==0) f.rss_version = RSS_0_91; else if (strcmp(version, "0.92")==0) f.rss_version = RSS_0_92; else if (strcmp(version, "0.94")==0) f.rss_version = RSS_0_94; else if (strcmp(version, "2.0")==0 || strcmp(version, "2")==0) f.rss_version = RSS_2_0; else { xmlFree((void *)version); throw exception(_("invalid RSS version")); } xmlFree((void *)version); } else if (strcmp((const char *)node->name, "RDF")==0) { f.rss_version = RSS_1_0; } else if (strcmp((const char *)node->name, "feed")==0) { if (node->ns && node->ns->href) { if (strcmp((const char *)node->ns->href, ATOM_0_3_URI)==0) { f.rss_version = ATOM_0_3; } else if (strcmp((const char *)node->ns->href, ATOM_1_0_URI)==0) { f.rss_version = ATOM_1_0; } else { const char * version = (const char *)xmlGetProp(node, (const xmlChar *)"version"); if (!version) { xmlFree((void *)version); throw exception(_("invalid Atom version")); } if (strcmp(version, "0.3")==0) { xmlFree((void *)version); f.rss_version = ATOM_0_3_NONS; } else { xmlFree((void *)version); throw exception(_("invalid Atom version")); } } } else { throw exception(_("no Atom version")); } } std::tr1::shared_ptr parser = rss_parser_factory::get_object(f, doc); try { parser->parse_feed(f, node); } catch (exception& e) { throw; } } } else { throw exception(_("XML root node is NULL")); } return f; } void parser::global_init() { LIBXML_TEST_VERSION curl_global_init(CURL_GLOBAL_ALL); } void parser::global_cleanup() { xmlCleanupParser(); curl_global_cleanup(); } } newsbeuter-2.7/rss/parser_factory.cpp000066400000000000000000000015171220711462700201110ustar00rootroot00000000000000/* rsspp - Copyright (C) 2008-2012 Andreas Krennmair * Licensed under the MIT/X Consortium License. See file LICENSE * for more information. */ #include #include namespace rsspp { std::tr1::shared_ptr rss_parser_factory::get_object(feed& f, xmlDocPtr doc) { switch (f.rss_version) { case RSS_0_91: case RSS_0_92: case RSS_0_94: return std::tr1::shared_ptr(new rss_09x_parser(doc)); case RSS_2_0: return std::tr1::shared_ptr(new rss_20_parser(doc)); case RSS_1_0: return std::tr1::shared_ptr(new rss_10_parser(doc)); case ATOM_0_3: case ATOM_0_3_NONS: case ATOM_1_0: return std::tr1::shared_ptr(new atom_parser(doc)); case UNKNOWN: default: throw exception(_("unsupported feed format")); } } } newsbeuter-2.7/rss/rss_09x_parser.cpp000066400000000000000000000076571220711462700177640ustar00rootroot00000000000000/* rsspp - Copyright (C) 2008-2012 Andreas Krennmair * Licensed under the MIT/X Consortium License. See file LICENSE * for more information. */ #include #include #include #include using namespace newsbeuter; namespace rsspp { void rss_20_parser::parse_feed(feed& f, xmlNode * rootNode) { if (!rootNode) throw exception(_("XML root node is NULL")); const char * ns = rootNode->ns ? (const char *)rootNode->ns->href : NULL; //(const char *)xmlGetProp(rootNode, (const xmlChar *)"xmlns"); if (ns != NULL) { if (strcmp(ns, RSS20USERLAND_URI) == 0) { this->ns = strdup(ns); } } rss_09x_parser::parse_feed(f, rootNode); } void rss_09x_parser::parse_feed(feed& f, xmlNode * rootNode) { if (!rootNode) throw exception(_("XML root node is NULL")); xmlNode * channel = rootNode->children; while (channel && strcmp((const char *)channel->name, "channel")!=0) channel = channel->next; if (!channel) throw exception(_("no RSS channel found")); for (xmlNode * node = channel->children; node != NULL; node = node->next) { if (node_is(node, "title", ns)) { f.title = get_content(node); f.title_type = "text"; } else if (node_is(node, "link", ns)) { f.link = get_content(node); } else if (node_is(node, "description", ns)) { f.description = get_content(node); } else if (node_is(node, "language", ns)) { f.language = get_content(node); } else if (node_is(node, "managingEditor", ns)) { f.managingeditor = get_content(node); } else if (node_is(node, "item", ns)) { f.items.push_back(parse_item(node)); } } } item rss_09x_parser::parse_item(xmlNode * itemNode) { item it; std::string author; std::string dc_date; for (xmlNode * node = itemNode->children; node != NULL; node = node->next) { if (node_is(node, "title", ns)) { it.title = get_content(node); it.title_type = "text"; } else if (node_is(node, "link", ns)) { it.link = get_content(node); } else if (node_is(node, "description", ns)) { it.description = get_content(node); } else if (node_is(node, "encoded", CONTENT_URI)) { it.content_encoded = get_content(node); } else if (node_is(node, "summary", ITUNES_URI)) { it.itunes_summary = get_content(node); } else if (node_is(node, "guid", ns)) { it.guid = get_content(node); it.guid_isPermaLink = true; std::string isPermaLink = get_prop(node,"isPermaLink"); if (isPermaLink == "false") it.guid_isPermaLink = false; } else if (node_is(node, "pubDate", ns)) { it.pubDate = get_content(node); } else if (node_is(node, "date", DC_URI)) { dc_date = w3cdtf_to_rfc822(get_content(node)); } else if (node_is(node, "author", ns)) { std::string authorfield = get_content(node); if (authorfield[authorfield.length()-1] == ')') { it.author_email = newsbeuter::utils::tokenize(authorfield, " ")[0]; unsigned int start, end; end = authorfield.length()-2; for (start = end;start > 0 && authorfield[start] != '(';start--) { } it.author = authorfield.substr(start+1, end-start); } else { it.author_email = authorfield; it.author = authorfield; } } else if (node_is(node, "creator", DC_URI)) { author = get_content(node); } else if (node_is(node, "enclosure", ns)) { it.enclosure_url = get_prop(node, "url"); it.enclosure_type = get_prop(node, "type"); } else if (node_is(node, "content", MEDIA_RSS_URI)) { it.enclosure_url = get_prop(node, "url"); it.enclosure_type = get_prop(node, "type"); } else if (node_is(node, "group", MEDIA_RSS_URI)) { for (xmlNode * mnode = node->children; mnode != NULL; mnode = mnode->next) { if (node_is(mnode, "content", MEDIA_RSS_URI)) { it.enclosure_url = get_prop(mnode, "url"); it.enclosure_type = get_prop(mnode, "type"); } } } } if (it.author == "") { it.author = author; } if (it.pubDate == "") { it.pubDate = dc_date; } return it; } rss_09x_parser::~rss_09x_parser() { free((void *)ns); } } newsbeuter-2.7/rss/rss_10_parser.cpp000066400000000000000000000037241220711462700175530ustar00rootroot00000000000000/* rsspp - Copyright (C) 2008-2012 Andreas Krennmair * Licensed under the MIT/X Consortium License. See file LICENSE * for more information. */ #include #include #include #define RSS_1_0_NS "http://purl.org/rss/1.0/" namespace rsspp { void rss_10_parser::parse_feed(feed& f, xmlNode * rootNode) { if (!rootNode) throw exception(_("XML root node is NULL")); for (xmlNode * node = rootNode->children; node != NULL; node = node->next) { if (node_is(node, "channel", RSS_1_0_NS)) { for (xmlNode * cnode = node->children; cnode != NULL; cnode = cnode->next) { if (node_is(cnode, "title", RSS_1_0_NS)) { f.title = get_content(cnode); f.title_type = "text"; } else if (node_is(cnode, "link", RSS_1_0_NS)) { f.link = get_content(cnode); } else if (node_is(cnode, "description", RSS_1_0_NS)) { f.description = get_content(cnode); } else if (node_is(cnode, "date", DC_URI)) { f.pubDate = w3cdtf_to_rfc822(get_content(cnode)); } else if (node_is(cnode, "creator", DC_URI)) { f.dc_creator = get_content(cnode); } } } else if (node_is(node, "item", RSS_1_0_NS)) { item it; it.guid = get_prop(node, "about", RDF_URI); for (xmlNode * itnode = node->children; itnode != NULL; itnode = itnode->next) { if (node_is(itnode, "title", RSS_1_0_NS)) { it.title = get_content(itnode); it.title_type = "text"; } else if (node_is(itnode, "link", RSS_1_0_NS)) { it.link = get_content(itnode); } else if (node_is(itnode, "description", RSS_1_0_NS)) { it.description = get_content(itnode); } else if (node_is(itnode, "date", DC_URI)) { it.pubDate = w3cdtf_to_rfc822(get_content(itnode)); } else if (node_is(itnode, "encoded", CONTENT_URI)) { it.content_encoded = get_content(itnode); } else if (node_is(itnode, "summary", ITUNES_URI)) { it.itunes_summary = get_content(itnode); } } f.items.push_back(it); } } } } newsbeuter-2.7/rss/rss_parser.cpp000066400000000000000000000055531220711462700172550ustar00rootroot00000000000000/* rsspp - Copyright (C) 2008-2012 Andreas Krennmair * Licensed under the MIT/X Consortium License. See file LICENSE * for more information. */ #include #include #include namespace rsspp { std::string rss_parser::get_content(xmlNode * node) { std::string retval; if (node) { xmlChar * content = xmlNodeGetContent(node); if (content) { retval = (const char *)content; xmlFree(content); } } return retval; } std::string rss_parser::get_xml_content(xmlNode * node) { xmlBufferPtr buf = xmlBufferCreate(); std::string result; if (node->children) { for (xmlNodePtr ptr = node->children; ptr != NULL; ptr = ptr->next) { if (xmlNodeDump(buf, doc, ptr, 0, 0) >= 0) { result.append((const char *)xmlBufferContent(buf)); xmlBufferEmpty(buf); } else { result.append(get_content(ptr)); } } } else { result = get_content(node); // fallback } xmlBufferFree(buf); return result; } std::string rss_parser::get_prop(xmlNode * node, const char * prop, const char * ns) { std::string retval; if (node) { xmlChar * value; if (ns) value = xmlGetProp(node, (xmlChar *)prop); else value = xmlGetNsProp(node, (xmlChar *)prop, (xmlChar *)ns); if (value) { retval = (const char*)value; xmlFree(value); } } return retval; } std::string rss_parser::w3cdtf_to_rfc822(const std::string& w3cdtf) { return __w3cdtf_to_rfc822(w3cdtf); } std::string rss_parser::__w3cdtf_to_rfc822(const std::string& w3cdtf) { struct tm stm; memset(&stm, 0, sizeof (stm)); stm.tm_mday = 1; //ptr = strptime(w3cdtf.c_str(), "%Y-%m-%dT%H:%M:%S", &stm); char * ptr = strptime(w3cdtf.c_str(), "%Y", &stm); if (ptr != NULL) { ptr = strptime(ptr, "-%m", &stm); } else { return ""; } if (ptr != NULL) { ptr = strptime(ptr, "-%d", &stm); } if (ptr != NULL) { ptr = strptime(ptr, "T%H", &stm); } if (ptr != NULL) { ptr = strptime(ptr, ":%M", &stm); } if (ptr != NULL) { ptr = strptime(ptr, ":%S", &stm); } int offs = 0; if (ptr != NULL) { if (ptr[0] == '+' || ptr[0] == '-') { unsigned int hour, min; if (sscanf(ptr+1,"%02u:%02u", &hour, &min)==2) { offs = 60*60*hour + 60*min; if (ptr[0] == '+') offs = -offs; stm.tm_gmtoff = offs; } } else if (ptr[0] == 'Z') { stm.tm_gmtoff = 0; } } time_t t = mktime(&stm); time_t x = time(NULL); t += localtime(&x)->tm_gmtoff + offs; char datebuf[256]; strftime (datebuf, sizeof (datebuf), "%a, %d %b %Y %H:%M:%S %z", gmtime(&t)); return datebuf; } bool rss_parser::node_is(xmlNode * node, const char * name, const char * ns_uri) { if (!node || !name || !node->name) return false; if (strcmp((const char *)node->name, name)==0) { if (!ns_uri && !node->ns) return true; if (ns_uri && node->ns && node->ns->href && strcmp((const char *)node->ns->href, ns_uri)==0) return true; } return false; } } newsbeuter-2.7/rss/rsspp.h000066400000000000000000000044741220711462700157070ustar00rootroot00000000000000/* rsspp - Copyright (C) 2008-2012 Andreas Krennmair * Licensed under the MIT/X Consortium License. See file LICENSE * for more information. */ #ifndef RSSPP_H #define RSSPP_H #include #include #include #include #include #include namespace rsspp { enum version { UNKNOWN = 0, RSS_0_91, RSS_0_92, RSS_1_0, RSS_2_0, ATOM_0_3, ATOM_1_0, RSS_0_94, ATOM_0_3_NONS, TTRSS_JSON }; struct item { std::string title; std::string title_type; std::string link; std::string description; std::string description_type; std::string author; std::string author_email; std::string pubDate; std::string guid; bool guid_isPermaLink; std::string enclosure_url; std::string enclosure_type; // extensions: std::string content_encoded; std::string itunes_summary; // Atom-specific: std::string base; std::vector labels; // only required for ttrss support: time_t pubDate_ts; }; struct feed { std::string encoding; version rss_version; std::string title; std::string title_type; std::string description; std::string link; std::string language; std::string managingeditor; std::string dc_creator; std::string pubDate; std::vector items; }; class exception : public std::exception { public: exception(const std::string& errmsg = ""); ~exception() throw(); virtual const char* what() const throw(); private: std::string emsg; }; class parser { public: parser(unsigned int timeout = 30, const char * user_agent = 0, const char * proxy = 0, const char * proxy_auth = 0, curl_proxytype proxy_type = CURLPROXY_HTTP); ~parser(); feed parse_url(const std::string& url, time_t lastmodified = 0, const std::string& etag = "", newsbeuter::remote_api * api = 0, const std::string& cookie_cache = "", CURL *ehandle = 0); feed parse_buffer(const char * buffer, size_t size, const char * url = NULL); feed parse_file(const std::string& filename); time_t get_last_modified() { return lm; } const std::string& get_etag() { return et; } static void global_init(); static void global_cleanup(); private: feed parse_xmlnode(xmlNode * node); unsigned int to; const char * ua; const char * prx; const char * prxauth; curl_proxytype prxtype; xmlDocPtr doc; time_t lm; std::string et; }; } #endif newsbeuter-2.7/rss/rsspp_internal.h000066400000000000000000000045561220711462700176040ustar00rootroot00000000000000/* rsspp - Copyright (C) 2008-2012 Andreas Krennmair * Licensed under the MIT/X Consortium License. See file LICENSE * for more information. */ #ifndef RSSPP_INTERNAL__H #define RSSPP_INTERNAL__H #include #include #define CONTENT_URI "http://purl.org/rss/1.0/modules/content/" #define RDF_URI "http://www.w3.org/1999/02/22-rdf-syntax-ns#" #define ITUNES_URI "http://www.itunes.com/dtds/podcast-1.0.dtd" #define DC_URI "http://purl.org/dc/elements/1.1/" #define ATOM_0_3_URI "http://purl.org/atom/ns#" #define ATOM_1_0_URI "http://www.w3.org/2005/Atom" #define MEDIA_RSS_URI "http://search.yahoo.com/mrss/" #define XML_URI "http://www.w3.org/XML/1998/namespace" #define RSS20USERLAND_URI "http://backend.userland.com/rss2" namespace rsspp { struct rss_parser { virtual void parse_feed(feed& f, xmlNode * rootNode) = 0; rss_parser(xmlDocPtr d) : doc(d) { } virtual ~rss_parser() { } static std::string __w3cdtf_to_rfc822(const std::string& w3cdtf); protected: std::string get_content(xmlNode * node); std::string get_xml_content(xmlNode * node); std::string get_prop(xmlNode * node, const char * prop, const char * ns = NULL); std::string w3cdtf_to_rfc822(const std::string& w3cdtf); bool node_is(xmlNode * node, const char * name, const char * ns_uri = NULL); xmlDocPtr doc; }; struct rss_09x_parser : public rss_parser { virtual void parse_feed(feed& f, xmlNode * rootNode); rss_09x_parser(xmlDocPtr doc) : rss_parser(doc), ns(NULL) { } virtual ~rss_09x_parser(); protected: const char * ns; private: item parse_item(xmlNode * itemNode); }; struct rss_20_parser : public rss_09x_parser { rss_20_parser(xmlDocPtr doc) : rss_09x_parser(doc) { } virtual void parse_feed(feed& f, xmlNode * rootNode); virtual ~rss_20_parser() { } }; struct rss_10_parser : public rss_parser { virtual void parse_feed(feed& f, xmlNode * rootNode); rss_10_parser(xmlDocPtr doc) : rss_parser(doc) { } virtual ~rss_10_parser() { } }; struct atom_parser : public rss_parser { virtual void parse_feed(feed& f, xmlNode * rootNode); atom_parser(xmlDocPtr doc) : rss_parser(doc), ns(0) { } virtual ~atom_parser() { } private: item parse_entry(xmlNode * itemNode); std::string globalbase; const char * ns; }; struct rss_parser_factory { static std::tr1::shared_ptr get_object(feed& f, xmlDocPtr doc); }; } #endif newsbeuter-2.7/src/000077500000000000000000000000001220711462700143365ustar00rootroot00000000000000newsbeuter-2.7/src/cache.cpp000066400000000000000000001120571220711462700161130ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace newsbeuter { struct cb_handler { cb_handler() : c(-1) { } void set_count(int i) { c = i; } int count() { return c; } private: int c; }; struct header_values { time_t lastmodified; std::string etag; }; static int count_callback(void * handler, int argc, char ** argv, char ** /* azColName */) { cb_handler * cbh = static_cast(handler); if (argc>0) { std::istringstream is(argv[0]); int x; is >> x; cbh->set_count(x); } return 0; } static int single_string_callback(void * handler, int argc, char ** argv, char ** /* azColName */) { std::string * value = reinterpret_cast(handler); if (argc>0 && argv[0]) { *value = argv[0]; } return 0; } static int rssfeed_callback(void * myfeed, int argc, char ** argv, char ** /* azColName */) { std::tr1::shared_ptr* feed = static_cast* >(myfeed); // normaly, this shouldn't happen, but we keep the assert()s here nevertheless assert(argc == 3); assert(argv[0] != NULL); assert(argv[1] != NULL); assert(argv[2] != NULL); (*feed)->set_title(argv[0]); (*feed)->set_link(argv[1]); (*feed)->set_rtl(strcmp(argv[2],"1")==0); LOG(LOG_INFO, "rssfeed_callback: title = %s link = %s is_rtl = %s",argv[0],argv[1], argv[2]); return 0; } static int lastmodified_callback(void * handler, int argc, char ** argv, char ** /* azColName */) { header_values * result = static_cast(handler); assert(argc == 2); assert(result != NULL); if (argv[0]) { std::istringstream is(argv[0]); is >> result->lastmodified; } else { result->lastmodified = 0; } if (argv[1]) { result->etag = argv[1]; } else { result->etag = ""; } LOG(LOG_INFO, "lastmodified_callback: lastmodified = %d etag = %s", result->lastmodified, result->etag.c_str()); return 0; } static int vectorofstring_callback(void * vp, int argc, char ** argv, char ** /* azColName */) { std::vector * vectorptr = static_cast *>(vp); assert(argc == 1); assert(argv[0] != NULL); vectorptr->push_back(std::string(argv[0])); LOG(LOG_INFO, "vectorofstring_callback: element = %s", argv[0]); return 0; } static int rssitem_callback(void * myfeed, int argc, char ** argv, char ** /* azColName */) { std::tr1::shared_ptr* feed = static_cast* >(myfeed); assert (argc == 13); std::tr1::shared_ptr item(new rss_item(NULL)); item->set_guid(argv[0]); item->set_title(argv[1]); item->set_author(argv[2]); item->set_link(argv[3]); std::istringstream is(argv[4]); time_t t; is >> t; item->set_pubDate(t); item->set_size(utils::to_u(argv[5])); item->set_unread((std::string("1") == argv[6])); item->set_feedurl(argv[7]); item->set_enclosure_url(argv[8] ? argv[8] : ""); item->set_enclosure_type(argv[9] ? argv[9] : ""); item->set_enqueued((std::string("1") == (argv[10] ? argv[10] : ""))); item->set_flags(argv[11] ? argv[11] : ""); item->set_base(argv[12] ? argv[12] : ""); //(*feed)->items().push_back(item); (*feed)->add_item(item); return 0; } static int fill_content_callback(void * myfeed, int argc, char ** argv, char ** /* azColName */) { rss_feed * feed = static_cast(myfeed); assert(argc == 2); if (argv[0]) { std::tr1::shared_ptr item = feed->get_item_by_guid_unlocked(argv[0]); item->set_description(argv[1] ? argv[1] : ""); } return 0; } static int search_item_callback(void * myfeed, int argc, char ** argv, char ** /* azColName */) { std::vector > * items = static_cast > *>(myfeed); assert (argc == 13); std::tr1::shared_ptr item(new rss_item(NULL)); item->set_guid(argv[0]); item->set_title(argv[1]); item->set_author(argv[2]); item->set_link(argv[3]); std::istringstream is(argv[4]); time_t t; is >> t; item->set_pubDate(t); item->set_size(utils::to_u(argv[5])); item->set_unread((std::string("1") == argv[6])); item->set_feedurl(argv[7]); item->set_enclosure_url(argv[8] ? argv[8] : ""); item->set_enclosure_type(argv[9] ? argv[9] : ""); item->set_enqueued((std::string("1") == argv[10])); item->set_flags(argv[11] ? argv[11] : ""); item->set_base(argv[12] ? argv[12] : ""); items->push_back(item); return 0; } cache::cache(const std::string& cachefile, configcontainer * c) : db(0),cfg(c) { int error = sqlite3_open(cachefile.c_str(),&db); if (error != SQLITE_OK) { LOG(LOG_ERROR,"couldn't sqlite3_open(%s): error = %d", cachefile.c_str(), error); throw dbexception(db); } populate_tables(); set_pragmas(); clean_old_articles(); // we need to manually lock all DB operations because SQLite has no explicit support for multithreading. } cache::~cache() { sqlite3_close(db); } void cache::set_pragmas() { int rc; // first, we need to swithc off synchronous writing as it's slow as hell rc = sqlite3_exec(db, "PRAGMA synchronous = OFF;", NULL, NULL, NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"setting PRAGMA synchronous = OFF failed"); throw dbexception(db); } // then we disable case-sensitive matching for the LIKE operator in SQLite, for search operations rc = sqlite3_exec(db, "PRAGMA case_sensitive_like=OFF;", NULL, NULL, NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"setting PRAGMA case_sensitive_like = OFF failed"); throw dbexception(db); } } void cache::populate_tables() { int rc; rc = sqlite3_exec(db,"CREATE TABLE rss_feed ( " " rssurl VARCHAR(1024) PRIMARY KEY NOT NULL, " " url VARCHAR(1024) NOT NULL, " " title VARCHAR(1024) NOT NULL ); " , NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: CREATE TABLE rss_feed rc = %d", rc); rc = sqlite3_exec(db,"CREATE TABLE rss_item ( " " id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " " guid VARCHAR(64) NOT NULL, " " title VARCHAR(1024) NOT NULL, " " author VARCHAR(1024) NOT NULL, " " url VARCHAR(1024) NOT NULL, " " feedurl VARCHAR(1024) NOT NULL, " " pubDate INTEGER NOT NULL, " " content VARCHAR(65535) NOT NULL," " unread INTEGER(1) NOT NULL );", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: CREATE TABLE rss_item rc = %d", rc); rc = sqlite3_exec(db, "CREATE TABLE google_replay ( " " id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " " guid VARCHAR(64) NOT NULL, " " state INTEGER NOT NULL, " " ts INTEGER NOT NULL );", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: CREATE TABLE google_replay rc = %d", rc); /* we need to do these ALTER TABLE statements because we need to store additional data for the podcast support */ rc = sqlite3_exec(db, "ALTER TABLE rss_item ADD enclosure_url VARCHAR(1024);", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: ALTER TABLE rss_item (1) rc = %d", rc); rc = sqlite3_exec(db, "ALTER TABLE rss_item ADD enclosure_type VARCHAR(1024);", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: ALTER TABLE rss_item (2) rc = %d", rc); rc = sqlite3_exec(db, "ALTER TABLE rss_item ADD enqueued INTEGER(1) NOT NULL DEFAULT 0;", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: ALTER TABLE rss_item (3) rc = %d", rc); rc = sqlite3_exec(db, "ALTER TABLE rss_item ADD flags VARCHAR(52);", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: ALTER TABLE rss_item (4) rc = %d", rc); /* create indexes to speed up certain queries */ rc = sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS idx_rssurl ON rss_feed(rssurl);", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: CREATE INDEX ON rss_feed(rssurl) (4) rc = %d", rc); rc = sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS idx_guid ON rss_item(guid);", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: CREATE INDEX ON rss_item(guid) (5) rc = %d", rc); rc = sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS idx_feedurl ON rss_item(feedurl);", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: CREATE INDEX ON rss_item(feedurl) (5) rc = %d", rc); if(rc == SQLITE_OK){ /* we analyse the indices for better statistics */ rc = sqlite3_exec(db, "ANALYZE;", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: ANALYZE indices (6) rc = %d", rc); } rc = sqlite3_exec(db, "ALTER TABLE rss_feed ADD lastmodified INTEGER(11) NOT NULL DEFAULT 0;", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: ALTER TABLE rss_feed ADD lastmodified: rc = %d", rc); rc = sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS idx_lastmodified ON rss_feed(lastmodified);", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: CREATE INDEX ON rss_feed(lastmodified) rc = %d", rc); rc = sqlite3_exec(db, "ALTER TABLE rss_item ADD deleted INTEGER(1) NOT NULL DEFAULT 0;", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: ALTER TABLE rss_item (7) rc = %d", rc); rc = sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS idx_deleted ON rss_item(deleted);", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: CREATE INDEX ON rss_item(deleted) rc = %d", rc); rc = sqlite3_exec(db, "ALTER TABLE rss_feed ADD is_rtl INTEGER(1) NOT NULL DEFAULT 0;", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: ALTER TABLE rss_feed (8) rc = %d", rc); rc = sqlite3_exec(db, "ALTER TABLE rss_feed ADD etag VARCHAR(128) NOT NULL DEFAULT \"\";", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: ALTER TABLE rss_feed (9) rc = %d", rc); rc = sqlite3_exec(db, "ALTER TABLE rss_item ADD base VARCHAR(128) NOT NULL DEFAULT \"\";", NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::populate_tables: ALTER TABLE rss_feed(10) rc = %d", rc); } void cache::fetch_lastmodified(const std::string& feedurl, time_t& t, std::string& etag) { scope_mutex lock(&mtx); std::string query = prepare_query("SELECT lastmodified, etag FROM rss_feed WHERE rssurl = '%q';", feedurl.c_str()); LOG(LOG_DEBUG, "running: query: %s", query.c_str()); header_values result = { 0, "" }; int rc = sqlite3_exec(db, query.c_str(), lastmodified_callback, &result, NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL, "query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } t = result.lastmodified; etag = result.etag; LOG(LOG_DEBUG, "cache::fetch_lastmodified: t = %d etag = %s", t, etag.c_str()); } void cache::update_lastmodified(const std::string& feedurl, time_t t, const std::string& etag) { if (t == 0 && etag.length() == 0) { LOG(LOG_INFO, "cache::update_lastmodified: both time and etag are empty, not updating anything"); return; } scope_mutex lock(&mtx); std::string query = "UPDATE rss_feed SET "; if (t > 0) query.append(utils::strprintf("lastmodified = '%d'", t)); if (etag.length() > 0) query.append(utils::strprintf("%c etag = %s", (t > 0 ? ',' : ' '), prepare_query("'%q'", etag.c_str()).c_str())); query.append(" WHERE rssurl = "); query.append(prepare_query("'%q'", feedurl.c_str())); int rc = sqlite3_exec(db, query.c_str(), NULL, NULL, NULL); LOG(LOG_DEBUG, "ran SQL statement: %s result = %d", query.c_str(), rc); } void cache::mark_item_deleted(const std::string& guid, bool b) { scope_mutex lock(&mtx); std::string query = prepare_query("UPDATE rss_item SET deleted = %u WHERE guid = '%q'", b ? 1 : 0, guid.c_str()); int rc = sqlite3_exec(db, query.c_str(), NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::mark_item_deleted ran SQL statement: %s result = %d", query.c_str(), rc); } std::vector cache::get_feed_urls() { scope_mutex lock(&mtx); std::string query = "SELECT rssurl FROM rss_feed;"; std::vector urls; int rc = sqlite3_exec(db, query.c_str(), vectorofstring_callback,&urls, NULL); assert(rc == SQLITE_OK); return urls; } // this function writes an rss_feed including all rss_items to the database void cache::externalize_rssfeed(std::tr1::shared_ptr feed, bool reset_unread) { scope_measure m1("cache::externalize_feed"); if (feed->rssurl().substr(0,6) == "query:") return; scope_mutex lock(&mtx); scope_mutex feedlock(&feed->item_mutex); //scope_transaction dbtrans(db); cb_handler count_cbh; int rc = sqlite3_exec(db,prepare_query("SELECT count(*) FROM rss_feed WHERE rssurl = '%q';", feed->rssurl().c_str()).c_str(),count_callback,&count_cbh,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query failed: error = %d", rc); throw dbexception(db); } int count = count_cbh.count(); LOG(LOG_DEBUG, "cache::externalize_rss_feed: rss_feeds with rssurl = '%s': found %d",feed->rssurl().c_str(), count); if (count > 0) { std::string updatequery = prepare_query("UPDATE rss_feed SET title = '%q', url = '%q', is_rtl = %u WHERE rssurl = '%q';", feed->title_raw().c_str(),feed->link().c_str(), feed->is_rtl() ? 1 : 0, feed->rssurl().c_str()); rc = sqlite3_exec(db,updatequery.c_str(),NULL,NULL,NULL); LOG(LOG_DEBUG,"ran SQL statement: %s", updatequery.c_str()); } else { std::string insertquery = prepare_query("INSERT INTO rss_feed (rssurl, url, title, is_rtl) VALUES ( '%q', '%q', '%q', %u );", feed->rssurl().c_str(), feed->link().c_str(), feed->title_raw().c_str(), feed->is_rtl() ? 1 : 0); rc = sqlite3_exec(db,insertquery.c_str(),NULL,NULL,NULL); LOG(LOG_DEBUG,"ran SQL statement: %s", insertquery.c_str()); } unsigned int max_items = cfg->get_configvalue_as_int("max-items"); LOG(LOG_INFO, "cache::externalize_feed: max_items = %u feed.items().size() = %u", max_items, feed->total_item_count()); if (max_items > 0 && feed->items().size() > max_items) { std::vector >::iterator it=feed->items().begin(); for (unsigned int i=0;iitems().end()) feed->erase_items(it, feed->items().end()); // delete entries that are too much } unsigned int days = cfg->get_configvalue_as_int("keep-articles-days"); time_t old_time = time(NULL) - days * 24*60*60; // the reverse iterator is there for the sorting foo below (think about it) for (std::vector >::reverse_iterator it=feed->items().rbegin(); it != feed->items().rend(); ++it) { if (days == 0 || (*it)->pubDate_timestamp() >= old_time) update_rssitem_unlocked(*it, feed->rssurl(), reset_unread); } } // this function reads an rss_feed including all of its rss_items. // the feed parameter needs to have the rssurl member set. void cache::internalize_rssfeed(std::tr1::shared_ptr feed, rss_ignores * ign) { scope_measure m1("cache::internalize_rssfeed"); if (feed->rssurl().substr(0,6) == "query:") return; scope_mutex lock(&mtx); scope_mutex feedlock(&feed->item_mutex); /* first, we check whether the feed is there at all */ std::string query = prepare_query("SELECT count(*) FROM rss_feed WHERE rssurl = '%q';",feed->rssurl().c_str()); cb_handler count_cbh; LOG(LOG_DEBUG,"running query: %s",query.c_str()); int rc = sqlite3_exec(db,query.c_str(),count_callback,&count_cbh,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } if (count_cbh.count() == 0) { return; } /* then we first read the feed from the database */ query = prepare_query("SELECT title, url, is_rtl FROM rss_feed WHERE rssurl = '%q';",feed->rssurl().c_str()); LOG(LOG_DEBUG,"running query: %s",query.c_str()); rc = sqlite3_exec(db,query.c_str(),rssfeed_callback,&feed,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } feed->clear_items(); /* ...and then the associated items */ query = prepare_query("SELECT guid,title,author,url,pubDate,length(content),unread,feedurl,enclosure_url,enclosure_type,enqueued,flags,base FROM rss_item WHERE feedurl = '%q' AND deleted = 0 ORDER BY pubDate DESC, id DESC;",feed->rssurl().c_str()); LOG(LOG_DEBUG,"running query: %s",query.c_str()); rc = sqlite3_exec(db,query.c_str(),rssitem_callback,&feed,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } unsigned int i=0; for (std::vector >::iterator it=feed->items().begin(); it != feed->items().end(); ++it,++i) { (*it)->set_cache(this); (*it)->set_feedptr(feed); (*it)->set_feedurl(feed->rssurl()); if (ign && ign->matches(it->get())) { feed->erase_item(it); // since we modified the vector, we need to reset the iterator // to the beginning of the vector, and then fast-forward to // the next element. it = feed->items().begin(); --i; for (int j=0;jget_configvalue_as_int("max-items"); if (max_items > 0 && feed->items().size() > max_items) { std::vector > flagged_items; std::vector >::iterator it=feed->items().begin(); for (unsigned int i=0;iitems().size();++i) { if (feed->items()[i]->flags().length() == 0) { delete_item(feed->items()[i]); } else { flagged_items.push_back(feed->items()[i]); } } feed->erase_items(it, feed->items().end()); // delete old entries if (flagged_items.size() > 0) { // if some flagged articles were saved, append them for (std::vector >::iterator jt=flagged_items.begin();jt!=flagged_items.end();++jt) { feed->add_item(*jt); } } } feed->sort_unlocked(cfg->get_configvalue("article-sort-order")); } std::vector > cache::search_for_items(const std::string& querystr, const std::string& feedurl) { std::string query; std::vector > items; int rc; scope_mutex lock(&mtx); if (feedurl.length() > 0) { query = prepare_query("SELECT guid,title,author,url,pubDate,length(content),unread,feedurl,enclosure_url,enclosure_type,enqueued,flags,base FROM rss_item WHERE (title LIKE '%%%q%%' OR content LIKE '%%%q%%') AND feedurl = '%q' AND deleted = 0 ORDER BY pubDate DESC, id DESC;",querystr.c_str(), querystr.c_str(), feedurl.c_str()); } else { query = prepare_query("SELECT guid,title,author,url,pubDate,length(content),unread,feedurl,enclosure_url,enclosure_type,enqueued,flags,base FROM rss_item WHERE (title LIKE '%%%q%%' OR content LIKE '%%%q%%') AND deleted = 0 ORDER BY pubDate DESC, id DESC;",querystr.c_str(), querystr.c_str()); } LOG(LOG_DEBUG,"running query: %s",query.c_str()); rc = sqlite3_exec(db,query.c_str(),search_item_callback,&items,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } return items; } void cache::delete_item(const std::tr1::shared_ptr item) { std::string query = prepare_query("DELETE FROM rss_item WHERE guid = '%q';",item->guid().c_str()); LOG(LOG_DEBUG,"running query: %s",query.c_str()); int rc = sqlite3_exec(db,query.c_str(),NULL,NULL,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } } void cache::do_vacuum() { scope_mutex lock(&mtx); const char * vacuum_query = "VACUUM;"; int rc = sqlite3_exec(db,vacuum_query,NULL,NULL,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", vacuum_query, rc); } } void cache::cleanup_cache(std::vector >& feeds) { mtx.lock(); // we don't use the scope_mutex here... see comments below /* * cache cleanup means that all entries in both the rss_feed and rss_item tables that are associated with * an RSS feed URL that is not contained in the current configuration are deleted. * Such entries are the result when a user deletes one or more lines in the urls configuration file. We * then assume that the user isn't interested anymore in reading this feed, and delete all associated entries * because they would be non-accessible. * * The behaviour whether the cleanup is done or not is configurable via the configuration file. */ if (cfg->get_configvalue_as_bool("cleanup-on-quit")) { LOG(LOG_DEBUG,"cache::cleanup_cache: cleaning up cache..."); std::string list = "("; int rc; unsigned int i = 0; unsigned int feed_size = feeds.size(); for (std::vector >::iterator it=feeds.begin();it!=feeds.end();++it,++i) { std::string name = prepare_query("'%q'",(*it)->rssurl().c_str()); list.append(name); if (i < feed_size-1) { list.append(", "); } } list.append(")"); std::string cleanup_rss_feeds_statement("DELETE FROM rss_feed WHERE rssurl NOT IN "); cleanup_rss_feeds_statement.append(list); cleanup_rss_feeds_statement.append(1,';'); std::string cleanup_rss_items_statement("DELETE FROM rss_item WHERE feedurl NOT IN "); cleanup_rss_items_statement.append(list); cleanup_rss_items_statement.append(1,';'); std::string cleanup_read_items_statement("DELETE FROM rss_item WHERE unread = 0"); // std::cerr << "statements: " << cleanup_rss_feeds_statement << " " << cleanup_rss_items_statement << std::endl; LOG(LOG_DEBUG,"running query: %s", cleanup_rss_feeds_statement.c_str()); rc = sqlite3_exec(db,cleanup_rss_feeds_statement.c_str(),NULL,NULL,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", cleanup_rss_feeds_statement.c_str(), rc); throw dbexception(db); } LOG(LOG_DEBUG,"running query: %s", cleanup_rss_items_statement.c_str()); rc = sqlite3_exec(db,cleanup_rss_items_statement.c_str(),NULL,NULL,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", cleanup_rss_items_statement.c_str(), rc); throw dbexception(db); } if (cfg->get_configvalue_as_bool("delete-read-articles-on-quit")) { LOG(LOG_DEBUG,"running query: %s", cleanup_read_items_statement.c_str()); rc = sqlite3_exec(db,cleanup_read_items_statement.c_str(),NULL,NULL,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", cleanup_read_items_statement.c_str(), rc); throw dbexception(db); } } // WARNING: THE MISSING UNLOCK OPERATION IS MISSING FOR A PURPOSE! // It's missing so that no database operation can occur after the cache cleanup! // mtx->unlock(); } else { LOG(LOG_DEBUG,"cache::cleanup_cache: NOT cleaning up cache..."); } } void cache::update_rssitem_unlocked(std::tr1::shared_ptr item, const std::string& feedurl, bool reset_unread) { std::string query = prepare_query("SELECT count(*) FROM rss_item WHERE guid = '%q';",item->guid().c_str()); cb_handler count_cbh; LOG(LOG_DEBUG,"running query: %s", query.c_str()); int rc = sqlite3_exec(db,query.c_str(),count_callback,&count_cbh,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } if (count_cbh.count() > 0) { if (reset_unread) { std::string content; query = prepare_query("SELECT content FROM rss_item WHERE guid = '%q';", item->guid().c_str()); rc = sqlite3_exec(db, query.c_str(), single_string_callback, &content, NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } if (content != item->description_raw()) { LOG(LOG_DEBUG, "cache::update_rssitem_unlocked: '%s' is different from '%s'", content.c_str(), item->description_raw().c_str()); query = prepare_query("UPDATE rss_item SET unread = 1 WHERE guid = '%q';", item->guid().c_str()); rc = sqlite3_exec(db, query.c_str(), NULL, NULL, NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } } } std::string update; if (item->override_unread()) { update = prepare_query("UPDATE rss_item SET title = '%q', author = '%q', url = '%q', feedurl = '%q', content = '%q', enclosure_url = '%q', enclosure_type = '%q', base = '%q', unread = '%d' WHERE guid = '%q'", item->title_raw().c_str(), item->author_raw().c_str(), item->link().c_str(), feedurl.c_str(), item->description_raw().c_str(), item->enclosure_url().c_str(), item->enclosure_type().c_str(), item->get_base().c_str(), (item->unread() ? 1 : 0), item->guid().c_str()); } else { update = prepare_query("UPDATE rss_item SET title = '%q', author = '%q', url = '%q', feedurl = '%q', content = '%q', enclosure_url = '%q', enclosure_type = '%q', base = '%q' WHERE guid = '%q'", item->title_raw().c_str(), item->author_raw().c_str(), item->link().c_str(), feedurl.c_str(), item->description_raw().c_str(), item->enclosure_url().c_str(), item->enclosure_type().c_str(), item->get_base().c_str(), item->guid().c_str()); } LOG(LOG_DEBUG,"running query: %s", update.c_str()); rc = sqlite3_exec(db,update.c_str(),NULL,NULL,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", update.c_str(), rc); throw dbexception(db); } } else { std::string insert = prepare_query("INSERT INTO rss_item (guid,title,author,url,feedurl,pubDate,content,unread,enclosure_url,enclosure_type,enqueued, base) " "VALUES ('%q','%q','%q','%q','%q','%u','%q','%d','%q','%q',%d, '%q')", item->guid().c_str(), item->title_raw().c_str(), item->author_raw().c_str(), item->link().c_str(), feedurl.c_str(), item->pubDate_timestamp(), item->description_raw().c_str(), (item->unread() ? 1 : 0), item->enclosure_url().c_str(), item->enclosure_type().c_str(), item->enqueued() ? 1 : 0, item->get_base().c_str()); LOG(LOG_DEBUG,"running query: %s", insert.c_str()); rc = sqlite3_exec(db,insert.c_str(),NULL,NULL,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", insert.c_str(), rc); throw dbexception(db); } } } void cache::catchup_all(std::tr1::shared_ptr feed) { scope_mutex lock(&mtx); scope_mutex feedlock(&feed->item_mutex); std::string query = "UPDATE rss_item SET unread = '0' WHERE unread != '0' AND guid IN ("; for (std::vector >::iterator it=feed->items().begin();it!=feed->items().end();++it) { query.append(prepare_query("'%q',", (*it)->guid().c_str())); } query.append("'');"); LOG(LOG_DEBUG, "running query: %s", query.c_str()); int rc = sqlite3_exec(db, query.c_str(), NULL, NULL, NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } } /* this function marks all rss_items (optionally of a certain feed url) as read */ void cache::catchup_all(const std::string& feedurl) { scope_mutex lock(&mtx); std::string query; if (feedurl.length() > 0) { query = prepare_query("UPDATE rss_item SET unread = '0' WHERE unread != '0' AND feedurl = '%q';", feedurl.c_str()); } else { query = prepare_query("UPDATE rss_item SET unread = '0' WHERE unread != '0';"); } LOG(LOG_DEBUG, "running query: %s", query.c_str()); int rc = sqlite3_exec(db, query.c_str(), NULL, NULL, NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } } void cache::update_rssitem_unread_and_enqueued(rss_item* item, const std::string& feedurl) { scope_mutex lock(&mtx); std::string query = prepare_query("SELECT count(*) FROM rss_item WHERE guid = '%q';",item->guid().c_str()); cb_handler count_cbh; LOG(LOG_DEBUG,"running query: %s", query.c_str()); int rc = sqlite3_exec(db,query.c_str(),count_callback,&count_cbh,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } if (count_cbh.count() > 0) { std::string update = prepare_query("UPDATE rss_item SET unread = '%d', enqueued = '%d' WHERE guid = '%q'", item->unread()?1:0, item->enqueued()?1:0, item->guid().c_str()); LOG(LOG_DEBUG,"running query: %s", update.c_str()); rc = sqlite3_exec(db,update.c_str(),NULL,NULL,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", update.c_str(), rc); throw dbexception(db); } } else { std::string insert = prepare_query("INSERT INTO rss_item (guid,title,author,url,feedurl,pubDate,content,unread,enclosure_url,enclosure_type,enqueued,flags,base) " "VALUES ('%q','%q','%q','%q','%q','%u','%q','%d','%q','%q',%d, '%q', '%q')", item->guid().c_str(), item->title_raw().c_str(), item->author_raw().c_str(), item->link().c_str(), feedurl.c_str(), item->pubDate_timestamp(), item->description_raw().c_str(), item->unread() ? 1 : 0, item->enclosure_url().c_str(), item->enclosure_type().c_str(), item->enqueued() ? 1 : 0, item->flags().c_str(), item->get_base().c_str()); LOG(LOG_DEBUG,"running query: %s", insert.c_str()); rc = sqlite3_exec(db,insert.c_str(),NULL,NULL,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", insert.c_str(), rc); throw dbexception(db); } } } /* this function updates the unread and enqueued flags */ void cache::update_rssitem_unread_and_enqueued(std::tr1::shared_ptr item, const std::string& feedurl) { scope_mutex lock(&mtx); std::string query = prepare_query("SELECT count(*) FROM rss_item WHERE guid = '%q';",item->guid().c_str()); cb_handler count_cbh; LOG(LOG_DEBUG,"running query: %s", query.c_str()); int rc = sqlite3_exec(db,query.c_str(),count_callback,&count_cbh,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } if (count_cbh.count() > 0) { std::string update = prepare_query("UPDATE rss_item SET unread = '%d', enqueued = '%d' WHERE guid = '%q'", item->unread()?1:0, item->enqueued()?1:0, item->guid().c_str()); LOG(LOG_DEBUG,"running query: %s", update.c_str()); rc = sqlite3_exec(db,update.c_str(),NULL,NULL,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", update.c_str(), rc); throw dbexception(db); } } else { std::string insert = prepare_query("INSERT INTO rss_item (guid,title,author,url,feedurl,pubDate,content,unread,enclosure_url,enclosure_type,enqueued,flags,base) " "VALUES ('%q','%q','%q','%q','%q','%u','%q','%d','%q','%q',%d, '%q', '%q')", item->guid().c_str(), item->title_raw().c_str(), item->author_raw().c_str(), item->link().c_str(), feedurl.c_str(), item->pubDate_timestamp(), item->description_raw().c_str(), (item->unread() ? 1 : 0), item->enclosure_url().c_str(), item->enclosure_type().c_str(), item->enqueued() ? 1 : 0, item->flags().c_str(), item->get_base().c_str()); LOG(LOG_DEBUG,"running query: %s", insert.c_str()); rc = sqlite3_exec(db,insert.c_str(),NULL,NULL,NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL,"query \"%s\" failed: error = %d", insert.c_str(), rc); throw dbexception(db); } } } /* helper function to wrap std::string around the sqlite3_*mprintf function */ std::string cache::prepare_query(const char * format, ...) { std::string result; va_list ap; va_start(ap, format); char * query = sqlite3_vmprintf(format, ap); if (query) { result = query; sqlite3_free(query); } va_end(ap); return result; } void cache::update_rssitem_flags(rss_item* item) { scope_mutex lock(&mtx); std::string update = prepare_query("UPDATE rss_item SET flags = '%q' WHERE guid = '%q';", item->flags().c_str(), item->guid().c_str()); LOG(LOG_DEBUG,"running query: %s", update.c_str()); int rc = sqlite3_exec(db,update.c_str(), NULL, NULL, NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL, "query \"%s\" failed: error = %d", update.c_str(), rc); throw dbexception(db); } } void cache::remove_old_deleted_items(const std::string& rssurl, const std::vector& guids) { scope_measure m1("cache::remove_old_deleted_items"); if (guids.size() == 0) { LOG(LOG_DEBUG, "cache::remove_old_deleted_items: not cleaning up anything because last reload brought no new items (detected no changes)"); return; } std::string guidset = "("; for (std::vector::const_iterator it=guids.begin();it!=guids.end();++it) { guidset.append(prepare_query("'%q', ", it->c_str())); } guidset.append("'')"); std::string query = prepare_query("DELETE FROM rss_item WHERE feedurl = '%q' AND deleted = 1 AND guid NOT IN %s;", rssurl.c_str(), guidset.c_str()); scope_mutex lock(&mtx); int rc = sqlite3_exec(db, query.c_str(), NULL, NULL, NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL, "query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } else { LOG(LOG_DEBUG, "cache::remove_old_deleted_items: executed query successfully: %s", query.c_str()); } } unsigned int cache::get_unread_count() { scope_mutex lock(&mtx); std::string countquery = "SELECT count(id) FROM rss_item WHERE unread = 1;"; cb_handler count_cbh; int rc = sqlite3_exec(db,countquery.c_str(),count_callback,&count_cbh,NULL); unsigned int count = static_cast(count_cbh.count()); LOG(LOG_DEBUG, "cache::get_unread_count: rc = %d count = %u", rc, count); return count; } void cache::mark_items_read_by_guid(const std::vector& guids) { scope_measure m1("cache::mark_items_read_by_guid"); std::string guidset("("); for (std::vector::const_iterator it=guids.begin();it!=guids.end();++it) { guidset.append(prepare_query("'%q', ", it->c_str())); } guidset.append("'')"); std::string updatequery = utils::strprintf("UPDATE rss_item SET unread = 0 WHERE unread = 1 AND guid IN %s;", guidset.c_str()); int rc; { scope_mutex lock(&mtx); rc = sqlite3_exec(db, updatequery.c_str(), NULL, NULL, NULL); } if (rc != SQLITE_OK) { LOG(LOG_CRITICAL, "query \"%s\" failed: error = %d", updatequery.c_str(), rc); throw dbexception(db); } else { LOG(LOG_DEBUG, "cache::mark_items_read_by_guid: executed query successfully: %s", updatequery.c_str()); } } std::vector cache::get_read_item_guids() { std::vector guids; std::string query = "SELECT guid FROM rss_item WHERE unread = 0;"; int rc; { scope_mutex lock(&mtx); rc = sqlite3_exec(db, query.c_str(), vectorofstring_callback, &guids, NULL); } if (rc != SQLITE_OK) { LOG(LOG_CRITICAL, "query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } else { LOG(LOG_DEBUG, "cache::get_read_item_guids: executed query successfully: %s", query.c_str()); } return guids; } void cache::clean_old_articles() { scope_mutex lock(&mtx); unsigned int days = cfg->get_configvalue_as_int("keep-articles-days"); if (days > 0) { time_t old_date = time(NULL) - days*24*60*60; std::string query(utils::strprintf("DELETE FROM rss_item WHERE pubDate < %d", old_date)); LOG(LOG_DEBUG, "cache::clean_old_articles: about to delete articles with a pubDate older than %d", old_date); int rc = sqlite3_exec(db, query.c_str(), NULL, NULL, NULL); LOG(LOG_DEBUG, "cache::clean_old_artgicles: old article delete result: rc = %d", rc); } else { LOG(LOG_DEBUG, "cache::clean_old_articles, days == 0, not cleaning up anything"); } } void cache::fetch_descriptions(rss_feed * feed) { std::vector >& items = feed->items(); std::vector guids; for (std::vector >::iterator it=items.begin();it!=items.end();++it) { guids.push_back(prepare_query("'%q'", (*it)->guid().c_str())); } std::string in_clause = utils::join(guids, ", "); std::string query = prepare_query("SELECT guid,content FROM rss_item WHERE guid IN (%s);", in_clause.c_str()); LOG(LOG_DEBUG, "running query: %s", query.c_str()); int rc = sqlite3_exec(db, query.c_str(), fill_content_callback, feed, NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL, "query: \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } } void cache::record_google_replay(const std::string& guid, unsigned int state) { scope_mutex lock(&mtx); std::string query = prepare_query("INSERT INTO google_replay ( guid, state, ts ) VALUES ( '%q', %u, %u );", guid.c_str(), state, (unsigned int)time(NULL)); int rc = sqlite3_exec(db, query.c_str(), NULL, NULL, NULL); LOG(LOG_DEBUG, "ran SQL statement: %s rc = %d", query.c_str(), rc); } void cache::delete_google_replay_by_guid(const std::vector& guids) { std::vector escaped_guids; for (std::vector::const_iterator it=guids.begin();it!=guids.end();++it) { escaped_guids.push_back(prepare_query("'%q'", it->c_str())); } std::string query = prepare_query("DELETE FROM google_replay WHERE guid IN ( %s );", utils::join(escaped_guids, ", ").c_str()); int rc = sqlite3_exec(db, query.c_str(), NULL, NULL, NULL); LOG(LOG_DEBUG, "ran SQL statement: %s rc = %d", query.c_str(), rc); } static int google_replay_cb(void * result, int argc, char ** argv, char ** /* azColName */) { std::vector * google_replay_data = static_cast *>(result); assert(argc == 2); google_replay_data->push_back(google_replay_pair(argv[0], utils::to_u(argv[1]))); return 0; } std::vector cache::get_google_replay() { std::vector result; std::string query = "SELECT guid, state FROM google_replay ORDER BY ts;"; int rc = sqlite3_exec(db, query.c_str(), google_replay_cb, &result, NULL); if (rc != SQLITE_OK) { LOG(LOG_CRITICAL, "query \"%s\" failed: error = %d", query.c_str(), rc); throw dbexception(db); } return result; } } newsbeuter-2.7/src/colormanager.cpp000066400000000000000000000103521220711462700175140ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include using namespace podbeuter; namespace newsbeuter { colormanager::colormanager() : colors_loaded_(false) { } colormanager::~colormanager() { } void colormanager::register_commands(configparser& cfgparser) { cfgparser.register_handler("color", this); } void colormanager::handle_action(const std::string& action, const std::vector& params) { LOG(LOG_DEBUG, "colormanager::handle_action(%s,...) was called",action.c_str()); if (action == "color") { if (params.size() < 3) { throw confighandlerexception(AHS_TOO_FEW_PARAMS); } /* * the command syntax is: * color [ ...] */ std::string element = params[0]; std::string fgcolor = params[1]; std::string bgcolor = params[2]; if (!utils::is_valid_color(fgcolor)) throw confighandlerexception(utils::strprintf(_("`%s' is not a valid color"), fgcolor.c_str())); if (!utils::is_valid_color(bgcolor)) throw confighandlerexception(utils::strprintf(_("`%s' is not a valid color"), bgcolor.c_str())); std::vector attribs; for (unsigned int i=3;i& config_output) { for (std::map::iterator it=fg_colors.begin();it!=fg_colors.end();++it) { std::string configline = utils::strprintf("color %s %s %s", it->first.c_str(), it->second.c_str(), bg_colors[it->first].c_str()); std::vector attribs = attributes[it->first]; for (std::vector::iterator jt=attribs.begin();jt!=attribs.end();++jt) { configline.append(" "); configline.append(*jt); } config_output.push_back(configline); } } /* * this is podbeuter-specific color management * TODO: refactor this */ void colormanager::set_pb_colors(podbeuter::pb_view * v) { std::map::iterator fgcit = fg_colors.begin(); std::map::iterator bgcit = bg_colors.begin(); std::map >::iterator attit = attributes.begin(); for (;fgcit != fg_colors.end(); ++fgcit, ++bgcit, ++attit) { std::string colorattr; if (fgcit->second != "default") { colorattr.append("fg="); colorattr.append(fgcit->second); } if (bgcit->second != "default") { if (colorattr.length() > 0) colorattr.append(","); colorattr.append("bg="); colorattr.append(bgcit->second); } for (std::vector::iterator it=attit->second.begin(); it!= attit->second.end(); ++it) { if (colorattr.length() > 0) colorattr.append(","); colorattr.append("attr="); colorattr.append(*it); } LOG(LOG_DEBUG,"colormanager::set_pb_colors: %s %s\n",fgcit->first.c_str(), colorattr.c_str()); v->dllist_form.set(fgcit->first, colorattr); v->help_form.set(fgcit->first, colorattr); if (fgcit->first == "article") { std::string styleend_str; if (bgcit->second != "default") { styleend_str.append("bg="); styleend_str.append(bgcit->second); } if (styleend_str.length() > 0) styleend_str.append(","); styleend_str.append("attr=bold"); v->help_form.set("styleend", styleend_str.c_str()); } } } } newsbeuter-2.7/src/configcontainer.cpp000066400000000000000000000326371220711462700202250ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include namespace newsbeuter { configdata::configdata(const std::string& v, ...) : value(v), default_value(v), type(ENUM) { va_list ap; va_start(ap, v); const char * arg; do { arg = va_arg(ap, const char *); if (arg) { enum_values.insert(arg); } } while (arg != NULL); va_end(ap); } configcontainer::configcontainer() { // create the config options and set their resp. default value and type config_data["show-read-feeds"] = configdata("yes", configdata::BOOL); config_data["browser"] = configdata("lynx", configdata::PATH); config_data["use-proxy"] = configdata("no", configdata::BOOL); config_data["auto-reload"] = configdata("no", configdata::BOOL); config_data["reload-time"] = configdata("60", configdata::INT); config_data["max-items"] = configdata("0", configdata::INT); config_data["save-path"] = configdata("~/", configdata::PATH); config_data["download-path"] = configdata("~/", configdata::PATH); config_data["max-downloads"] = configdata("1", configdata::INT); config_data["podcast-auto-enqueue"] = configdata("no", configdata::BOOL); config_data["player"] = configdata("", configdata::PATH); config_data["cleanup-on-quit"] = configdata("yes", configdata::BOOL); config_data["user-agent"] = configdata("", configdata::STR); config_data["refresh-on-startup"] = configdata("no", configdata::BOOL); config_data["suppress-first-reload"] = configdata("no", configdata::BOOL); config_data["cache-file"] = configdata("", configdata::PATH); config_data["proxy"] = configdata("", configdata::STR); config_data["proxy-auth"] = configdata("", configdata::STR); config_data["proxy-auth-method"] = configdata("any", "any", "basic", "digest", "digest_ie", "gssnegotiate", "ntlm", "anysafe", NULL); config_data["http-auth-method"] = configdata("any", "any", "basic", "digest", "digest_ie", "gssnegotiate", "ntlm", "anysafe", NULL); config_data["confirm-exit"] = configdata("no", configdata::BOOL); config_data["error-log"] = configdata("", configdata::PATH); config_data["notify-screen"] = configdata("no", configdata::BOOL); config_data["notify-always"] = configdata("no", configdata::BOOL); config_data["notify-xterm"] = configdata("no", configdata::BOOL); config_data["notify-beep"] = configdata("no", configdata::BOOL); config_data["notify-program"] = configdata("", configdata::PATH); config_data["notify-format"] = configdata(_("newsbeuter: finished reload, %f unread feeds (%n unread articles total)"), configdata::STR); config_data["datetime-format"] = configdata("%b %d", configdata::STR); config_data["urls-source"] = configdata("local", "local", "opml", "googlereader", "ttrss", NULL); // enum config_data["bookmark-cmd"] = configdata("", configdata::STR); config_data["opml-url"] = configdata("", configdata::STR, true); config_data["html-renderer"] = configdata("internal", configdata::PATH); config_data["feedlist-format"] = configdata("%4i %n %11u %t", configdata::STR); config_data["articlelist-format"] = configdata("%4i %f %D %6L %?T?|%-17T| &?%t", configdata::STR); config_data["text-width"] = configdata("0", configdata::INT); config_data["always-display-description"] = configdata("false", configdata::BOOL); config_data["reload-only-visible-feeds"] = configdata("false", configdata::BOOL); config_data["article-sort-order"] = configdata("date-asc", configdata::STR); config_data["show-read-articles"] = configdata("yes", configdata::BOOL); config_data["goto-next-feed"] = configdata("yes", configdata::BOOL); config_data["display-article-progress"] = configdata("yes", configdata::BOOL); config_data["swap-title-and-hints"] = configdata("no", configdata::BOOL); config_data["show-keymap-hint"] = configdata("yes", configdata::BOOL); config_data["download-timeout"] = configdata("30", configdata::INT); config_data["download-retries"] = configdata("1", configdata::INT); config_data["feed-sort-order"] = configdata("none-desc", configdata::STR); config_data["reload-threads"] = configdata("1", configdata::INT); config_data["keep-articles-days"] = configdata("0", configdata::INT); config_data["bookmark-interactive"] = configdata("false", configdata::BOOL); config_data["bookmark-autopilot"] = configdata("false", configdata::BOOL); config_data["mark-as-read-on-hover"] = configdata("false", configdata::BOOL); config_data["search-highlight-colors"] = configdata("black yellow bold", configdata::STR, true); config_data["pager"] = configdata("internal", configdata::PATH); config_data["history-limit"] = configdata("100", configdata::INT); config_data["prepopulate-query-feeds"] = configdata("false", configdata::BOOL); config_data["goto-first-unread"] = configdata("true", configdata::BOOL); config_data["proxy-type"] = configdata("http", "http", "socks4", "socks4a", "socks5", NULL); // enum config_data["googlereader-login"] = configdata("", configdata::STR); config_data["googlereader-password"] = configdata("", configdata::STR); config_data["googlereader-passwordfile"] = configdata("", configdata::PATH); config_data["googlereader-flag-share"] = configdata("", configdata::STR); config_data["googlereader-flag-star"] = configdata("", configdata::STR); config_data["googlereader-show-special-feeds"] = configdata("true", configdata::BOOL); config_data["googlereader-min-items"] = configdata("20", configdata::INT); config_data["ignore-mode"] = configdata("download", "download", "display", NULL); // enum config_data["max-download-speed"] = configdata("0", configdata::INT); config_data["cookie-cache"] = configdata("", configdata::STR); config_data["download-full-page"] = configdata("false", configdata::BOOL); config_data["external-url-viewer"] = configdata("", configdata::STR); config_data["ttrss-login"] = configdata("", configdata::STR); config_data["ttrss-password"] = configdata("", configdata::STR); config_data["ttrss-url"] = configdata("", configdata::STR); config_data["ttrss-mode"] = configdata("multi", "single", "multi", NULL); // enum config_data["ttrss-flag-star"] = configdata("", configdata::STR); config_data["ttrss-flag-publish"] = configdata("", configdata::STR); config_data["delete-read-articles-on-quit"] = configdata("false", configdata::BOOL); config_data["openbrowser-and-mark-jumps-to-next-unread"] = configdata("false", configdata::BOOL); config_data["toggleitemread-jumps-to-next-unread"] = configdata("false", configdata::BOOL); config_data["markfeedread-jumps-to-next-unread"] = configdata("false", configdata::BOOL); /* title formats: */ config_data["feedlist-title-format"] = configdata(_("%N %V - Your feeds (%u unread, %t total)%?T? - tag `%T'&?"), configdata::STR); config_data["articlelist-title-format"] = configdata(_("%N %V - Articles in feed '%T' (%u unread, %t total) - %U"), configdata::STR); config_data["searchresult-title-format"] = configdata(_("%N %V - Search result (%u unread, %t total)"), configdata::STR); config_data["filebrowser-title-format"] = configdata(_("%N %V - %?O?Open File&Save File? - %f"), configdata::STR); config_data["help-title-format"] = configdata(_("%N %V - Help"), configdata::STR); config_data["selecttag-title-format"] = configdata(_("%N %V - Select Tag"), configdata::STR); config_data["selectfilter-title-format"] = configdata(_("%N %V - Select Filter"), configdata::STR); config_data["itemview-title-format"] = configdata(_("%N %V - Article '%T' (%u unread, %t total)"), configdata::STR); config_data["urlview-title-format"] = configdata(_("%N %V - URLs"), configdata::STR); config_data["dialogs-title-format"] = configdata(_("%N %V - Dialogs"), configdata::STR); } configcontainer::~configcontainer() { } void configcontainer::register_commands(configparser& cfgparser) { // this registers the config options defined above in the configuration parser // -> if the resp. config option is encountered, it is passed to the configcontainer for (std::map::iterator it=config_data.begin();it!=config_data.end();++it) { cfgparser.register_handler(it->first, this); } } void configcontainer::handle_action(const std::string& action, const std::vector& params) { std::string resolved_action = lookup_alias(action); configdata& cfgdata = config_data[resolved_action]; // configdata::INVALID indicates that the action didn't exist, and that the returned object was created ad-hoc. if (cfgdata.type == configdata::INVALID) { LOG(LOG_WARN, "configcontainer::handler_action: unknown action %s", action.c_str()); throw confighandlerexception(AHS_INVALID_COMMAND); } LOG(LOG_DEBUG, "configcontainer::handle_action: action = %s, type = %u", action.c_str(), cfgdata.type); if (params.size() < 1) { throw confighandlerexception(AHS_TOO_FEW_PARAMS); } switch (cfgdata.type) { case configdata::BOOL: if (!is_bool(params[0])) throw confighandlerexception(utils::strprintf(_("expected boolean value, found `%s' instead"), params[0].c_str())); cfgdata.value = params[0]; break; case configdata::INT: if (!is_int(params[0])) throw confighandlerexception(utils::strprintf(_("expected integer value, found `%s' instead"), params[0].c_str())); cfgdata.value = params[0]; break; case configdata::ENUM: if (cfgdata.enum_values.find(params[0]) == cfgdata.enum_values.end()) throw confighandlerexception(utils::strprintf(_("invalid configuration value `%s'"), params[0].c_str())); // fall-through case configdata::STR: case configdata::PATH: if (cfgdata.multi_option) cfgdata.value = utils::join(params, " "); else cfgdata.value = params[0]; break; default: // should not happen throw confighandlerexception(AHS_INVALID_COMMAND); } } bool configcontainer::is_bool(const std::string& s) { const char * bool_values[] = { "yes", "no", "true", "false", 0 }; for (int i=0; bool_values[i] ; ++i) { if (s == bool_values[i]) return true; } return false; } std::string configcontainer::lookup_alias(const std::string& s) { // this assumes that the config_data table is consistent. std::string alias = s; while (alias != "" && config_data[alias].type == configdata::ALIAS) { alias = config_data[alias].default_value; } return alias; } bool configcontainer::is_int(const std::string& s) { const char * s1 = s.c_str(); for (;*s1;s1++) { if (!isdigit(*s1)) return false; } return true; } std::string configcontainer::get_configvalue(const std::string& key) { std::string retval = config_data[lookup_alias(key)].value; if (config_data[key].type == configdata::PATH) { retval = utils::resolve_tilde(retval); } return retval; } int configcontainer::get_configvalue_as_int(const std::string& key) { std::istringstream is(config_data[lookup_alias(key)].value); int i; is >> i; return i; } bool configcontainer::get_configvalue_as_bool(const std::string& key) { std::string value = config_data[lookup_alias(key)].value; if (value == "true" || value == "yes") return true; return false; } void configcontainer::set_configvalue(const std::string& key, const std::string& value) { LOG(LOG_DEBUG,"configcontainer::set_configvalue(%s [resolved: %s],%s) called", key.c_str(), lookup_alias(key).c_str(), value.c_str()); config_data[lookup_alias(key)].value = value; } void configcontainer::reset_to_default(const std::string& key) { std::string resolved_key = lookup_alias(key); config_data[resolved_key].value = config_data[resolved_key].default_value; } void configcontainer::toggle(const std::string& key) { std::string resolved_key = lookup_alias(key); if (config_data[resolved_key].type == configdata::BOOL) { set_configvalue(resolved_key, std::string(get_configvalue_as_bool(resolved_key) ? "false" : "true")); } } void configcontainer::dump_config(std::vector& config_output) { for (std::map::iterator it=config_data.begin();it!=config_data.end();++it) { std::string configline = it->first + " "; assert(it->second.type != configdata::INVALID); switch (it->second.type) { case configdata::BOOL: case configdata::INT: configline.append(it->second.value); if (it->second.value != it->second.default_value) configline.append(utils::strprintf(" # default: %s", it->second.default_value.c_str())); break; case configdata::ENUM: case configdata::STR: case configdata::PATH: if (it->second.multi_option) { std::vector tokens = utils::tokenize(it->second.value, " "); for (std::vector::iterator it=tokens.begin();it!=tokens.end();++it) { configline.append(utils::quote(*it) + " "); } } else { configline.append(utils::quote(it->second.value)); if (it->second.value != it->second.default_value) { configline.append(utils::strprintf(" # default: %s", it->second.default_value.c_str())); } } break; case configdata::ALIAS: // skip entry, generate no output continue; case configdata::INVALID: assert(0); break; } config_output.push_back(configline); } } std::vector configcontainer::get_suggestions(const std::string& fragment) { std::vector result; for (std::map::iterator it=config_data.begin();it!=config_data.end();++it) { if (it->first.substr(0, fragment.length()) == fragment) result.push_back(it->first); } std::sort(result.begin(), result.end()); return result; } } newsbeuter-2.7/src/configparser.cpp000066400000000000000000000073201220711462700175260ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include namespace newsbeuter { configparser::configparser() { register_handler("include", this); } configparser::~configparser() { } void configparser::handle_action(const std::string& action, const std::vector& params) { /* * configparser also acts as config_action_handler to implement to recursive "include" command. */ if (action == "include") { if (params.size() < 1) { throw confighandlerexception(AHS_TOO_FEW_PARAMS); } if (!this->parse(utils::resolve_tilde(params[0]))) throw confighandlerexception(AHS_FILENOTFOUND); } else throw confighandlerexception(AHS_INVALID_COMMAND); } bool configparser::parse(const std::string& filename, bool double_include) { /* * this function parses a config file. * * First, it checks whether this file has already been included, and if not, * it does the following: * - open the file * - read if line by line * - tokenize every line * - if there is at least one token, look up a registered config_action_handler to handle to command (which is specified in the first token) * - hand over the tokenize results to the config_action_handler * - if an error happens, react accordingly. */ if (!double_include && included_files.find(filename) != included_files.end()) { LOG(LOG_WARN, "configparser::parse: file %s has already been included", filename.c_str()); return true; } included_files.insert(included_files.begin(), filename); unsigned int linecounter = 1; std::ifstream f(filename.c_str()); std::string line; getline(f,line); if (!f.is_open()) { LOG(LOG_WARN, "configparser::parse: file %s couldn't be opened", filename.c_str()); return false; } while (f.is_open() && !f.eof()) { LOG(LOG_DEBUG,"configparser::parse: tokenizing %s",line.c_str()); std::vector tokens = utils::tokenize_quoted(line); if (!tokens.empty()) { std::string cmd = tokens[0]; config_action_handler * handler = action_handlers[cmd]; if (handler) { tokens.erase(tokens.begin()); // delete first element try { evaluate_backticks(tokens); handler->handle_action(cmd,tokens); } catch (const confighandlerexception& e) { throw configexception(utils::strprintf(_("Error while processing command `%s' (%s line %u): %s"), line.c_str(), filename.c_str(), linecounter, e.what())); } } else { throw configexception(utils::strprintf(_("unknown command `%s'"), cmd.c_str())); } } getline(f,line); ++linecounter; } return true; } void configparser::register_handler(const std::string& cmd, config_action_handler * handler) { action_handlers[cmd] = handler; } void configparser::unregister_handler(const std::string& cmd) { action_handlers[cmd] = 0; } void configparser::evaluate_backticks(std::vector& tokens) { for (std::vector::iterator it=tokens.begin();it!=tokens.end();++it) { *it = evaluate_backticks(*it); } } std::string configparser::evaluate_backticks(std::string token) { std::string::size_type pos1 = token.find_first_of("`", 0); std::string::size_type pos2 = 0; while (pos1 != std::string::npos && pos2 != std::string::npos) { pos2 = token.find_first_of("`", pos1+1); if (pos2 != std::string::npos) { std::string cmd = token.substr(pos1+1, pos2-pos1-1); token.erase(pos1, pos2-pos1+1); std::string result = utils::get_command_output(cmd); utils::trim_end(result); token.insert(pos1, result); pos1 = token.find_first_of("`", pos1+result.length()+1); } } return token; } } newsbeuter-2.7/src/controller.cpp000066400000000000000000001455321220711462700172370ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace newsbeuter { #define LOCK_SUFFIX ".lock" std::string lock_file; int ctrl_c_hit = 0; void ctrl_c_action(int sig) { LOG(LOG_DEBUG,"caught signal %d",sig); if (SIGINT == sig) { ctrl_c_hit = 1; } else { stfl::reset(); utils::remove_fs_lock(lock_file); ::exit(EXIT_FAILURE); } } void ignore_signal(int sig) { LOG(LOG_WARN, "caught signal %d but ignored it", sig); } void omg_a_child_died(int /* sig */) { pid_t pid; int stat; while ((pid = waitpid(-1,&stat,WNOHANG)) > 0) { } ::signal(SIGCHLD, omg_a_child_died); /* in case of unreliable signals */ } controller::controller() : v(0), urlcfg(0), rsscache(0), url_file("urls"), cache_file("cache.db"), config_file("config"), queue_file("queue"), refresh_on_start(false), api(0), offline_mode(false) { } /** * \brief Try to setup XDG style dirs. * * returns false, if that fails */ bool controller::setup_dirs_xdg(const char *env_home, bool silent) { const char *env_xdg_config; const char *env_xdg_data; std::string xdg_config_dir; std::string xdg_data_dir; env_xdg_config = ::getenv("XDG_CONFIG_HOME"); if (env_xdg_config) { xdg_config_dir = env_xdg_config; } else { xdg_config_dir = env_home; xdg_config_dir.append(NEWSBEUTER_PATH_SEP); xdg_config_dir.append(".config"); } env_xdg_data = ::getenv("XDG_DATA_HOME"); if (env_xdg_data) { xdg_data_dir = env_xdg_data; } else { xdg_data_dir = env_home; xdg_data_dir.append(NEWSBEUTER_PATH_SEP); xdg_data_dir.append(".local"); xdg_data_dir.append(NEWSBEUTER_PATH_SEP); xdg_data_dir.append("share"); } xdg_config_dir.append(NEWSBEUTER_PATH_SEP); xdg_config_dir.append(NEWSBEUTER_SUBDIR_XDG); xdg_data_dir.append(NEWSBEUTER_PATH_SEP); xdg_data_dir.append(NEWSBEUTER_SUBDIR_XDG); if (access(xdg_config_dir.c_str(), R_OK | X_OK) != 0) { if (!silent) { std::cerr << utils::strprintf(_("XDG: configuration directory '%s' not accessible, using '%s' instead."), xdg_config_dir.c_str(), config_dir.c_str()) << std::endl; } return false; } if (access(xdg_data_dir.c_str(), R_OK | X_OK | W_OK) != 0) { if (!silent) { std::cerr << utils::strprintf(_("XDG: data directory '%s' not accessible, using '%s' instead."), xdg_data_dir.c_str(), config_dir.c_str()) << std::endl; } return false; } config_dir = xdg_config_dir; /* in config */ url_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + url_file; config_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + config_file; /* in data */ cache_file = xdg_data_dir + std::string(NEWSBEUTER_PATH_SEP) + cache_file; lock_file = cache_file + LOCK_SUFFIX; queue_file = xdg_data_dir + std::string(NEWSBEUTER_PATH_SEP) + queue_file; searchfile = utils::strprintf("%s%shistory.search", xdg_data_dir.c_str(), NEWSBEUTER_PATH_SEP); cmdlinefile = utils::strprintf("%s%shistory.cmdline", xdg_data_dir.c_str(), NEWSBEUTER_PATH_SEP); return true; } void controller::setup_dirs(bool silent) { const char * env_home; if (!(env_home = ::getenv("HOME"))) { struct passwd * spw = ::getpwuid(::getuid()); if (spw) { env_home = spw->pw_dir; } else { std::cerr << _("Fatal error: couldn't determine home directory!") << std::endl; std::cerr << utils::strprintf(_("Please set the HOME environment variable or add a valid user for UID %u!"), ::getuid()) << std::endl; ::exit(EXIT_FAILURE); } } config_dir = env_home; config_dir.append(NEWSBEUTER_PATH_SEP); config_dir.append(NEWSBEUTER_CONFIG_SUBDIR); if (setup_dirs_xdg(env_home, silent)) return; mkdir(config_dir.c_str(),0700); // create configuration directory if it doesn't exist url_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + url_file; cache_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + cache_file; lock_file = cache_file + LOCK_SUFFIX; config_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + config_file; queue_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + queue_file; searchfile = utils::strprintf("%s%shistory.search", config_dir.c_str(), NEWSBEUTER_PATH_SEP); cmdlinefile = utils::strprintf("%s%shistory.cmdline", config_dir.c_str(), NEWSBEUTER_PATH_SEP); } controller::~controller() { delete rsscache; delete urlcfg; delete api; scope_mutex feedslock(&feeds_mutex); for (std::vector >::iterator it=feeds.begin();it!=feeds.end();++it) { scope_mutex lock(&((*it)->item_mutex)); (*it)->clear_items(); } feeds.clear(); } void controller::set_view(view * vv) { v = vv; } void controller::run(int argc, char * argv[]) { int c; ::signal(SIGINT, ctrl_c_action); ::signal(SIGPIPE, ignore_signal); ::signal(SIGHUP, ctrl_c_action); ::signal(SIGCHLD, omg_a_child_died); bool do_import = false, do_export = false, cachefile_given_on_cmdline = false, do_vacuum = false; bool real_offline_mode = false; std::string importfile; bool do_read_import = false, do_read_export = false; std::string readinfofile; unsigned int show_version = 0; bool silent = false; bool execute_cmds = false; static char getopt_str[] = "i:erhqu:c:C:d:l:vVoxXI:E:"; do { if ((c = ::getopt(argc,argv,getopt_str)) < 0) continue; if (strchr("iexq", c) != NULL) { silent = true; break; } } while (c != -1); setup_dirs(silent); optind = 1; do { if((c = ::getopt(argc,argv,getopt_str))<0) continue; switch (c) { case ':': /* fall-through */ case '?': /* missing option */ usage(argv[0]); break; case 'i': if (do_export) usage(argv[0]); do_import = true; importfile = optarg; break; case 'r': refresh_on_start = true; break; case 'e': if (do_import) usage(argv[0]); do_export = true; break; case 'h': usage(argv[0]); break; case 'u': url_file = optarg; break; case 'c': cache_file = optarg; lock_file = std::string(cache_file) + LOCK_SUFFIX; cachefile_given_on_cmdline = true; break; case 'C': config_file = optarg; break; case 'X': do_vacuum = true; break; case 'v': case 'V': show_version++; break; case 'o': offline_mode = true; break; case 'x': execute_cmds = true; break; case 'q': break; case 'd': // this is an undocumented debug commandline option! logger::getInstance().set_logfile(optarg); break; case 'l': // this is an undocumented debug commandline option! { loglevel level = static_cast(atoi(optarg)); if (level > LOG_NONE && level <= LOG_DEBUG) { logger::getInstance().set_loglevel(level); } else { std::cerr << utils::strprintf(_("%s: %d: invalid loglevel value"), argv[0], level) << std::endl; ::std::exit(EXIT_FAILURE); } } break; case 'I': if (do_read_export) usage(argv[0]); do_read_import = true; readinfofile = optarg; break; case 'E': if (do_read_import) usage(argv[0]); do_read_export = true; readinfofile = optarg; break; default: std::cout << utils::strprintf(_("%s: unknown option - %c"), argv[0], static_cast(c)) << std::endl; usage(argv[0]); break; } } while (c != -1); if (show_version) { version_information(argv[0], show_version); } if (do_import) { LOG(LOG_INFO,"Importing OPML file from %s",importfile.c_str()); urlcfg = new file_urlreader(url_file); urlcfg->reload(); import_opml(importfile.c_str()); return; } LOG(LOG_INFO, "nl_langinfo(CODESET): %s", nl_langinfo(CODESET)); if (!do_export) { if (!silent) std::cout << utils::strprintf(_("Starting %s %s..."), PROGRAM_NAME, PROGRAM_VERSION) << std::endl; pid_t pid; if (!utils::try_fs_lock(lock_file, pid)) { if (pid > 0) { LOG(LOG_ERROR,"an instance is already running: pid = %u",pid); } else { LOG(LOG_ERROR,"something went wrong with the lock: %s", strerror(errno)); } if (!execute_cmds) { std::cout << utils::strprintf(_("Error: an instance of %s is already running (PID: %u)"), PROGRAM_NAME, pid) << std::endl; } return; } } if (!silent) std::cout << _("Loading configuration..."); std::cout.flush(); cfg.register_commands(cfgparser); colorman.register_commands(cfgparser); keymap keys(KM_NEWSBEUTER); cfgparser.register_handler("bind-key",&keys); cfgparser.register_handler("unbind-key",&keys); cfgparser.register_handler("macro", &keys); cfgparser.register_handler("ignore-article",&ign); cfgparser.register_handler("always-download",&ign); cfgparser.register_handler("reset-unread-on-update",&ign); cfgparser.register_handler("define-filter",&filters); cfgparser.register_handler("highlight", &rxman); cfgparser.register_handler("highlight-article", &rxman); try { cfgparser.parse("/etc/" PROGRAM_NAME "/config"); cfgparser.parse(config_file); } catch (const configexception& ex) { LOG(LOG_ERROR,"an exception occured while parsing the configuration file: %s",ex.what()); std::cout << ex.what() << std::endl; utils::remove_fs_lock(lock_file); return; } update_config(); if (!silent) std::cout << _("done.") << std::endl; // create cache object std::string cachefilepath = cfg.get_configvalue("cache-file"); if (cachefilepath.length() > 0 && !cachefile_given_on_cmdline) { cache_file = cachefilepath.c_str(); // ok, we got another cache file path via the configuration // that means we need to remove the old lock file, assemble // the new lock file's name, and then try to lock it. utils::remove_fs_lock(lock_file); lock_file = std::string(cache_file) + LOCK_SUFFIX; pid_t pid; if (!utils::try_fs_lock(lock_file, pid)) { if (pid > 0) { LOG(LOG_ERROR,"an instance is already running: pid = %u",pid); } else { LOG(LOG_ERROR,"something went wrong with the lock: %s", strerror(errno)); } std::cout << utils::strprintf(_("Error: an instance of %s is already running (PID: %u)"), PROGRAM_NAME, pid) << std::endl; return; } } if (!silent) { std::cout << _("Opening cache..."); std::cout.flush(); } try { rsscache = new cache(cache_file,&cfg); } catch (const dbexception& e) { std::cerr << utils::strprintf(_("Error: opening the cache file `%s' failed: %s"), cache_file.c_str(), e.what()) << std::endl; utils::remove_fs_lock(lock_file); ::exit(EXIT_FAILURE); } if (!silent) { std::cout << _("done.") << std::endl; } std::string type = cfg.get_configvalue("urls-source"); if (type == "local") { urlcfg = new file_urlreader(url_file); } else if (type == "opml") { urlcfg = new opml_urlreader(&cfg); real_offline_mode = offline_mode; } else if (type == "googlereader") { api = new googlereader_api(&cfg); urlcfg = new googlereader_urlreader(&cfg, url_file, api); real_offline_mode = offline_mode; } else if (type == "ttrss") { api = new ttrss_api(&cfg); urlcfg = new ttrss_urlreader(&cfg, url_file, api); real_offline_mode = offline_mode; } else { LOG(LOG_ERROR,"unknown urls-source `%s'", urlcfg->get_source().c_str()); } if (real_offline_mode) { if (!do_export) { std::cout << _("Loading URLs from local cache..."); std::cout.flush(); } urlcfg->set_offline(true); urlcfg->get_urls() = rsscache->get_feed_urls(); if (!do_export) { std::cout << _("done.") << std::endl; } } else { if (!do_export && !silent) { std::cout << utils::strprintf(_("Loading URLs from %s..."), urlcfg->get_source().c_str()); std::cout.flush(); } if (api) { if (!api->authenticate()) { std::cout << "Authentication failed." << std::endl; utils::remove_fs_lock(lock_file); return; } } urlcfg->reload(); if (!do_export && !silent) { std::cout << _("done.") << std::endl; } if (api && type == "googlereader") { // ugly hack! std::vector actions = rsscache->get_google_replay(); if (!actions.empty()) { std::cout << _("Updating Google Reader unread states..."); std::cout.flush(); std::vector successful_guids = dynamic_cast(api)->bulk_mark_articles_read(actions); rsscache->delete_google_replay_by_guid(successful_guids); std::cout << _("done.") << std::endl; } } } if (urlcfg->get_urls().size() == 0) { LOG(LOG_ERROR,"no URLs configured."); std::string msg; if (type == "local") { msg = utils::strprintf(_("Error: no URLs configured. Please fill the file %s with RSS feed URLs or import an OPML file."), url_file.c_str()); } else if (type == "opml") { msg = utils::strprintf(_("It looks like the OPML feed you subscribed contains no feeds. Please fill it with feeds, and try again.")); } else if (type == "googlereader") { msg = utils::strprintf(_("It looks like you haven't configured any feeds in your Google Reader account. Please do so, and try again.")); } else if (type == "ttrss") { msg = utils::strprintf(_("It looks like you haven't configured any feeds in your Tiny Tiny RSS account. Please do so, and try again.")); } else { assert(0); // shouldn't happen } std::cout << msg << std::endl << std::endl; usage(argv[0]); } if (!do_export && !do_vacuum && !silent) std::cout << _("Loading articles from cache..."); if (do_vacuum) std::cout << _("Opening cache..."); std::cout.flush(); if (do_vacuum) { std::cout << _("done.") << std::endl; std::cout << _("Cleaning up cache thoroughly..."); std::cout.flush(); rsscache->do_vacuum(); std::cout << _("done.") << std::endl; utils::remove_fs_lock(lock_file); return; } unsigned int i=0; for (std::vector::const_iterator it=urlcfg->get_urls().begin(); it != urlcfg->get_urls().end(); ++it, ++i) { std::tr1::shared_ptr feed(new rss_feed(rsscache)); try { feed->set_rssurl(*it); feed->set_tags(urlcfg->get_tags(*it)); bool ignore_disp = (cfg.get_configvalue("ignore-mode") == "display"); rsscache->internalize_rssfeed(feed, ignore_disp ? &ign : NULL); } catch(const dbexception& e) { std::cout << _("Error while loading feeds from database: ") << e.what() << std::endl; utils::remove_fs_lock(lock_file); return; } catch(const std::string& str) { std::cout << utils::strprintf(_("Error while loading feed '%s': %s"), it->c_str(), str.c_str()) << std::endl; utils::remove_fs_lock(lock_file); return; } feed->set_order(i); scope_mutex feedslock(&feeds_mutex); feeds.push_back(feed); } sort_feeds(); std::vector tags = urlcfg->get_alltags(); if (!do_export && !silent) std::cout << _("done.") << std::endl; // if configured, we fill all query feeds with some data; no need to sort it, it will be refilled when actually opening it. if (cfg.get_configvalue_as_bool("prepopulate-query-feeds")) { std::cout << _("Prepopulating query feeds..."); std::cout.flush(); scope_mutex feedslock(&feeds_mutex); for (std::vector >::iterator it=feeds.begin();it!=feeds.end();++it) { if ((*it)->rssurl().substr(0,6) == "query:") { (*it)->update_items(get_all_feeds_unlocked()); } } std::cout << _("done.") << std::endl; } if (do_export) { export_opml(); utils::remove_fs_lock(lock_file); return; } if (do_read_import) { LOG(LOG_INFO,"Importing read information file from %s",readinfofile.c_str()); std::cout << _("Importing list of read articles..."); std::cout.flush(); import_read_information(readinfofile); std::cout << _("done.") << std::endl; return; } if (do_read_export) { LOG(LOG_INFO,"Exporting read information file to %s",readinfofile.c_str()); std::cout << _("Exporting list of read articles..."); std::cout.flush(); export_read_information(readinfofile); std::cout << _("done.") << std::endl; return; } if (execute_cmds) { execute_commands(argv, optind); utils::remove_fs_lock(lock_file); return; } // if the user wants to refresh on startup via configuration file, then do so, // but only if -r hasn't been supplied. if (!refresh_on_start && cfg.get_configvalue_as_bool("refresh-on-startup")) { refresh_on_start = true; } // hand over the important objects to the view v->set_config_container(&cfg); v->set_keymap(&keys); v->set_tags(tags); formaction::load_histories(searchfile, cmdlinefile); // run the view v->run(); unsigned int history_limit = cfg.get_configvalue_as_int("history-limit"); LOG(LOG_DEBUG, "controller::run: history-limit = %u", history_limit); formaction::save_histories(searchfile, cmdlinefile, history_limit); if (!silent) { std::cout << _("Cleaning up cache..."); std::cout.flush(); } try { scope_mutex feedslock(&feeds_mutex); rsscache->cleanup_cache(feeds); if (!silent) { std::cout << _("done.") << std::endl; } } catch (const dbexception& e) { LOG(LOG_USERERROR, "Cleaning up cache failed: %s", e.what()); if (!silent) { std::cout << _("failed: ") << e.what() << std::endl; } } utils::remove_fs_lock(lock_file); } void controller::update_feedlist() { scope_mutex feedslock(&feeds_mutex); v->set_feedlist(feeds); } void controller::update_visible_feeds() { scope_mutex feedslock(&feeds_mutex); v->update_visible_feeds(feeds); } void controller::catchup_all() { try { rsscache->catchup_all(); } catch (const dbexception& e) { v->show_error(utils::strprintf(_("Error: couldn't mark all feeds read: %s"), e.what())); return; } scope_mutex feedslock(&feeds_mutex); for (std::vector >::iterator it=feeds.begin();it!=feeds.end();++it) { scope_mutex lock(&(*it)->item_mutex); if ((*it)->items().size() > 0) { if (api) { api->mark_all_read((*it)->rssurl()); } for (std::vector >::iterator jt=(*it)->items().begin();jt!=(*it)->items().end();++jt) { (*jt)->set_unread_nowrite(false); } } } } void controller::mark_article_read(const std::string& guid, bool read) { if (api) { if (offline_mode) { if (dynamic_cast(api) != NULL) { LOG(LOG_DEBUG, "controller::mark_article_read: recording %s", guid.c_str()); record_google_replay(guid, read); } else { LOG(LOG_DEBUG, "not on googlereader_api"); } } else { api->mark_article_read(guid, read); } } } void controller::record_google_replay(const std::string& guid, bool read) { rsscache->record_google_replay(guid, read ? GOOGLE_MARK_READ : GOOGLE_MARK_UNREAD); } void controller::mark_all_read(unsigned int pos) { if (pos < feeds.size()) { scope_measure m("controller::mark_all_read"); scope_mutex feedslock(&feeds_mutex); std::tr1::shared_ptr feed = feeds[pos]; if (feed->rssurl().substr(0,6) == "query:") { rsscache->catchup_all(feed); } else { rsscache->catchup_all(feed->rssurl()); if (api) { api->mark_all_read(feed->rssurl()); } } m.stopover("after rsscache->catchup_all, before iteration over items"); scope_mutex lock(&feed->item_mutex); std::vector >& items = feed->items(); std::vector >::iterator begin = items.begin(), end = items.end(); if (items.size() > 0) { bool notify = items[0]->feedurl() != feed->rssurl(); LOG(LOG_DEBUG, "controller::mark_all_read: notify = %s", notify ? "yes" : "no"); for (std::vector >::iterator it=begin;it!=end;++it) { (*it)->set_unread_nowrite_notify(false, notify); } } } } void controller::reload(unsigned int pos, unsigned int max, bool unattended, curl_handle *easyhandle) { LOG(LOG_DEBUG, "controller::reload: pos = %u max = %u", pos, max); if (pos < feeds.size()) { std::tr1::shared_ptr oldfeed = feeds[pos]; std::string errmsg; if (!unattended) v->set_status(utils::strprintf(_("%sLoading %s..."), prepare_message(pos+1, max).c_str(), utils::censor_url(oldfeed->rssurl()).c_str())); bool ignore_dl = (cfg.get_configvalue("ignore-mode") == "download"); rss_parser parser(oldfeed->rssurl(), rsscache, &cfg, ignore_dl ? &ign : NULL, api); parser.set_easyhandle(easyhandle); LOG(LOG_DEBUG, "controller::reload: created parser"); try { oldfeed->set_status(DURING_DOWNLOAD); std::tr1::shared_ptr newfeed = parser.parse(); if (newfeed->items().size() > 0) { scope_mutex feedslock(&feeds_mutex); save_feed(newfeed, pos); enqueue_items(newfeed); if (!unattended) { v->set_feedlist(feeds); } } else { LOG(LOG_DEBUG, "controller::reload: feed is empty"); } oldfeed->set_status(SUCCESS); v->set_status(""); } catch (const dbexception& e) { errmsg = utils::strprintf(_("Error while retrieving %s: %s"), utils::censor_url(oldfeed->rssurl()).c_str(), e.what()); } catch (const std::string& emsg) { errmsg = utils::strprintf(_("Error while retrieving %s: %s"), utils::censor_url(oldfeed->rssurl()).c_str(), emsg.c_str()); } catch (rsspp::exception& e) { errmsg = utils::strprintf(_("Error while retrieving %s: %s"), utils::censor_url(oldfeed->rssurl()).c_str(), e.what()); } if (errmsg != "") { oldfeed->set_status(DL_ERROR); v->set_status(errmsg); LOG(LOG_USERERROR, "%s", errmsg.c_str()); } } else { v->show_error(_("Error: invalid feed!")); } } std::tr1::shared_ptr controller::get_feed(unsigned int pos) { scope_mutex feedslock(&feeds_mutex); if (pos >= feeds.size()) { throw std::out_of_range(_("invalid feed index (bug)")); } std::tr1::shared_ptr feed = feeds[pos]; return feed; } void controller::reload_indexes(const std::vector& indexes, bool unattended) { scope_measure m1("controller::reload_indexes"); unsigned int unread_feeds, unread_articles; compute_unread_numbers(unread_feeds, unread_articles); unsigned long size; { scope_mutex feedslock(&feeds_mutex); size = feeds.size(); } for (std::vector::const_iterator it=indexes.begin();it!=indexes.end();++it) { this->reload(*it, size, unattended); } unsigned int unread_feeds2, unread_articles2; compute_unread_numbers(unread_feeds2, unread_articles2); bool notify_always = cfg.get_configvalue_as_bool("notify-always"); if (notify_always || unread_feeds2 != unread_feeds || unread_articles2 != unread_articles) { fmtstr_formatter fmt; fmt.register_fmt('f', utils::to_string(unread_feeds2)); fmt.register_fmt('n', utils::to_string(unread_articles2)); fmt.register_fmt('d', utils::to_string(unread_articles2 - unread_articles)); fmt.register_fmt('D', utils::to_string(unread_feeds2 - unread_feeds)); this->notify(fmt.do_format(cfg.get_configvalue("notify-format"))); } if (!unattended) v->set_status(""); } struct feed_cmp { const std::vector > &feeds; feed_cmp(const std::vector > &f) : feeds(f) { } void extract(std::string &s, const std::string &url) const { size_t p = url.find("//"); p = (p == std::string::npos) ? 0 : p+2; std::string suff(url.substr(p)); p = suff.find('/'); s = suff.substr(0, p); } bool operator()(unsigned a, unsigned b) const { std::tr1::shared_ptr x = feeds[a]; std::tr1::shared_ptr y = feeds[b]; const std::string &u = x->rssurl(); const std::string &v = y->rssurl(); std::string domain1, domain2; extract(domain1, u); extract(domain2, v); std::reverse(domain1.begin(), domain1.end()); std::reverse(domain2.begin(), domain2.end()); return domain1 < domain2; } }; void controller::reload_range(unsigned int start, unsigned int end, unsigned int size, bool unattended) { std::vector v; for (unsigned i=start;i<=end;++i) v.push_back(i); std::sort(v.begin(), v.end(), feed_cmp(feeds)); curl_handle easyhandle; for (std::vector::iterator i = v.begin(); i!= v.end(); ++i) { LOG(LOG_DEBUG, "controller::reload_range: reloading feed #%u", *i); this->reload(*i, size, unattended, &easyhandle); } } void controller::reload_all(bool unattended) { unsigned int unread_feeds, unread_articles; compute_unread_numbers(unread_feeds, unread_articles); unsigned int num_threads = cfg.get_configvalue_as_int("reload-threads"); time_t t1, t2, dt; unsigned int size; { scope_mutex feedlock(&feeds_mutex); for (std::vector >::iterator it=feeds.begin();it!=feeds.end();++it) { (*it)->reset_status(); } size = feeds.size(); } if (num_threads < 1) num_threads = 1; if (num_threads > size) { num_threads = size; } t1 = time(NULL); LOG(LOG_DEBUG,"controller::reload_all: starting with reload all..."); if (num_threads <= 1) { this->reload_range(0, size-1, size, unattended); } else { std::vector > partitions = utils::partition_indexes(0, size-1, num_threads); std::vector threads; LOG(LOG_DEBUG, "controller::reload_all: starting reload threads..."); for (unsigned int i=0;istart()); } LOG(LOG_DEBUG, "controller::reload_all: starting my own reload..."); this->reload_range(partitions[num_threads-1].first, partitions[num_threads-1].second, size, unattended); LOG(LOG_DEBUG, "controller::reload_all: joining other threads..."); for (std::vector::iterator it=threads.begin();it!=threads.end();++it) { ::pthread_join(*it, NULL); } } // refresh query feeds (update and sort) LOG(LOG_DEBUG, "controller::reload_all: refresh query feeds"); for (std::vector >::iterator it=feeds.begin();it!=feeds.end();++it) { v->prepare_query_feed(*it); } v->force_redraw(); sort_feeds(); update_feedlist(); t2 = time(NULL); dt = t2 - t1; LOG(LOG_INFO, "controller::reload_all: reload took %d seconds", dt); unsigned int unread_feeds2, unread_articles2; compute_unread_numbers(unread_feeds2, unread_articles2); bool notify_always = cfg.get_configvalue_as_bool("notify-always"); if (notify_always || unread_feeds2 > unread_feeds || unread_articles2 > unread_articles) { int article_count = unread_articles2 - unread_articles; int feed_count = unread_feeds2 - unread_feeds; LOG(LOG_DEBUG, "unread article count: %d", article_count); LOG(LOG_DEBUG, "unread feed count: %d", feed_count); fmtstr_formatter fmt; fmt.register_fmt('f', utils::to_string(unread_feeds2)); fmt.register_fmt('n', utils::to_string(unread_articles2)); fmt.register_fmt('d', utils::to_string(article_count >= 0 ? article_count : 0)); fmt.register_fmt('D', utils::to_string(feed_count >= 0 ? feed_count : 0)); this->notify(fmt.do_format(cfg.get_configvalue("notify-format"))); } } void controller::notify(const std::string& msg) { if (cfg.get_configvalue_as_bool("notify-screen")) { LOG(LOG_DEBUG, "controller:notify: notifying screen"); std::cout << "\033^" << msg << "\033\\"; std::cout.flush(); } if (cfg.get_configvalue_as_bool("notify-xterm")) { LOG(LOG_DEBUG, "controller:notify: notifying xterm"); std::cout << "\033]2;" << msg << "\033\\"; std::cout.flush(); } if (cfg.get_configvalue_as_bool("notify-beep")) { LOG(LOG_DEBUG, "controller:notify: notifying beep"); ::beep(); } if (cfg.get_configvalue("notify-program").length() > 0) { std::string prog = cfg.get_configvalue("notify-program"); LOG(LOG_DEBUG, "controller:notify: notifying external program `%s'", prog.c_str()); utils::run_command(prog, msg); } } void controller::compute_unread_numbers(unsigned int& unread_feeds, unsigned int& unread_articles) { unread_feeds = 0; unread_articles = 0; for (std::vector >::iterator it=feeds.begin();it!=feeds.end();++it) { unsigned int items = (*it)->unread_item_count(); if (items > 0) { ++unread_feeds; unread_articles += items; } } } bool controller::trylock_reload_mutex() { if (reload_mutex.trylock()) { LOG(LOG_DEBUG, "controller::trylock_reload_mutex succeeded"); return true; } LOG(LOG_DEBUG, "controller::trylock_reload_mutex failed"); return false; } void controller::start_reload_all_thread(std::vector * indexes) { LOG(LOG_INFO,"starting reload all thread"); thread * dlt = new downloadthread(this, indexes); dlt->start(); } void controller::version_information(const char * argv0, unsigned int level) { if (level<=1) { std::cout << PROGRAM_NAME << " " << PROGRAM_VERSION << " - " << PROGRAM_URL << std::endl; std::cout << "Copyright (C) 2006-2010 Andreas Krennmair" << std::endl << std::endl; std::cout << _("newsbeuter is free software and licensed under the MIT/X Consortium License.") << std::endl; std::cout << utils::strprintf(_("Type `%s -vv' for more information."), argv0) << std::endl << std::endl; struct utsname xuts; uname(&xuts); std::cout << "Compilation date/time: " << __DATE__ << " " << __TIME__ << std::endl; std::cout << "System: " << xuts.sysname << " " << xuts.release << " (" << xuts.machine << ")" << std::endl; #if defined(__GNUC__) && defined(__VERSION__) std::cout << "Compiler: g++ " << __VERSION__ << std::endl; #endif std::cout << "ncurses: " << curses_version() << " (compiled with " << NCURSES_VERSION << ")" << std::endl; std::cout << "libcurl: " << curl_version() << " (compiled with " << LIBCURL_VERSION << ")" << std::endl; std::cout << "SQLite: " << sqlite3_libversion() << " (compiled with " << SQLITE_VERSION << ")" << std::endl; std::cout << "libxml2: compiled with " << LIBXML_DOTTED_VERSION << std::endl << std::endl; } else { std::cout << LICENSE_str << std::endl; } ::exit(EXIT_SUCCESS); } static unsigned int gentabs(const std::string& str) { int tabcount = 2 - ((3 + utils::strwidth(str)) / 8); if (tabcount <= 0) { tabcount = 1; } return tabcount; } void controller::usage(char * argv0) { std::cout << utils::strprintf(_("%s %s\nusage: %s [-i |-e] [-u ] [-c ] [-x ...] [-h]\n"), PROGRAM_NAME, PROGRAM_VERSION, argv0); struct { char arg; const char * params; const char * desc; } args[] = { { 'e', "", _("export OPML feed to stdout") }, { 'r', "", _("refresh feeds on start") }, { 'i', _(""), _("import OPML file") }, { 'u', _(""), _("read RSS feed URLs from ") }, { 'c', _(""), _("use as cache file") }, { 'C', _(""), _("read configuration from ") }, { 'X', "", _("clean up cache thoroughly") }, { 'x', _("..."), _("execute list of commands") }, { 'o', "", _("activate offline mode (only applies to Google Reader synchronization mode)") }, { 'q', "", _("quiet startup") }, { 'v', "", _("get version information") }, { 'l', _(""), _("write a log with a certain loglevel (valid values: 1 to 6)") }, { 'd', _(""), _("use as output log file") }, { 'E', _(""), _("export list of read articles to ") }, { 'I', _(""), _("import list of read articles from ") }, { 'h', "", _("this help") }, { '\0', NULL, NULL } }; for (unsigned int i=0;args[i].arg != '\0';i++) { unsigned int tabs = gentabs(args[i].params); std::cout << "\t-" << args[i].arg << " " << args[i].params; for (unsigned int j=0;jchildren; node != NULL; node = node->next) { if (strcmp((const char *)node->name, "body")==0) { LOG(LOG_DEBUG, "import_opml: found body"); rec_find_rss_outlines(node->children, ""); urlcfg->write_config(); } } xmlFreeDoc(doc); std::cout << utils::strprintf(_("Import of %s finished."), filename) << std::endl; } void controller::export_opml() { xmlDocPtr root = xmlNewDoc((const xmlChar *)"1.0"); xmlNodePtr opml_node = xmlNewDocNode(root, NULL, (const xmlChar *)"opml", NULL); xmlSetProp(opml_node, (const xmlChar *)"version", (const xmlChar *)"1.0"); xmlDocSetRootElement(root, opml_node); xmlNodePtr head = xmlNewTextChild(opml_node, NULL, (const xmlChar *)"head", NULL); xmlNewTextChild(head, NULL, (const xmlChar *)"title", (const xmlChar *)PROGRAM_NAME " - Exported Feeds"); xmlNodePtr body = xmlNewTextChild(opml_node, NULL, (const xmlChar *)"body", NULL); for (std::vector >::iterator it=feeds.begin(); it != feeds.end(); ++it) { if (!utils::is_special_url((*it)->rssurl())) { std::string rssurl = (*it)->rssurl(); std::string link = (*it)->link(); std::string title = (*it)->title(); xmlNodePtr outline = xmlNewTextChild(body, NULL, (const xmlChar *)"outline", NULL); xmlSetProp(outline, (const xmlChar *)"type", (const xmlChar *)"rss"); xmlSetProp(outline, (const xmlChar *)"xmlUrl", (const xmlChar *)rssurl.c_str()); xmlSetProp(outline, (const xmlChar *)"htmlUrl", (const xmlChar *)link.c_str()); xmlSetProp(outline, (const xmlChar *)"title", (const xmlChar *)title.c_str()); } } xmlSaveCtxtPtr savectx = xmlSaveToFd(1, NULL, 1); xmlSaveDoc(savectx, root); xmlSaveClose(savectx); xmlFreeNode(opml_node); } void controller::rec_find_rss_outlines(xmlNode * node, std::string tag) { while (node) { std::string newtag = tag; if (strcmp((const char *)node->name, "outline")==0) { char * url = (char *)xmlGetProp(node, (const xmlChar *)"xmlUrl"); if (!url) { url = (char *)xmlGetProp(node, (const xmlChar *)"url"); } if (url) { LOG(LOG_DEBUG,"OPML import: found RSS outline with url = %s",url); std::string nurl = std::string(url); // Liferea uses a pipe to signal feeds read from the output of // a program in its OPMLs. Convert them to our syntax. if (*url == '|') { nurl = utils::strprintf("exec:%s", url+1); LOG(LOG_DEBUG,"OPML import: liferea-style url %s converted to %s", url, nurl.c_str()); } // Handle OPML filters. char * filtercmd = (char *)xmlGetProp(node, (const xmlChar *)"filtercmd"); if (filtercmd) { LOG(LOG_DEBUG,"OPML import: adding filter command %s to url %s", filtercmd, nurl.c_str()); nurl.insert(0, utils::strprintf("filter:%s:", filtercmd)); xmlFree(filtercmd); } xmlFree(url); // Filters and scripts may have arguments, so, quote them when needed. url = (char*) xmlStrdup((const xmlChar*)utils::quote_if_necessary(nurl).c_str()); assert(url); bool found = false; LOG(LOG_DEBUG, "OPML import: size = %u", urlcfg->get_urls().size()); if (urlcfg->get_urls().size() > 0) { for (std::vector::iterator it = urlcfg->get_urls().begin(); it != urlcfg->get_urls().end(); ++it) { if (*it == url) { found = true; } } } if (!found) { LOG(LOG_DEBUG,"OPML import: added url = %s",url); urlcfg->get_urls().push_back(std::string(url)); if (tag.length() > 0) { LOG(LOG_DEBUG, "OPML import: appending tag %s to url %s", tag.c_str(), url); urlcfg->get_tags(url).push_back(tag); } } else { LOG(LOG_DEBUG,"OPML import: url = %s is already in list",url); } xmlFree(url); } else { char * text = (char *)xmlGetProp(node, (const xmlChar *)"text"); if (!text) text = (char *)xmlGetProp(node, (const xmlChar *)"title"); if (text) { if (newtag.length() > 0) { newtag.append("/"); } newtag.append(text); xmlFree(text); } } } rec_find_rss_outlines(node->children, newtag); node = node->next; } } std::vector > controller::search_for_items(const std::string& query, const std::string& feedurl) { std::vector > items = rsscache->search_for_items(query, feedurl); LOG(LOG_DEBUG, "controller::search_for_items: setting feed pointers"); for (std::vector >::iterator it=items.begin();it!=items.end();++it) { (*it)->set_feedptr(get_feed_by_url((*it)->feedurl())); } return items; } std::tr1::shared_ptr controller::get_feed_by_url(const std::string& feedurl) { for (std::vector >::iterator it=feeds.begin();it!=feeds.end();++it) { if (feedurl == (*it)->rssurl()) return *it; } return std::tr1::shared_ptr(); } bool controller::is_valid_podcast_type(const std::string& /* mimetype */) { return true; } void controller::enqueue_url(const std::string& url, std::tr1::shared_ptr feed) { bool url_found = false; std::fstream f; f.open(queue_file.c_str(), std::fstream::in); if (f.is_open()) { do { std::string line; getline(f, line); if (!f.eof() && line.length() > 0) { std::vector fields = utils::tokenize_quoted(line); if (!fields.empty() && fields[0] == url) { url_found = true; break; } } } while (!f.eof()); f.close(); } if (!url_found) { f.open(queue_file.c_str(), std::fstream::app | std::fstream::out); std::string filename = generate_enqueue_filename(url, feed); f << url << " " << stfl::quote(filename) << std::endl; f.close(); } } void controller::reload_urls_file() { urlcfg->reload(); std::vector > new_feeds; unsigned int i = 0; for (std::vector::const_iterator it=urlcfg->get_urls().begin();it!=urlcfg->get_urls().end();++it,++i) { bool found = false; for (std::vector >::iterator jt=feeds.begin();jt!=feeds.end();++jt) { if (*it == (*jt)->rssurl()) { found = true; (*jt)->set_tags(urlcfg->get_tags(*it)); (*jt)->set_order(i); new_feeds.push_back(*jt); break; } } if (!found) { std::tr1::shared_ptr new_feed(new rss_feed(rsscache)); try { new_feed->set_rssurl(*it); } catch (const std::string& str) { LOG(LOG_USERERROR, "ignored invalid RSS URL '%s'", it->c_str()); continue; } new_feed->set_tags(urlcfg->get_tags(*it)); new_feed->set_order(i); try { bool ignore_disp = (cfg.get_configvalue("ignore-mode") == "display"); rsscache->internalize_rssfeed(new_feed, ignore_disp ? &ign : NULL); } catch(const dbexception& e) { LOG(LOG_ERROR, "controller::reload_urls_file: caught exception: %s", e.what()); throw; } new_feeds.push_back(new_feed); } } { scope_mutex feedslock(&feeds_mutex); feeds = new_feeds; } sort_feeds(); update_feedlist(); } void controller::edit_urls_file() { const char * editor; editor = getenv("VISUAL"); if (!editor) editor = getenv("EDITOR"); if (!editor) editor = "vi"; std::string cmdline = utils::strprintf("%s \"%s\"", editor, utils::replace_all(url_file,"\"","\\\"").c_str()); v->push_empty_formaction(); stfl::reset(); LOG(LOG_DEBUG, "controller::edit_urls_file: running `%s'", cmdline.c_str()); ::system(cmdline.c_str()); v->pop_current_formaction(); reload_urls_file(); } std::string controller::bookmark(const std::string& url, const std::string& title, const std::string& description) { std::string bookmark_cmd = cfg.get_configvalue("bookmark-cmd"); bool is_interactive = cfg.get_configvalue_as_bool("bookmark-interactive"); if (bookmark_cmd.length() > 0) { std::string cmdline = utils::strprintf("%s '%s' %s %s", bookmark_cmd.c_str(), utils::replace_all(url,"'", "%27").c_str(), stfl::quote(title).c_str(), stfl::quote(description).c_str()); LOG(LOG_DEBUG, "controller::bookmark: cmd = %s", cmdline.c_str()); if (is_interactive) { v->push_empty_formaction(); stfl::reset(); ::system(cmdline.c_str()); v->pop_current_formaction(); return ""; } else { char * my_argv[4]; my_argv[0] = const_cast("/bin/sh"); my_argv[1] = const_cast("-c"); my_argv[2] = const_cast(cmdline.c_str()); my_argv[3] = NULL; return utils::run_program(my_argv, ""); } } else { return _("bookmarking support is not configured. Please set the configuration variable `bookmark-cmd' accordingly."); } } void controller::execute_commands(char ** argv, unsigned int i) { if (v->formaction_stack_size() > 0) v->pop_current_formaction(); for (;argv[i];++i) { LOG(LOG_DEBUG, "controller::execute_commands: executing `%s'", argv[i]); std::string cmd(argv[i]); if (cmd == "reload") { reload_all(true); } else if (cmd == "print-unread") { std::cout << utils::strprintf(_("%u unread articles"), rsscache->get_unread_count()) << std::endl; } else { std::cerr << utils::strprintf(_("%s: %s: unknown command"), argv[0], argv[i]) << std::endl; ::std::exit(EXIT_FAILURE); } } } std::string controller::write_temporary_item(std::tr1::shared_ptr item) { char filename[1024]; snprintf(filename, sizeof(filename), "/tmp/newsbeuter-article.XXXXXX"); int fd = mkstemp(filename); if (fd != -1) { write_item(item, filename); close(fd); return std::string(filename); } else { return ""; } } void controller::write_item(std::tr1::shared_ptr item, const std::string& filename) { std::fstream f; f.open(filename.c_str(),std::fstream::out); if (!f.is_open()) throw exception(errno); write_item(item, f); } void controller::write_item(std::tr1::shared_ptr item, std::ostream& ostr) { std::vector lines; std::vector links; // not used std::string title(_("Title: ")); title.append(item->title()); lines.push_back(title); std::string author(_("Author: ")); author.append(item->author()); lines.push_back(author); std::string date(_("Date: ")); date.append(item->pubDate()); lines.push_back(date); std::string link(_("Link: ")); link.append(item->link()); lines.push_back(link); if (item->enclosure_url() != "") { std::string dlurl(_("Podcast Download URL: ")); dlurl.append(item->enclosure_url()); lines.push_back(dlurl); } lines.push_back(std::string("")); unsigned int width = cfg.get_configvalue_as_int("text-width"); if (width == 0) width = 80; htmlrenderer rnd(width, true); rnd.render(item->description(), lines, links, item->feedurl()); for (std::vector::iterator it=lines.begin();it!=lines.end();++it) { ostr << *it << std::endl; } } void controller::mark_deleted(const std::string& guid, bool b) { rsscache->mark_item_deleted(guid, b); } std::string controller::prepare_message(unsigned int pos, unsigned int max) { if (max > 0) { return utils::strprintf("(%u/%u) ", pos, max); } return ""; } void controller::save_feed(std::tr1::shared_ptr feed, unsigned int pos) { if (!feed->is_empty()) { LOG(LOG_DEBUG, "controller::save_feed: feed is nonempty, saving"); rsscache->externalize_rssfeed(feed, ign.matches_resetunread(feed->rssurl())); LOG(LOG_DEBUG, "controller::save_feed: after externalize_rssfeed"); bool ignore_disp = (cfg.get_configvalue("ignore-mode") == "display"); rsscache->internalize_rssfeed(feed, ignore_disp ? &ign : NULL); LOG(LOG_DEBUG, "controller::save_feed: after internalize_rssfeed"); feed->set_tags(urlcfg->get_tags(feed->rssurl())); { unsigned int order = feeds[pos]->get_order(); scope_mutex itemlock(&feeds[pos]->item_mutex); feeds[pos]->clear_items(); feed->set_order(order); } feeds[pos] = feed; v->notify_itemlist_change(feeds[pos]); } else { LOG(LOG_DEBUG, "controller::save_feed: feed is empty, not saving"); } } void controller::enqueue_items(std::tr1::shared_ptr feed) { if (!cfg.get_configvalue_as_bool("podcast-auto-enqueue")) return; scope_mutex lock(&feed->item_mutex); for (std::vector >::iterator it=feed->items().begin();it!=feed->items().end();++it) { if (!(*it)->enqueued() && (*it)->enclosure_url().length() > 0) { LOG(LOG_DEBUG, "controller::enqueue_items: enclosure_url = `%s' enclosure_type = `%s'", (*it)->enclosure_url().c_str(), (*it)->enclosure_type().c_str()); if (is_valid_podcast_type((*it)->enclosure_type()) && utils::is_http_url((*it)->enclosure_url())) { LOG(LOG_INFO, "controller::enqueue_items: enqueuing `%s'", (*it)->enclosure_url().c_str()); enqueue_url((*it)->enclosure_url(), feed); (*it)->set_enqueued(true); rsscache->update_rssitem_unread_and_enqueued(*it, feed->rssurl()); } } } } std::string controller::generate_enqueue_filename(const std::string& url, std::tr1::shared_ptr feed) { std::string dlformat = cfg.get_configvalue("download-path"); if (dlformat[dlformat.length()-1] != NEWSBEUTER_PATH_SEP[0]) dlformat.append(NEWSBEUTER_PATH_SEP); fmtstr_formatter fmt; fmt.register_fmt('n', feed->title()); fmt.register_fmt('h', get_hostname_from_url(url)); std::string dlpath = fmt.do_format(dlformat); char buf[2048]; snprintf(buf, sizeof(buf), "%s", url.c_str()); char * base = basename(buf); if (!base || strlen(base) == 0) { char lbuf[128]; time_t t = time(NULL); strftime(lbuf, sizeof(lbuf), "%Y-%b-%d-%H%M%S.unknown", localtime(&t)); dlpath.append(lbuf); } else { dlpath.append(base); } return dlpath; } std::string controller::get_hostname_from_url(const std::string& url) { xmlURIPtr uri = xmlParseURI(url.c_str()); std::string hostname; if (uri) { hostname = uri->server; xmlFreeURI(uri); } return hostname; } void controller::import_read_information(const std::string& readinfofile) { std::vector guids; std::ifstream f(readinfofile.c_str()); std::string line; getline(f,line); if (!f.is_open()) { return; } while (f.is_open() && !f.eof()) { guids.push_back(line); getline(f, line); } rsscache->mark_items_read_by_guid(guids); } void controller::export_read_information(const std::string& readinfofile) { std::vector guids = rsscache->get_read_item_guids(); std::fstream f; f.open(readinfofile.c_str(), std::fstream::out); if (f.is_open()) { for (std::vector::iterator it=guids.begin();it!=guids.end();++it) { f << *it << std::endl; } } } struct sort_feeds_by_firsttag : public std::binary_function, std::tr1::shared_ptr, bool> { sort_feeds_by_firsttag() { } bool operator()(std::tr1::shared_ptr a, std::tr1::shared_ptr b) { if (a->get_firsttag().length() == 0 || b->get_firsttag().length() == 0) { return a->get_firsttag().length() > b->get_firsttag().length(); } return strcasecmp(a->get_firsttag().c_str(), b->get_firsttag().c_str()) < 0; } }; struct sort_feeds_by_title : public std::binary_function, std::tr1::shared_ptr, bool> { sort_feeds_by_title() { } bool operator()(std::tr1::shared_ptr a, std::tr1::shared_ptr b) { return strcasecmp(a->title().c_str(), b->title().c_str()) < 0; } }; struct sort_feeds_by_articles : public std::binary_function, std::tr1::shared_ptr, bool> { sort_feeds_by_articles() { } bool operator()(std::tr1::shared_ptr a, std::tr1::shared_ptr b) { return a->total_item_count() < b->total_item_count(); } }; struct sort_feeds_by_unread_articles : public std::binary_function, std::tr1::shared_ptr, bool> { sort_feeds_by_unread_articles() { } bool operator()(std::tr1::shared_ptr a, std::tr1::shared_ptr b) { return a->unread_item_count() < b->unread_item_count(); } }; struct sort_feeds_by_order : public std::binary_function, std::tr1::shared_ptr, bool> { sort_feeds_by_order() { } bool operator()(std::tr1::shared_ptr a, std::tr1::shared_ptr b) { return a->get_order() < b->get_order(); } }; void controller::sort_feeds() { scope_mutex feedslock(&feeds_mutex); std::vector sortmethod_info = utils::tokenize(cfg.get_configvalue("feed-sort-order"), "-"); std::string sortmethod = sortmethod_info[0]; std::string direction = "desc"; if (sortmethod_info.size() > 1) direction = sortmethod_info[1]; if (sortmethod == "none") { std::stable_sort(feeds.begin(), feeds.end(), sort_feeds_by_order()); } else if (sortmethod == "firsttag") { std::stable_sort(feeds.begin(), feeds.end(), sort_feeds_by_firsttag()); } else if (sortmethod == "title") { std::stable_sort(feeds.begin(), feeds.end(), sort_feeds_by_title()); } else if (sortmethod == "articlecount") { std::stable_sort(feeds.begin(), feeds.end(), sort_feeds_by_articles()); } else if (sortmethod == "unreadarticlecount") { std::stable_sort(feeds.begin(), feeds.end(), sort_feeds_by_unread_articles()); } if (direction == "asc") { std::reverse(feeds.begin(), feeds.end()); } } void controller::update_config() { v->set_regexmanager(&rxman); v->update_bindings(); if (colorman.colors_loaded()) { v->set_colors(colorman.get_fgcolors(), colorman.get_bgcolors(), colorman.get_attributes()); v->apply_colors_to_all_formactions(); } if (cfg.get_configvalue("error-log").length() > 0) { logger::getInstance().set_errorlogfile(cfg.get_configvalue("error-log").c_str()); } } void controller::load_configfile(const std::string& filename) { if (cfgparser.parse(filename, true)) { update_config(); } else { v->show_error(utils::strprintf(_("Error: couldn't open configuration file `%s'!"), filename.c_str())); } } void controller::dump_config(const std::string& filename) { std::vector configlines; cfg.dump_config(configlines); if (v) { v->get_keys()->dump_config(configlines); } ign.dump_config(configlines); filters.dump_config(configlines); colorman.dump_config(configlines); rxman.dump_config(configlines); std::fstream f; f.open(filename.c_str(), std::fstream::out); if (f.is_open()) { for (std::vector::iterator it=configlines.begin();it!=configlines.end();++it) { f << *it << std::endl; } } } unsigned int controller::get_pos_of_next_unread(unsigned int pos) { scope_mutex feedslock(&feeds_mutex); for (pos++;pos < feeds.size();pos++) { if (feeds[pos]->unread_item_count() > 0) break; } return pos; } void controller::update_flags(std::tr1::shared_ptr item) { if (api) { api->update_article_flags(item->oldflags(), item->flags(), item->guid()); } item->update_flags(); } std::vector > controller::get_all_feeds() { std::vector > tmpfeeds; { scope_mutex feedslock(&feeds_mutex); tmpfeeds = feeds; } return tmpfeeds; } std::vector > controller::get_all_feeds_unlocked() { return feeds; } unsigned int controller::get_feed_count_per_tag(const std::string& tag) { unsigned int count = 0; scope_mutex feedslock(&feeds_mutex); for (std::vector >::const_iterator it=feeds.begin();it!=feeds.end();it++) { if ((*it)->matches_tag(tag)) { count++; } } return count; } } newsbeuter-2.7/src/dialogs_formaction.cpp000066400000000000000000000057371220711462700207210ustar00rootroot00000000000000#include #include #include #include #include #include namespace newsbeuter { dialogs_formaction::dialogs_formaction(view * vv, std::string formstr) : formaction(vv, formstr), update_list(true) { } dialogs_formaction::~dialogs_formaction() { } void dialogs_formaction::init() { set_keymap_hints(); unsigned int width = utils::to_u(f->get("dialogs:w")); std::string title_format = v->get_cfg()->get_configvalue("dialogs-title-format"); fmtstr_formatter fmt; fmt.register_fmt('N', PROGRAM_NAME); fmt.register_fmt('V', PROGRAM_VERSION); f->set("head", fmt.do_format(title_format, width)); } void dialogs_formaction::prepare() { if (update_list) { listformatter listfmt; std::vector > formaction_names = v->get_formaction_names(); unsigned int i = 1; for (std::vector >::iterator it=formaction_names.begin();it!=formaction_names.end();++it,i++) { LOG(LOG_DEBUG, "dialogs_formaction::prepare: p1 = %p p2 = %p", v->get_current_formaction().get(), get_parent_formaction().get()); listfmt.add_line(utils::strprintf("%4u %s %s", i, (v->get_formaction(it->first).get() == get_parent_formaction().get()) ? "*" : " ", it->second.c_str()), it->first); } f->modify("dialogs", "replace_inner", listfmt.format_list()); update_list = false; } } keymap_hint_entry * dialogs_formaction::get_keymap_hint() { static keymap_hint_entry hints[] = { { OP_QUIT, _("Close") }, { OP_OPEN, _("Goto Dialog") }, { OP_CLOSEDIALOG, _("Close Dialog") }, { OP_NIL, NULL } }; return hints; } void dialogs_formaction::process_operation(operation op, bool /* automatic */, std::vector * /* args */) { switch (op) { case OP_OPEN: { std::string dialogposname = f->get("dialogpos"); unsigned int dialogpos = utils::to_u(dialogposname); if (dialogposname.length() > 0) { v->set_current_formaction(dialogpos); } else { v->show_error(_("No item selected!")); } } break; case OP_CLOSEDIALOG: { std::string dialogposname = f->get("dialogpos"); unsigned int dialogpos = utils::to_u(dialogposname); if (dialogposname.length() > 0) { if (dialogpos != 0) { v->remove_formaction(dialogpos); update_list = true; } else { v->show_error(_("Error: you can't remove the feed list!")); } } else { v->show_error(_("No item selected!")); } } break; case OP_QUIT: v->pop_current_formaction(); break; default: break; } } std::string dialogs_formaction::title() { return ""; // will never be displayed } void dialogs_formaction::handle_cmdline(const std::string& cmd) { unsigned int idx = 0; if (1==sscanf(cmd.c_str(), "%u", &idx)) { if (idx <= v->formaction_stack_size()) { f->set("dialogpos", utils::to_string(idx - 1)); } else { v->show_error(_("Invalid position!")); } } else { formaction::handle_cmdline(cmd); } } } newsbeuter-2.7/src/download.cpp000066400000000000000000000033551220711462700166570ustar00rootroot00000000000000#include #include #include #include namespace podbeuter { /* * the download class represents a single download entry in podbeuter. * It manages the filename, the URL, the current state, the progress, etc. */ download::download(pb_controller * c) : dlstatus(DL_QUEUED), cursize(0.0), totalsize(0.0), curkbps(0.0), offs(0), ctrl(c) { } download::~download() { } const char * download::filename() { return fn.c_str(); } const char * download::url() { return url_.c_str(); } void download::set_filename(const std::string& str) { fn = str; } double download::percents_finished() { if (totalsize < 1) { return 0.0; } else { return (100*(offs + cursize))/(offs + totalsize); } } const char * download::status_text() { switch (dlstatus) { case DL_QUEUED: return _("queued"); case DL_DOWNLOADING: return _("downloading"); case DL_CANCELLED: return _("cancelled"); case DL_DELETED: return _("deleted"); case DL_FINISHED: return _("finished"); case DL_FAILED: return _("failed"); case DL_ALREADY_DOWNLOADED: return _("incomplete"); case DL_READY: return _("ready"); case DL_PLAYED: return _("played"); default: return _("unknown (bug)."); } } void download::set_url(const std::string& u) { url_ = u; } void download::set_progress(double cur, double max) { if (cur > cursize) ctrl->set_view_update_necessary(true); cursize = cur; totalsize = max; } void download::set_status(dlstatus_t dls) { if (dlstatus != dls) { ctrl->set_view_update_necessary(true); } dlstatus = dls; } void download::set_kbps(double k) { curkbps = k; } double download::kbps() { return curkbps; } void download::set_offset(unsigned long offset) { offs = offset; } } newsbeuter-2.7/src/downloadthread.cpp000066400000000000000000000017121220711462700200420ustar00rootroot00000000000000#include #include namespace newsbeuter { downloadthread::downloadthread(controller * c, std::vector * idxs) : ctrl(c) { if (idxs) indexes = *idxs; } downloadthread::~downloadthread() { } void downloadthread::run() { /* * the downloadthread class drives the reload-all process. * A downloadthread is spawned whenever "reload all" is invoked, and whenever an auto-reload * comes up. */ LOG(LOG_DEBUG, "downloadthread::run: inside downloadthread, reloading all feeds..."); if (ctrl->trylock_reload_mutex()) { if (indexes.size() == 0) { ctrl->reload_all(); } else { ctrl->reload_indexes(indexes); } ctrl->unlock_reload_mutex(); } this->detach(); } reloadrangethread::reloadrangethread(controller * c, unsigned int start, unsigned int end, unsigned int size, bool unattended) : ctrl(c), s(start), e(end), ss(size), u(unattended) { } void reloadrangethread::run() { ctrl->reload_range(s, e, ss, u); } } newsbeuter-2.7/src/exception.cpp000066400000000000000000000023601220711462700170410ustar00rootroot00000000000000#include #include #include #include #include #include namespace newsbeuter { exception::exception(unsigned int error_code) : ecode(error_code) { } exception::~exception() throw() { } const char * exception::what() const throw() { return ::strerror(ecode); } const char * matcherexception::what() const throw() { static std::string errmsg; switch (type) { case ATTRIB_UNAVAIL: errmsg = utils::strprintf(_("attribute `%s' is not available."), addinfo.c_str()); break; case INVALID_REGEX: errmsg = utils::strprintf(_("regular expression '%s' is invalid: %s"), addinfo.c_str(), addinfo2.c_str()); break; default: errmsg = ""; } return errmsg.c_str(); } confighandlerexception::confighandlerexception(action_handler_status e) { msg = get_errmsg(e); } const char * confighandlerexception::get_errmsg(action_handler_status status) { switch (status) { case AHS_INVALID_PARAMS: return _("invalid parameters."); case AHS_TOO_FEW_PARAMS: return _("too few parameters."); case AHS_INVALID_COMMAND: return _("unknown command (bug)."); case AHS_FILENOTFOUND: return _("file couldn't be opened."); default: return _("unknown error (bug)."); } } } newsbeuter-2.7/src/feedlist_formaction.cpp000066400000000000000000000614601220711462700210710ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define FILTER_UNREAD_FEEDS "unread_count != \"0\"" namespace newsbeuter { feedlist_formaction::feedlist_formaction(view * vv, std::string formstr) : formaction(vv,formstr), zero_feedpos(false), feeds_shown(0), auto_open(false), quit(false), apply_filter(false), search_dummy_feed(new rss_feed(v->get_ctrl()->get_cache())), filterpos(0), set_filterpos(false), rxman(0), old_width(0) { assert(true==m.parse(FILTER_UNREAD_FEEDS)); valid_cmds.push_back("tag"); valid_cmds.push_back("goto"); std::sort(valid_cmds.begin(), valid_cmds.end()); old_sort_order = v->get_cfg()->get_configvalue("feed-sort-order"); } void feedlist_formaction::init() { set_keymap_hints(); f->run(-3); // compute all widget dimensions if(v->get_ctrl()->get_refresh_on_start()) { v->get_ctrl()->start_reload_all_thread(); } v->get_ctrl()->update_feedlist(); /* * This is kind of a hack. * The feedlist_formaction is responsible for starting up the reloadthread, which is responsible * for regularly spawning downloadthreads. */ reloadthread * rt = new reloadthread(v->get_ctrl(), v->get_cfg()); rt->start(); apply_filter = !(v->get_cfg()->get_configvalue_as_bool("show-read-feeds")); } feedlist_formaction::~feedlist_formaction() { } void feedlist_formaction::prepare() { unsigned int width = utils::to_u(f->get("items:w")); if (old_width != width) { do_redraw = true; old_width = width; LOG(LOG_DEBUG, "feedlist_formaction::prepare: apparent resize"); } std::string sort_order = v->get_cfg()->get_configvalue("feed-sort-order"); if (sort_order != old_sort_order) { v->get_ctrl()->sort_feeds(); old_sort_order = sort_order; do_redraw = true; } if (do_redraw) { LOG(LOG_DEBUG, "feedlist_formaction::prepare: doing redraw"); v->get_ctrl()->update_feedlist(); set_pos(); do_redraw = false; } } void feedlist_formaction::process_operation(operation op, bool automatic, std::vector * args) { std::string feedpos = f->get("feedposname"); std::istringstream posname(feedpos); unsigned int pos = 0; posname >> pos; switch (op) { case OP_OPEN: { if (f->get_focus() == "feeds") { if (automatic && args->size() > 0) { std::istringstream x((*args)[0]); x >> pos; } LOG(LOG_INFO, "feedlist_formaction: opening feed at position `%s'",feedpos.c_str()); if (feeds_shown > 0 && feedpos.length() > 0) { v->push_itemlist(pos); } else { v->show_error(_("No feed selected!")); // should not happen } } } break; case OP_RELOAD: { LOG(LOG_INFO, "feedlist_formaction: reloading feed at position `%s'",feedpos.c_str()); if (feeds_shown > 0 && feedpos.length() > 0) { v->get_ctrl()->reload(pos); } else { v->show_error(_("No feed selected!")); // should not happen } } break; case OP_INT_RESIZE: do_redraw = true; break; case OP_RELOADURLS: v->get_ctrl()->reload_urls_file(); break; case OP_SORT: { char c = v->confirm(_("Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?"), _("ftaun")); if (!c) break; std::string result(1, c); if (result == _("f")) { v->get_cfg()->set_configvalue("feed-sort-order", "firsttag-desc"); } else if (result == _("t")) { v->get_cfg()->set_configvalue("feed-sort-order", "title-desc"); } else if (result == _("a")) { v->get_cfg()->set_configvalue("feed-sort-order", "articlecount-desc"); } else if (result == _("u")) { v->get_cfg()->set_configvalue("feed-sort-order", "unreadarticlecount-desc"); } else if (result == _("n")) { v->get_cfg()->set_configvalue("feed-sort-order", "none-desc"); } } break; case OP_REVSORT: { char c = v->confirm(_("Reverse Sort by (f)irsttag/(t)itle/(a)rticlecount/(u)nreadarticlecount/(n)one?"), _("ftaun")); if (!c) break; std::string result(1, c); if (result == _("f")) { v->get_cfg()->set_configvalue("feed-sort-order", "firsttag-asc"); } else if (result == _("t")) { v->get_cfg()->set_configvalue("feed-sort-order", "title-asc"); } else if (result == _("a")) { v->get_cfg()->set_configvalue("feed-sort-order", "articlecount-asc"); } else if (result == _("u")) { v->get_cfg()->set_configvalue("feed-sort-order", "unreadarticlecount-asc"); } else if (result == _("n")) { v->get_cfg()->set_configvalue("feed-sort-order", "none-asc"); } } break; case OP_OPENINBROWSER: if (feeds_shown > 0 && feedpos.length() > 0) { std::tr1::shared_ptr feed = v->get_ctrl()->get_feed(pos); if (feed) { LOG(LOG_INFO, "feedlist_formaction: opening feed at position `%s': %s", feedpos.c_str(), feed->link().c_str()); v->open_in_browser(feed->link()); } } else { v->show_error(_("No feed selected!")); } break; case OP_RELOADALL: LOG(LOG_INFO, "feedlist_formaction: reloading all feeds"); { bool reload_only_visible_feeds = v->get_cfg()->get_configvalue_as_bool("reload-only-visible-feeds"); std::vector idxs; for (std::vector::iterator it=visible_feeds.begin();it!=visible_feeds.end();++it) { idxs.push_back(it->second); } v->get_ctrl()->start_reload_all_thread(reload_only_visible_feeds ? &idxs : NULL); } break; case OP_MARKFEEDREAD: { LOG(LOG_INFO, "feedlist_formaction: marking feed read at position `%s'",feedpos.c_str()); if (feeds_shown > 0 && feedpos.length() > 0) { v->set_status(_("Marking feed read...")); try { v->get_ctrl()->mark_all_read(pos); do_redraw = true; v->set_status(""); if (feeds_shown > (pos + 1) && !apply_filter) { f->set("feedpos", utils::to_string(pos + 1)); } } catch (const dbexception& e) { v->show_error(utils::strprintf(_("Error: couldn't mark feed read: %s"), e.what())); } } else { v->show_error(_("No feed selected!")); // should not happen } } break; case OP_TOGGLESHOWREAD: m.parse(FILTER_UNREAD_FEEDS); LOG(LOG_INFO, "feedlist_formaction: toggling show-read-feeds"); if (v->get_cfg()->get_configvalue_as_bool("show-read-feeds")) { v->get_cfg()->set_configvalue("show-read-feeds","no"); apply_filter = true; } else { v->get_cfg()->set_configvalue("show-read-feeds","yes"); apply_filter = false; } save_filterpos(); do_redraw = true; break; case OP_NEXTUNREAD: { unsigned int local_tmp; LOG(LOG_INFO, "feedlist_formaction: jumping to next unread feed"); if (!jump_to_next_unread_feed(local_tmp)) { v->show_error(_("No feeds with unread items.")); } } break; case OP_PREVUNREAD: { unsigned int local_tmp; LOG(LOG_INFO, "feedlist_formaction: jumping to previous unread feed"); if (!jump_to_previous_unread_feed(local_tmp)) { v->show_error(_("No feeds with unread items.")); } } break; case OP_NEXT: { unsigned int local_tmp; LOG(LOG_INFO, "feedlist_formaction: jumping to next feed"); if (!jump_to_next_feed(local_tmp)) { v->show_error(_("Already on last feed.")); } } break; case OP_PREV: { unsigned int local_tmp; LOG(LOG_INFO, "feedlist_formaction: jumping to previous feed"); if (!jump_to_previous_feed(local_tmp)) { v->show_error(_("Already on first feed.")); } } break; case OP_RANDOMUNREAD: { unsigned int local_tmp; LOG(LOG_INFO, "feedlist_formaction: jumping to random unread feed"); if (!jump_to_random_unread_feed(local_tmp)) { v->show_error(_("No feeds with unread items.")); } } break; case OP_MARKALLFEEDSREAD: LOG(LOG_INFO, "feedlist_formaction: marking all feeds read"); v->set_status(_("Marking all feeds read...")); v->get_ctrl()->catchup_all(); v->set_status(""); do_redraw = true; break; case OP_CLEARTAG: tag = ""; do_redraw = true; zero_feedpos = true; break; case OP_SETTAG: if (tags.size() > 0) { std::string newtag; if (automatic && args->size() > 0) { newtag = (*args)[0]; } else { newtag = v->select_tag(tags); } if (newtag != "") { tag = newtag; do_redraw = true; zero_feedpos = true; } } else { v->show_error(_("No tags defined.")); } break; case OP_SELECTFILTER: if (v->get_ctrl()->get_filters().size() > 0) { std::string newfilter; if (automatic && args->size() > 0) { newfilter = (*args)[0]; } else { newfilter = v->select_filter(v->get_ctrl()->get_filters().get_filters()); } if (newfilter != "") { filterhistory.add_line(newfilter); if (newfilter.length() > 0) { if (!m.parse(newfilter)) { v->show_error(utils::strprintf(_("Error: couldn't parse filter command `%s': %s"), newfilter.c_str(), m.get_parse_error().c_str())); m.parse(FILTER_UNREAD_FEEDS); } else { save_filterpos(); apply_filter = true; do_redraw = true; } } } } else { v->show_error(_("No filters defined.")); } break; case OP_SEARCH: if (automatic && args->size() > 0) { qna_responses.clear(); // when in automatic mode, we manually fill the qna_responses vector from the arguments // and then run the finished_qna() by ourselves to simulate a "Q&A" session that is // in fact macro-driven. qna_responses.push_back((*args)[0]); finished_qna(OP_INT_START_SEARCH); } else { std::vector qna; qna.push_back(qna_pair(_("Search for: "), "")); this->start_qna(qna, OP_INT_START_SEARCH, &searchhistory); } break; case OP_CLEARFILTER: apply_filter = !(v->get_cfg()->get_configvalue_as_bool("show-read-feeds")); m.parse(FILTER_UNREAD_FEEDS); do_redraw = true; save_filterpos(); break; case OP_SETFILTER: if (automatic && args->size() > 0) { qna_responses.clear(); qna_responses.push_back((*args)[0]); finished_qna(OP_INT_END_SETFILTER); } else { std::vector qna; qna.push_back(qna_pair(_("Filter: "), "")); this->start_qna(qna, OP_INT_END_SETFILTER, &filterhistory); } break; case OP_EDIT_URLS: v->get_ctrl()->edit_urls_file(); break; case OP_QUIT: LOG(LOG_INFO, "feedlist_formaction: quitting"); if (automatic || !v->get_cfg()->get_configvalue_as_bool("confirm-exit") || v->confirm(_("Do you really want to quit (y:Yes n:No)? "), _("yn")) == *_("y")) { quit = true; } break; case OP_HARDQUIT: LOG(LOG_INFO, "feedlist_formaction: hard quitting"); quit = true; break; case OP_HELP: v->push_help(); break; default: break; } if (quit) { while (v->formaction_stack_size() > 0) v->pop_current_formaction(); } } void feedlist_formaction::update_visible_feeds(std::vector >& feeds) { assert(v->get_cfg() != NULL); // must not happen visible_feeds.clear(); unsigned int i = 0; for (std::vector >::iterator it = feeds.begin(); it != feeds.end(); ++it, ++i) { (*it)->set_index(i+1); if ((tag == "" || (*it)->matches_tag(tag)) && (!apply_filter || m.matches(it->get())) && !(*it)->hidden()) { visible_feeds.push_back(feedptr_pos_pair(*it,i)); } } feeds_shown = visible_feeds.size(); } void feedlist_formaction::set_feedlist(std::vector >& feeds) { assert(v->get_cfg() != NULL); // must not happen unsigned int width = utils::to_u(f->get("feeds:w")); unsigned int i = 0; unread_feeds = 0; std::string feedlist_format = v->get_cfg()->get_configvalue("feedlist-format"); listformatter listfmt; update_visible_feeds(feeds); for (std::vector::iterator it = visible_feeds.begin(); it != visible_feeds.end(); ++it, ++i) { std::string title = get_title(it->first); if (it->first->unread_item_count() > 0) ++unread_feeds; listfmt.add_line(format_line(feedlist_format, it->first, it->second, width), it->second); } total_feeds = i; f->modify("feeds","replace_inner",listfmt.format_list(rxman, "feedlist")); std::string title_format = v->get_cfg()->get_configvalue("feedlist-title-format"); fmtstr_formatter fmt; fmt.register_fmt('T', tag); fmt.register_fmt('N', PROGRAM_NAME); fmt.register_fmt('V', PROGRAM_VERSION); fmt.register_fmt('u', utils::to_string(unread_feeds)); fmt.register_fmt('t', utils::to_string(i)); f->set("head", fmt.do_format(title_format, width)); } void feedlist_formaction::set_tags(const std::vector& t) { tags = t; } keymap_hint_entry * feedlist_formaction::get_keymap_hint() { static keymap_hint_entry hints[] = { { OP_QUIT, _("Quit") }, { OP_OPEN, _("Open") }, { OP_NEXTUNREAD, _("Next Unread") }, { OP_RELOAD, _("Reload") }, { OP_RELOADALL, _("Reload All") }, { OP_MARKFEEDREAD, _("Mark Read") }, { OP_MARKALLFEEDSREAD, _("Catchup All") }, { OP_SEARCH, _("Search") }, { OP_HELP, _("Help") }, { OP_NIL, NULL } }; return hints; } bool feedlist_formaction::jump_to_previous_unread_feed(unsigned int& feedpos) { unsigned int curpos; std::istringstream is(f->get("feedpos")); is >> curpos; LOG(LOG_DEBUG, "feedlist_formaction::jump_to_previous_unread_feed: searching for unread feed"); for (int i=curpos-1;i>=0;--i) { LOG(LOG_DEBUG, "feedlist_formaction::jump_to_previous_unread_feed: visible_feeds[%u] unread items: %u", i, visible_feeds[i].first->unread_item_count()); if (visible_feeds[i].first->unread_item_count() > 0) { LOG(LOG_DEBUG, "feedlist_formaction::jump_to_previous_unread_feed: hit"); f->set("feedpos", utils::to_string(i)); feedpos = visible_feeds[i].second; return true; } } for (int i=visible_feeds.size()-1;i>=static_cast(curpos);--i) { LOG(LOG_DEBUG, "feedlist_formaction::jump_to_previous_unread_feed: visible_feeds[%u] unread items: %u", i, visible_feeds[i].first->unread_item_count()); if (visible_feeds[i].first->unread_item_count() > 0) { LOG(LOG_DEBUG, "feedlist_formaction::jump_to_previous_unread_feed: hit"); f->set("feedpos", utils::to_string(i)); feedpos = visible_feeds[i].second; return true; } } return false; } void feedlist_formaction::goto_feed(const std::string& str) { unsigned int curpos; std::istringstream is(f->get("feedpos")); is >> curpos; LOG(LOG_DEBUG, "feedlist_formaction::goto_feed: curpos = %u str = `%s'", curpos, str.c_str()); for (unsigned int i=curpos+1;ititle().c_str(), str.c_str()) != NULL) { f->set("feedpos", utils::to_string(i)); return; } } for (unsigned int i=0;i<=curpos;++i) { if (strcasestr(visible_feeds[i].first->title().c_str(), str.c_str()) != NULL) { f->set("feedpos", utils::to_string(i)); return; } } } bool feedlist_formaction::jump_to_random_unread_feed(unsigned int& feedpos) { bool unread_feeds_available = false; for (unsigned int i=0;iunread_item_count() > 0) { unread_feeds_available = true; break; } } if (unread_feeds_available) { for (;;) { unsigned int pos = utils::get_random_value(visible_feeds.size()); if (visible_feeds[pos].first->unread_item_count() > 0) { f->set("feedpos", utils::to_string(pos)); feedpos = visible_feeds[pos].second; break; } } } return unread_feeds_available; } bool feedlist_formaction::jump_to_next_unread_feed(unsigned int& feedpos) { unsigned int curpos; std::istringstream is(f->get("feedpos")); is >> curpos; LOG(LOG_DEBUG, "feedlist_formaction::jump_to_next_unread_feed: searching for unread feed"); for (unsigned int i=curpos+1;iunread_item_count()); if (visible_feeds[i].first->unread_item_count() > 0) { LOG(LOG_DEBUG, "feedlist_formaction::jump_to_next_unread_feed: hit"); f->set("feedpos", utils::to_string(i)); feedpos = visible_feeds[i].second; return true; } } for (unsigned int i=0;i<=curpos;++i) { LOG(LOG_DEBUG, "feedlist_formaction::jump_to_next_unread_feed: visible_feeds[%u] unread items: %u", i, visible_feeds[i].first->unread_item_count()); if (visible_feeds[i].first->unread_item_count() > 0) { LOG(LOG_DEBUG, "feedlist_formaction::jump_to_next_unread_feed: hit"); f->set("feedpos", utils::to_string(i)); feedpos = visible_feeds[i].second; return true; } } return false; } bool feedlist_formaction::jump_to_previous_feed(unsigned int& feedpos) { unsigned int curpos; std::istringstream is(f->get("feedpos")); is >> curpos; for (int i=curpos-1;i>=0;--i) { LOG(LOG_DEBUG, "feedlist_formaction::jump_to_previous_feed: visible_feeds[%u]", i); f->set("feedpos", utils::to_string(i)); feedpos = visible_feeds[i].second; return true; } return false; // not sure if we should exit here or continue // wrap to last feed for (int i=visible_feeds.size()-1;i>=static_cast(curpos);--i) { LOG(LOG_DEBUG, "feedlist_formaction::jump_to_previous_feed: visible_feeds[%u]", i); f->set("feedpos", utils::to_string(i)); feedpos = visible_feeds[i].second; return true; } return false; } bool feedlist_formaction::jump_to_next_feed(unsigned int& feedpos) { unsigned int curpos; std::istringstream is(f->get("feedpos")); is >> curpos; for (unsigned int i=curpos+1;iset("feedpos", utils::to_string(i)); feedpos = visible_feeds[i].second; return true; } return false; // not sure if we should exit here or continue // wrap to first feed for (unsigned int i=0;i<=curpos;++i) { LOG(LOG_DEBUG, "feedlist_formaction::jump_to_next_feed: visible_feeds[%u]", i); f->set("feedpos", utils::to_string(i)); feedpos = visible_feeds[i].second; return true; } return false; } std::tr1::shared_ptr feedlist_formaction::get_feed() { unsigned int curpos; std::istringstream is(f->get("feedpos")); is >> curpos; return visible_feeds[curpos].first; } int feedlist_formaction::get_pos(unsigned int realidx) { for (unsigned int i=0;i tokens = utils::tokenize_quoted(cmd, " \t"); if (!tokens.empty()) { if (tokens[0] == "tag") { if (tokens.size() >= 2 && tokens[1] != "") { tag = tokens[1]; do_redraw = true; zero_feedpos = true; } } else if (tokens[0] == "goto") { if (tokens.size() >= 2 && tokens[1] != "") { goto_feed(tokens[1]); } } else { formaction::handle_cmdline(cmd); } } } } void feedlist_formaction::finished_qna(operation op) { formaction::finished_qna(op); // important! switch (op) { case OP_INT_END_SETFILTER: op_end_setfilter(); break; case OP_INT_START_SEARCH: op_start_search(); break; default: break; } } void feedlist_formaction::mark_pos_if_visible(unsigned int pos) { scope_measure m1("feedlist_formaction::mark_pos_if_visible"); unsigned int vpos = 0; v->get_ctrl()->update_visible_feeds(); for (std::vector::iterator it=visible_feeds.begin();it!=visible_feeds.end();++it, ++vpos) { if (it->second == pos) { LOG(LOG_DEBUG, "feedlist_formaction::mark_pos_if_visible: match, setting position to %u", vpos); f->set("feedpos", utils::to_string(vpos)); return; } } vpos = 0; pos = v->get_ctrl()->get_pos_of_next_unread(pos); for (std::vector::iterator it=visible_feeds.begin();it!=visible_feeds.end();++it, ++vpos) { if (it->second == pos) { LOG(LOG_DEBUG, "feedlist_formaction::mark_pos_if_visible: match in 2nd try, setting position to %u", vpos); f->set("feedpos", utils::to_string(vpos)); return; } } } void feedlist_formaction::save_filterpos() { std::istringstream is(f->get("feedpos")); unsigned int i; is >> i; if (i& attrs = r->get_attrs("feedlist"); unsigned int i=0; std::string attrstr; for (std::vector::iterator it=attrs.begin();it!=attrs.end();++it,++i) { attrstr.append(utils::strprintf("@style_%u_normal:%s ", i, it->c_str())); attrstr.append(utils::strprintf("@style_%u_focus:%s ", i, it->c_str())); } std::string textview = utils::strprintf("{!list[feeds] .expand:vh style_normal[listnormal]: style_focus[listfocus]:fg=yellow,bg=blue,attr=bold pos_name[feedposname]: pos[feedpos]:0 %s richtext:1}", attrstr.c_str()); f->modify("feeds", "replace", textview); } void feedlist_formaction::op_end_setfilter() { std::string filtertext = qna_responses[0]; filterhistory.add_line(filtertext); if (filtertext.length() > 0) { if (!m.parse(filtertext)) { v->show_error(_("Error: couldn't parse filter command!")); m.parse(FILTER_UNREAD_FEEDS); } else { save_filterpos(); apply_filter = true; do_redraw = true; } } } void feedlist_formaction::op_start_search() { std::string searchphrase = qna_responses[0]; LOG(LOG_DEBUG, "feedlist_formaction::op_start_search: starting search for `%s'", searchphrase.c_str()); if (searchphrase.length() > 0) { v->set_status(_("Searching...")); searchhistory.add_line(searchphrase); std::vector > items; try { std::string utf8searchphrase = utils::convert_text(searchphrase, "utf-8", nl_langinfo(CODESET)); items = v->get_ctrl()->search_for_items(utf8searchphrase, ""); } catch (const dbexception& e) { v->show_error(utils::strprintf(_("Error while searching for `%s': %s"), searchphrase.c_str(), e.what())); return; } if (!items.empty()) { search_dummy_feed->item_mutex.lock(); search_dummy_feed->clear_items(); for (std::vector >::iterator it=items.begin();it!=items.end();++it) { search_dummy_feed->add_item(*it); } search_dummy_feed->item_mutex.unlock(); v->push_searchresult(search_dummy_feed, searchphrase); } else { v->show_error(_("No results.")); } } } void feedlist_formaction::handle_cmdline_num(unsigned int idx) { if (idx > 0 && idx <= (visible_feeds[visible_feeds.size()-1].second + 1)) { int i = get_pos(idx - 1); if (i == -1) { v->show_error(_("Position not visible!")); } else { f->set("feedpos", utils::to_string(i)); } } else { v->show_error(_("Invalid position!")); } } void feedlist_formaction::set_pos() { if (set_filterpos) { set_filterpos = false; unsigned int i = 0; for (std::vector::iterator it=visible_feeds.begin();it!=visible_feeds.end();++it, ++i) { if (it->second == filterpos) { f->set("feedpos", utils::to_string(i)); return; } } f->set("feedpos", "0"); } else if (zero_feedpos) { f->set("feedpos","0"); zero_feedpos = false; } } std::string feedlist_formaction::get_title(std::tr1::shared_ptr feed) { std::string title = feed->title(); if (title.length()==0) title = utils::censor_url(feed->rssurl()); if (title.length()==0) title = ""; return title; } std::string feedlist_formaction::format_line(const std::string& feedlist_format, std::tr1::shared_ptr feed, unsigned int pos, unsigned int width) { fmtstr_formatter fmt; unsigned int unread_count = feed->unread_item_count(); fmt.register_fmt('i', utils::strprintf("%u", pos + 1)); fmt.register_fmt('u', utils::strprintf("(%u/%u)",unread_count,static_cast(feed->items().size()))); fmt.register_fmt('U', utils::to_string(unread_count)); fmt.register_fmt('c', utils::to_string(feed->items().size())); fmt.register_fmt('n', unread_count > 0 ? "N" : " "); fmt.register_fmt('S', feed->get_status()); fmt.register_fmt('t', get_title(feed)); fmt.register_fmt('T', feed->get_firsttag()); fmt.register_fmt('l', utils::censor_url(feed->link())); fmt.register_fmt('L', utils::censor_url(feed->rssurl())); fmt.register_fmt('d', feed->description()); return fmt.do_format(feedlist_format, width); } std::string feedlist_formaction::title() { return utils::strprintf(_("Feed List - %u unread, %u total"), unread_feeds, total_feeds); } } newsbeuter-2.7/src/filebrowser_formaction.cpp000066400000000000000000000160051220711462700216100ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace newsbeuter { filebrowser_formaction::filebrowser_formaction(view * vv, std::string formstr) : formaction(vv,formstr), quit(false) { } filebrowser_formaction::~filebrowser_formaction() { } void filebrowser_formaction::process_operation(operation op, bool /* automatic */, std::vector * /* args */) { switch (op) { case OP_OPEN: { /* * whenever "ENTER" is hit, we need to distinguish two different cases: * - the focus is in the list of files, then we need to set the filename field to the currently selected entry * - the focus is in the filename field, then the filename needs to be returned. */ LOG(LOG_DEBUG,"filebrowser_formaction: 'opening' item"); std::string focus = f->get_focus(); if (focus.length() > 0) { if (focus == "files") { std::string selection = f->get("listposname"); char filetype = selection[0]; selection.erase(0,1); std::string filename(selection); switch (filetype) { case 'd': { std::string fileswidth = f->get("files:w"); std::istringstream is(fileswidth); unsigned int width; is >> width; fmtstr_formatter fmt; fmt.register_fmt('N', PROGRAM_NAME); fmt.register_fmt('V', PROGRAM_VERSION); fmt.register_fmt('f', filename); f->set("head", fmt.do_format(v->get_cfg()->get_configvalue("filebrowser-title-format"), width)); ::chdir(filename.c_str()); f->set("listpos","0"); char cwdtmp[MAXPATHLEN]; ::getcwd(cwdtmp,sizeof(cwdtmp)); std::string fn(cwdtmp); fn.append(NEWSBEUTER_PATH_SEP); std::string fnstr = f->get("filenametext"); const char * base = strrchr(fnstr.c_str(),'/'); if (!base) base = fnstr.c_str(); fn.append(base); f->set("filenametext",fn); do_redraw = true; } break; case '-': { char cwdtmp[MAXPATHLEN]; ::getcwd(cwdtmp,sizeof(cwdtmp)); std::string fn(cwdtmp); fn.append(NEWSBEUTER_PATH_SEP); fn.append(filename); f->set("filenametext",fn); f->set_focus("filename"); } break; default: // TODO: show error message break; } } else { bool do_pop = true; std::string fn = f->get("filenametext"); struct stat sbuf; /* * this check is very important, as people will kill us if they accidentaly overwrote their files * with no further warning... */ if (::stat(fn.c_str(), &sbuf)!=-1) { f->set_focus("files"); if (v->confirm(utils::strprintf(_("Do you really want to overwrite `%s' (y:Yes n:No)? "), fn.c_str()), _("yn")) == *_("n")) { do_pop = false; } f->set_focus("filenametext"); } if (do_pop) v->pop_current_formaction(); } } } break; case OP_QUIT: LOG(LOG_DEBUG,"view::filebrowser: quitting"); v->pop_current_formaction(); f->set("filenametext", ""); break; case OP_HARDQUIT: LOG(LOG_DEBUG,"view::filebrowser: hard quitting"); while (v->formaction_stack_size() >0) { v->pop_current_formaction(); } f->set("filenametext", ""); break; default: break; } } void filebrowser_formaction::prepare() { /* * prepare is always called before an operation is processed, * and if a redraw is necessary, it updates the list of files * in the current directory. */ if (do_redraw) { char cwdtmp[MAXPATHLEN]; std::string code = "{list"; ::getcwd(cwdtmp,sizeof(cwdtmp)); DIR * dirp = ::opendir(cwdtmp); if (dirp) { struct dirent * de = ::readdir(dirp); while (de) { if (strcmp(de->d_name,".")!=0) code.append(add_file(de->d_name)); de = ::readdir(dirp); } ::closedir(dirp); } code.append("}"); f->modify("files", "replace_inner", code); do_redraw = false; } } void filebrowser_formaction::init() { char cwdtmp[MAXPATHLEN]; ::getcwd(cwdtmp,sizeof(cwdtmp)); set_keymap_hints(); f->set("fileprompt", _("File: ")); if (dir == "") { std::string save_path = v->get_cfg()->get_configvalue("save-path"); LOG(LOG_DEBUG,"view::filebrowser: save-path is '%s'",save_path.c_str()); dir = save_path; } LOG(LOG_DEBUG, "view::filebrowser: chdir(%s)", dir.c_str()); ::chdir(dir.c_str()); ::getcwd(cwdtmp,sizeof(cwdtmp)); f->set("filenametext", default_filename); f->set("head", utils::strprintf(_("%s %s - Save File - %s"), PROGRAM_NAME, PROGRAM_VERSION, cwdtmp)); } keymap_hint_entry * filebrowser_formaction::get_keymap_hint() { static keymap_hint_entry hints[] = { { OP_QUIT, _("Cancel") }, { OP_OPEN, _("Save") }, { OP_NIL, NULL } }; return hints; } std::string filebrowser_formaction::add_file(std::string filename) { std::string retval; struct stat sb; if (::stat(filename.c_str(),&sb)==0) { char ftype = get_filetype(sb.st_mode); std::string rwxbits = get_rwx(sb.st_mode & 0777); std::string owner = get_owner(sb.st_uid); std::string group = get_group(sb.st_gid); std::string sizestr = utils::strprintf("%12u", sb.st_size); std::string line = utils::strprintf("%c%s %s %s %s %s", ftype, rwxbits.c_str(), owner.c_str(), group.c_str(), sizestr.c_str(), filename.c_str()); retval = utils::strprintf("{listitem[%c%s] text:%s}", ftype, stfl::quote(filename).c_str(), stfl::quote(line).c_str()); } return retval; } std::string filebrowser_formaction::get_rwx(unsigned short val) { std::string str; const char * bitstrs[] = { "---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx" }; for (int i=0;i<3;++i) { unsigned char bits = val % 8; val /= 8; str.insert(0, bitstrs[bits]); } return str; } char filebrowser_formaction::get_filetype(mode_t mode) { static struct flag_char { mode_t flag; char ftype; } flags[] = { { S_IFREG, '-' }, { S_IFDIR, 'd' }, { S_IFBLK, 'b' }, { S_IFCHR, 'c' }, { S_IFIFO, 'p' }, { S_IFLNK, 'l' }, { 0 , 0 } }; for (unsigned int i=0;flags[i].flag != 0;i++) { if (mode & flags[i].flag) return flags[i].ftype; } return '?'; } std::string filebrowser_formaction::get_owner(uid_t uid) { struct passwd * spw = getpwuid(uid); if (spw) { std::string owner = spw->pw_name; for (int i=owner.length();i<8;++i) { owner.append(" "); } return owner; } return "????????"; } std::string filebrowser_formaction::get_group(gid_t gid) { struct group * sgr = getgrgid(gid); if (sgr) { std::string group = sgr->gr_name; for (int i=group.length();i<8;++i) { group.append(" "); } return group; } return "????????"; } std::string filebrowser_formaction::title() { char cwdtmp[MAXPATHLEN]; ::getcwd(cwdtmp,sizeof(cwdtmp)); return utils::strprintf(_("Save File - %s"), cwdtmp); } } newsbeuter-2.7/src/filtercontainer.cpp000066400000000000000000000023471220711462700202400ustar00rootroot00000000000000#include #include #include #include #include namespace newsbeuter { filtercontainer::~filtercontainer() { } void filtercontainer::handle_action(const std::string& action, const std::vector& params) { /* * filtercontainer does nothing but to save (filter name, filter expression) tuples. * These tuples are used for enabling the user to predefine filter expressions and * then select them from a list by their name. */ if (action == "define-filter") { if (params.size() < 2) throw confighandlerexception(AHS_TOO_FEW_PARAMS); matcher m; if (!m.parse(params[1])) throw confighandlerexception(utils::strprintf(_("couldn't parse filter expression `%s': %s"), params[1].c_str(), m.get_parse_error().c_str())); filters.push_back(filter_name_expr_pair(params[0],params[1])); } else throw confighandlerexception(AHS_INVALID_COMMAND); } void filtercontainer::dump_config(std::vector& config_output) { for (std::vector::iterator it=filters.begin();it!=filters.end();++it) { config_output.push_back(utils::strprintf("define-filter %s %s", utils::quote(it->first).c_str(), utils::quote(it->second).c_str())); } } } newsbeuter-2.7/src/formaction.cpp000066400000000000000000000350051220711462700172060ustar00rootroot00000000000000#include #include #include #include #include #include #include #include namespace newsbeuter { history formaction::searchhistory; history formaction::cmdlinehistory; formaction::formaction(view * vv, std::string formstr) : v(vv), f(new stfl::form(formstr)), do_redraw(true) { if (v) { if (v->get_cfg()->get_configvalue_as_bool("show-keymap-hint") == false) { f->set("showhint", "0"); } if (v->get_cfg()->get_configvalue_as_bool("swap-title-and-hints") == true) { std::string hints = f->dump("hints", "", 0); std::string title = f->dump("title", "", 0); f->modify("title", "replace", "label[swap-title]"); f->modify("hints", "replace", "label[swap-hints]"); f->modify("swap-title", "replace", hints); f->modify("swap-hints", "replace", title); } } valid_cmds.push_back("set"); valid_cmds.push_back("quit"); valid_cmds.push_back("source"); valid_cmds.push_back("dumpconfig"); valid_cmds.push_back("dumpform"); } void formaction::set_keymap_hints() { f->set("help", prepare_keymap_hint(this->get_keymap_hint())); } void formaction::recalculate_form() { f->run(-3); } formaction::~formaction() { } std::tr1::shared_ptr formaction::get_form() { return f; } std::string formaction::prepare_keymap_hint(keymap_hint_entry * hints) { /* * This function generates the "keymap hint" line by putting * together the elements of a structure, and looking up the * currently set keybinding so that the "keymap hint" line always * reflects the current configuration. */ std::string keymap_hint; for (int i=0;hints[i].op != OP_NIL; ++i) { keymap_hint.append(v->get_keys()->getkey(hints[i].op, this->id())); keymap_hint.append(":"); keymap_hint.append(hints[i].text); keymap_hint.append(" "); } return keymap_hint; } std::string formaction::get_value(const std::string& value) { return f->get(value); } void formaction::start_cmdline() { std::vector qna; qna.push_back(qna_pair(":", "")); v->inside_cmdline(true); this->start_qna(qna, OP_INT_END_CMDLINE, &formaction::cmdlinehistory); } void formaction::process_op(operation op, bool automatic, std::vector * args) { switch (op) { case OP_REDRAW: LOG(LOG_DEBUG, "formaction::process_op: redrawing screen"); stfl::reset(); break; case OP_CMDLINE: start_cmdline(); break; case OP_INT_SET: if (automatic) { std::string cmdline = "set "; if (args) { for (std::vector::iterator it=args->begin();it!=args->end();++it) { cmdline.append(utils::strprintf("%s ", stfl::quote(*it).c_str())); } } LOG(LOG_DEBUG, "formaction::process_op: running commandline `%s'", cmdline.c_str()); this->handle_cmdline(cmdline); } else { LOG(LOG_WARN, "formaction::process_op: got OP_INT_SET, but not automatic"); } break; case OP_INT_CANCEL_QNA: f->modify("lastline","replace","{hbox[lastline] .expand:0 {label[msglabel] .expand:h text[msg]:\"\"}}"); v->inside_qna(false); v->inside_cmdline(false); break; case OP_INT_QNA_NEXTHIST: if (qna_history) { std::string entry = qna_history->next(); f->set("qna_value", entry); f->set("qna_value_pos", utils::to_string(entry.length())); } break; case OP_INT_QNA_PREVHIST: if (qna_history) { std::string entry = qna_history->prev(); f->set("qna_value", entry); f->set("qna_value_pos", utils::to_string(entry.length())); } break; case OP_INT_END_QUESTION: /* * An answer has been entered, we save the value, and ask the next question. */ qna_responses.push_back(f->get("qna_value")); start_next_question(); break; case OP_VIEWDIALOGS: v->view_dialogs(); break; case OP_NEXTDIALOG: v->goto_next_dialog(); break; case OP_PREVDIALOG: v->goto_prev_dialog(); break; default: this->process_operation(op, automatic, args); } } std::vector formaction::get_suggestions(const std::string& fragment) { LOG(LOG_DEBUG, "formaction::get_suggestions: fragment = %s", fragment.c_str()); std::vector result; // first check all formaction command suggestions for (std::vector::iterator it=valid_cmds.begin();it!=valid_cmds.end();++it) { LOG(LOG_DEBUG, "formaction::get_suggestions: extracted part: %s", it->substr(0, fragment.length()).c_str()); if (it->substr(0, fragment.length()) == fragment) { LOG(LOG_DEBUG, "...and it matches."); result.push_back(*it); } } if (result.empty()) { std::vector tokens = utils::tokenize_quoted(fragment, " \t="); if (tokens.size() >= 1) { if (tokens[0] == "set") { if (tokens.size() < 3) { std::vector variable_suggestions; std::string variable_fragment; if (tokens.size() > 1) variable_fragment = tokens[1]; variable_suggestions = v->get_cfg()->get_suggestions(variable_fragment); for (std::vector::iterator it=variable_suggestions.begin();it!=variable_suggestions.end();++it) { std::string line = fragment + it->substr(variable_fragment.length(), it->length()-variable_fragment.length()); result.push_back(line); LOG(LOG_DEBUG, "formaction::get_suggestions: suggested %s", line.c_str()); } } } } } LOG(LOG_DEBUG, "formaction::get_suggestions: %u suggestions", result.size()); return result; } void formaction::handle_cmdline(const std::string& cmdline) { /* * this is the command line handling that is available on all dialogs. * It is only called when the handle_cmdline() methods of the derived classes * are unable to handle to command line or when the derived class doesn't * implement the handle_cmdline() method by itself. * * It works the same way basically everywhere: first the command line * is tokenized, and then the tokens are looked at. */ std::vector tokens = utils::tokenize_quoted(cmdline, " \t="); configcontainer * cfg = v->get_cfg(); assert(cfg != NULL); if (!tokens.empty()) { std::string cmd = tokens[0]; tokens.erase(tokens.begin()); if (cmd == "set") { if (tokens.empty()) { v->show_error(_("usage: set [=]")); } else if (tokens.size()==1) { std::string var = tokens[0]; if (var.length() > 0) { if (var[var.length()-1] == '!') { var.erase(var.length()-1); cfg->toggle(var); set_redraw(true); } else if (var[var.length()-1] == '&') { var.erase(var.length()-1); cfg->reset_to_default(var); set_redraw(true); } v->set_status(utils::strprintf(" %s=%s", var.c_str(), utils::quote_if_necessary(cfg->get_configvalue(var)).c_str())); } } else if (tokens.size()==2) { std::string result = configparser::evaluate_backticks(tokens[1]); utils::trim_end(result); cfg->set_configvalue(tokens[0], result); set_redraw(true); // because some configuration value might have changed something UI-related } else { v->show_error(_("usage: set [=]")); } } else if (cmd == "quit") { while (v->formaction_stack_size() > 0) { v->pop_current_formaction(); } } else if (cmd == "source") { if (tokens.empty()) { v->show_error(_("usage: source [...]")); } else { for (std::vector::iterator it=tokens.begin();it!=tokens.end();++it) { try { v->get_ctrl()->load_configfile(utils::resolve_tilde(*it)); } catch (const configexception& ex) { v->show_error(ex.what()); break; } } } } else if (cmd == "dumpconfig") { if (tokens.size()!=1) { v->show_error(_("usage: dumpconfig ")); } else { v->get_ctrl()->dump_config(utils::resolve_tilde(tokens[1])); v->show_error(utils::strprintf(_("Saved configuration to %s"), tokens[1].c_str())); } } else if (cmd == "dumpform") { v->dump_current_form(); } else { v->show_error(utils::strprintf(_("Not a command: %s"), cmdline.c_str())); } } } void formaction::start_qna(const std::vector& prompts, operation finish_op, history * h) { /* * the formaction base class contains a "Q&A" mechanism that makes it possible for all formaction-derived classes to * query the user for 1 or more values, optionally with a history. * * Every question is a prompt (such as "Search for: "), with an default value. These need to be provided as a vector * of (string, string) tuples. What also needs to be provided is the operation that will to be signaled to the * finished_qna() method when reading all answers is finished, and optionally, a pointer to a history object to support * browsing of the input history. When reading is done, the responses can be found in the qna_responses vector. In this * vector, the first fields corresponds with the first prompt, the second field with the second prompt, etc. */ qna_prompts = prompts; qna_responses.clear(); finish_operation = finish_op; qna_history = h; v->inside_qna(true); start_next_question(); } void formaction::finished_qna(operation op) { v->inside_qna(false); v->inside_cmdline(false); switch (op) { /* * since bookmarking is available in several formactions, I decided to put this into * the base class so that all derived classes can take advantage of it. We also see * here how the signaling of a finished "Q&A" is handled: * - check for the right operation * - take the responses * - run operation (in this case, save the bookmark) * - signal success (or failure) to the user */ case OP_INT_BM_END: { assert(qna_responses.size() == 3 && qna_prompts.size() == 0); // everything must be answered v->set_status(_("Saving bookmark...")); std::string retval = v->get_ctrl()->bookmark(qna_responses[0], qna_responses[1], qna_responses[2]); if (retval.length() == 0) { v->set_status(_("Saved bookmark.")); } else { v->set_status(std::string(_("Error while saving bookmark: ")) + retval); LOG(LOG_DEBUG, "formaction::finished_qna: error while saving bookmark, retval = `%s'", retval.c_str()); } } break; case OP_INT_END_CMDLINE: { f->set_focus("feeds"); std::string cmdline = qna_responses[0]; formaction::cmdlinehistory.add_line(cmdline); LOG(LOG_DEBUG,"formaction: commandline = `%s'", cmdline.c_str()); this->handle_cmdline(cmdline); } break; default: break; } } void formaction::start_bookmark_qna(const std::string& default_title, const std::string& default_url, const std::string& default_desc) { LOG(LOG_DEBUG, "formaction::start_bookmark_qna: starting bookmark Q&A... default_title = %s default_url = %s default_desc = %s", default_title.c_str(), default_url.c_str(), default_desc.c_str()); std::vector prompts; std::string new_title = ""; bool is_bm_autopilot = v->get_cfg()->get_configvalue_as_bool("bookmark-autopilot"); prompts.push_back(qna_pair(_("URL: "), default_url)); if(default_title.empty()) { // call the function to figure out title from url only if the default_title is no good new_title = make_title(default_url); prompts.push_back(qna_pair(_("Title: "), new_title)); } else { prompts.push_back(qna_pair(_("Title: "), default_title)); } prompts.push_back(qna_pair(_("Description: "), default_desc)); if (is_bm_autopilot) { //If bookmarking is set to autopilot don't prompt for url, title, desc if (default_title.empty()) new_title = make_title(default_url); // try to make the title from url else new_title = default_title; // assignment just to make the call to bookmark() below easier if (default_url.empty() || new_title.empty()) { //if url or title is missing, abort autopilot and ask user start_qna(prompts, OP_INT_BM_END); } else { v->set_status(_("Saving bookmark on autopilot...")); std::string retval = v->get_ctrl()->bookmark(default_url, new_title, default_desc); if (retval.length() == 0) { v->set_status(_("Saved bookmark.")); } else { v->set_status(std::string(_("Error while saving bookmark: ")) + retval); LOG(LOG_DEBUG, "formaction::finished_qna: error while saving bookmark, retval = `%s'", retval.c_str()); } } } else { start_qna(prompts, OP_INT_BM_END); } } std::string formaction::make_title(const std::string& const_url) { /* Sometimes it is possible to construct the title from the URL * This attempts to do just that. eg: http://domain.com/story/yy/mm/dd/title-with-dashes?a=b */ std::string url = (std::string&) const_url; std::string::size_type pos_of_slash = url.find_last_of('/', (int)url.length()-2); // get to the final part of the URI's path, catering for situation where last char is '/' if (url[url.length()-1] == '/') url.erase((int)url.length()-1); std::string path=url.substr(pos_of_slash+1); // extract just the juicy part 'title-with-dashes?a=b' std::string::size_type pos_of_qmrk = path.find_first_of('?'); // find where query part of URI starts std::string title = path.substr(0,pos_of_qmrk); //throw away the query part 'title-with-dashes' std::replace(title.begin(), title.end(), '-', ' '); // 'title with dashes' if (title.at(0)>= 'a' && title.at(0)<= 'z') title[0] -= 'a' - 'A'; //'Title with dashes' return title; } void formaction::start_next_question() { /* * If there is one more prompt to be presented to the user, set it up. */ if (qna_prompts.size() > 0) { std::string replacestr("{hbox[lastline] .expand:0 {label .expand:0 text:"); replacestr.append(stfl::quote(qna_prompts[0].first)); replacestr.append("}{input[qnainput] on_ESC:cancel-qna on_UP:qna-prev-history on_DOWN:qna-next-history on_ENTER:end-question modal:1 .expand:h @bind_home:** @bind_end:** text[qna_value]:"); replacestr.append(stfl::quote(qna_prompts[0].second)); replacestr.append(" pos[qna_value_pos]:"); replacestr.append(utils::to_string(qna_prompts[0].second.length())); replacestr.append("}}"); qna_prompts.erase(qna_prompts.begin()); f->modify("lastline", "replace", replacestr); f->set_focus("qnainput"); } else { /* * If there are no more prompts, restore the last line with the usual label, and signal the end of the "Q&A" to the finished_qna() method. */ f->modify("lastline","replace","{hbox[lastline] .expand:0 {label[msglabel] .expand:h text[msg]:\"\"}}"); this->finished_qna(finish_operation); } } void formaction::load_histories(const std::string& searchfile, const std::string& cmdlinefile) { searchhistory.load_from_file(searchfile); cmdlinehistory.load_from_file(cmdlinefile); } void formaction::save_histories(const std::string& searchfile, const std::string& cmdlinefile, unsigned int limit) { searchhistory.save_to_file(searchfile, limit); cmdlinehistory.save_to_file(cmdlinefile, limit); } } newsbeuter-2.7/src/formatstring.cpp000066400000000000000000000056151220711462700175700ustar00rootroot00000000000000#include #include #include #include #include #include namespace newsbeuter { void fmtstr_formatter::register_fmt(char f, const std::string& value) { fmts[f] = utils::str2wstr(value); } std::string fmtstr_formatter::do_format(const std::string& fmt, unsigned int width) { std::string result; if (fmt.length() > 0) { std::wstring wfmt(utils::str2wstr(fmt)); std::wstring w = do_wformat(wfmt, width); result = utils::wstr2str(w); } return result; } std::wstring fmtstr_formatter::do_wformat(const std::wstring& wfmt, unsigned int width) { std::wstring result; unsigned int i; unsigned int fmtlen = wfmt.length(); for (i=0;i> align; if (static_cast(abs(align)) > fmts[c].length()) { wchar_t buf[256]; swprintf(buf,sizeof(buf)/sizeof(*buf),L"%*ls", align, fmts[c].c_str()); result.append(buf); } else { result.append(fmts[c].substr(0,abs(align))); } } } else if (wfmt[i+1] == L'%') { result.append(1, L'%'); ++i; } else if (wfmt[i+1] == L'>') { if (wfmt[i+2]) { if (width == 0) { result.append(1, wfmt[i+2]); i += 2; } else { std::wstring rightside = do_wformat(&wfmt[i+3], 0); int diff = width - wcswidth(result.c_str(),result.length()) - wcswidth(rightside.c_str(), rightside.length()); if (diff > 0) { result.append(diff, wfmt[i+2]); } result.append(rightside); i = fmtlen; } } } else if (wfmt[i+1] == L'?') { unsigned int j = i+2; while (wfmt[j] && wfmt[j] != L'?') j++; if (wfmt[j]) { std::wstring cond = wfmt.substr(i+2, j - i - 2); unsigned int k = j + 1; while (wfmt[k] && wfmt[k] != L'?') k++; if (wfmt[k]) { std::wstring values = wfmt.substr(j+1, k - j - 1); std::vector pair = utils::wtokenize(values,L"&"); while (pair.size() < 2) pair.push_back(L""); std::wstring subresult; if (fmts[cond[0]].length() > 0) { if (pair[0].length() > 0) subresult = do_wformat(pair[0], width); } else { if (pair[1].length() > 0) subresult = do_wformat(pair[1], width); } result.append(subresult); i = k; } else { i = k - 1; } } else { i = j - 1; } } else { result.append(fmts[wfmt[i+1]]); ++i; } } } else { result.append(1, wfmt[i]); } } return result; } } newsbeuter-2.7/src/google_api.cpp000066400000000000000000000300651220711462700171530ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #define GREADER_LOGIN "https://www.google.com/accounts/ClientLogin" #define GREADER_API_PREFIX "http://www.google.com/reader/api/0/" #define GREADER_FEED_PREFIX "http://www.google.com/reader/atom/" #define GREADER_SUBSCRIPTION_LIST GREADER_API_PREFIX "subscription/list" #define GREADER_API_MARK_ALL_READ_URL GREADER_API_PREFIX "mark-all-as-read" #define GREADER_API_EDIT_TAG_URL GREADER_API_PREFIX "edit-tag" #define GREADER_API_TOKEN_URL GREADER_API_PREFIX "token" // for reference, see http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI namespace newsbeuter { googlereader_api::googlereader_api(configcontainer * c) : remote_api(c) { // TODO } googlereader_api::~googlereader_api() { // TODO } bool googlereader_api::authenticate() { auth = retrieve_auth(); LOG(LOG_DEBUG, "googlereader_api::authenticate: Auth = %s", auth.c_str()); return auth != ""; } static size_t my_write_data(void *buffer, size_t size, size_t nmemb, void *userp) { std::string * pbuf = static_cast(userp); pbuf->append(static_cast(buffer), size * nmemb); return size * nmemb; } std::string googlereader_api::retrieve_auth() { CURL * handle = curl_easy_init(); std::string user = cfg->get_configvalue("googlereader-login"); bool flushed = false; if (user == "") { std::cout << std::endl; std::cout.flush(); flushed = true; std::cout << "Username for Google Reader: "; std::cin >> user; if (user == "") { return ""; } } std::string pass = cfg->get_configvalue("googlereader-password"); if( pass == "" ) { wordexp_t exp; std::ifstream ifs; wordexp(cfg->get_configvalue("googlereader-passwordfile").c_str(),&exp,0); ifs.open(exp.we_wordv[0]); wordfree(&exp); if (!ifs) { if(!flushed) { std::cout << std::endl; std::cout.flush(); } // Find a way to do this in C++ by removing cin echoing. pass = std::string( getpass("Password for Google Reader: ") ); } else { ifs >> pass; if(pass == "") { return ""; } } } char * username = curl_easy_escape(handle, user.c_str(), 0); char * password = curl_easy_escape(handle, pass.c_str(), 0); std::string postcontent = utils::strprintf("service=reader&Email=%s&Passwd=%s&source=%s%2F%s&accountType=HOSTED_OR_GOOGLE&continue=http://www.google.com/", username, password, PROGRAM_NAME, PROGRAM_VERSION); curl_free(username); curl_free(password); std::string result; utils::set_common_curl_options(handle, cfg); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, my_write_data); curl_easy_setopt(handle, CURLOPT_WRITEDATA, &result); curl_easy_setopt(handle, CURLOPT_POSTFIELDS, postcontent.c_str()); curl_easy_setopt(handle, CURLOPT_URL, GREADER_LOGIN); curl_easy_perform(handle); curl_easy_cleanup(handle); std::vector lines = utils::tokenize(result); for (std::vector::iterator it=lines.begin();it!=lines.end();++it) { LOG(LOG_DEBUG, "googlereader_api::retrieve_auth: line = %s", it->c_str()); if (it->substr(0,5)=="Auth=") { std::string auth = it->substr(5, it->length()-5); return auth; } } return ""; } std::vector googlereader_api::get_subscribed_urls() { std::vector urls; CURL * handle = curl_easy_init(); std::string result; configure_handle(handle); utils::set_common_curl_options(handle, cfg); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, my_write_data); curl_easy_setopt(handle, CURLOPT_WRITEDATA, &result); curl_easy_setopt(handle, CURLOPT_URL, GREADER_SUBSCRIPTION_LIST); curl_easy_perform(handle); curl_easy_cleanup(handle); LOG(LOG_DEBUG, "googlereader_api::get_subscribed_urls: document = %s", result.c_str()); xmlDoc * doc = xmlParseMemory(result.c_str(), result.length()); if (!doc) { LOG(LOG_ERROR, "googlreader_api::get_subscribed_urls: failed to parse subscription list"); return urls; } xmlNode * root = xmlDocGetRootElement(doc); LOG(LOG_DEBUG, "googlereader_api::get_subscribed_urls: root = %p", root); if (root) { for (xmlNode * node = root->children; node != NULL; node = node->next) { if (strcmp((const char *)node->name, "list")==0 && utils::get_prop(node, "name") == "subscriptions") { LOG(LOG_DEBUG, "found subscriptions list"); for (xmlNode * objectnode = node->children; objectnode != NULL; objectnode = objectnode->next) { if (strcmp((const char *)objectnode->name, "object")==0) { LOG(LOG_DEBUG, "found object"); std::string id; std::string title; std::vector tags; for (xmlNode * elem = objectnode->children; elem != NULL; elem = elem->next) { if (strcmp((const char *)elem->name, "string")==0 && utils::get_prop(elem,"name")=="id") { LOG(LOG_DEBUG, "found id"); id = utils::get_content(elem); } else if (strcmp((const char *)elem->name, "string")==0 && utils::get_prop(elem,"name")=="title") { title = utils::get_content(elem); } else if (strcmp((const char *)elem->name, "list")==0 && utils::get_prop(elem,"name")=="categories") { LOG(LOG_DEBUG, "found tag"); tags = get_tags(elem); } } if (id != "") { if (title != "") { tags.push_back(utils::strprintf("~%s", title.c_str())); } urls.push_back(tagged_feedurl(utils::strprintf("%s%s?n=%u", GREADER_FEED_PREFIX, utils::escape_url(id).c_str(), cfg->get_configvalue_as_int("googlereader-min-items")), tags)); } } } } } } xmlFreeDoc(doc); return urls; } std::vector googlereader_api::get_tags(xmlNode * node) { std::vector tags; if (node && strcmp((const char *)node->name, "list")==0 && utils::get_prop(node, "name")=="categories") { LOG(LOG_DEBUG, "found tag list"); for (xmlNode * objnode = node->children; objnode != NULL; objnode = objnode->next) { if (strcmp((const char *)objnode->name, "object")==0) { LOG(LOG_DEBUG, "found tag list object"); for (xmlNode * str = objnode->children; str != NULL; str = str->next) { if (strcmp((const char *)str->name, "string")==0 && utils::get_prop(str, "name")=="label") { LOG(LOG_DEBUG, "found tag list label"); tags.push_back(utils::get_content(str)); } } } } } return tags; } void googlereader_api::configure_handle(CURL * handle) { struct curl_slist *chunk = NULL; std::string header = utils::strprintf("Authorization: GoogleLogin auth=%s", auth.c_str()); LOG(LOG_DEBUG, "googlereader_api::configure_handle header = %s", header.c_str()); chunk = curl_slist_append(chunk, header.c_str()); curl_easy_setopt(handle, CURLOPT_HTTPHEADER, chunk); } bool googlereader_api::mark_all_read(const std::string& feedurl) { std::string real_feedurl = feedurl.substr(strlen(GREADER_FEED_PREFIX), feedurl.length() - strlen(GREADER_FEED_PREFIX)); std::vector elems = utils::tokenize(real_feedurl, "?"); real_feedurl = utils::unescape_url(elems[0]); std::string token = get_new_token(); std::string postcontent = utils::strprintf("s=%s&T=%s", real_feedurl.c_str(), token.c_str()); std::string result = post_content(GREADER_API_MARK_ALL_READ_URL, postcontent); return result == "OK"; } std::vector googlereader_api::bulk_mark_articles_read(const std::vector& actions) { std::vector successful_tokens; std::string token = get_new_token(); for (std::vector::const_iterator it=actions.begin();it!=actions.end();++it) { bool read; if (it->second == GOOGLE_MARK_READ) { read = true; } else if (it->second == GOOGLE_MARK_UNREAD) { read = false; } else { continue; } if (mark_article_read_with_token(it->first, read, token)) { successful_tokens.push_back(it->first); } } return successful_tokens; } bool googlereader_api::mark_article_read(const std::string& guid, bool read) { std::string token = get_new_token(); return mark_article_read_with_token(guid, read, token); } bool googlereader_api::mark_article_read_with_token(const std::string& guid, bool read, const std::string& token) { std::string postcontent; if (read) { postcontent = utils::strprintf("i=%s&a=user/-/state/com.google/read&r=user/-/state/com.google/kept-unread&ac=edit&T=%s", guid.c_str(), token.c_str()); } else { postcontent = utils::strprintf("i=%s&r=user/-/state/com.google/read&a=user/-/state/com.google/kept-unread&a=user/-/state/com.google/tracking-kept-unread&ac=edit&T=%s", guid.c_str(), token.c_str()); } std::string result = post_content(GREADER_API_EDIT_TAG_URL, postcontent); LOG(LOG_DEBUG, "googlereader_api::mark_article_read_with_token: postcontent = %s result = %s", postcontent.c_str(), result.c_str()); return result == "OK"; } std::string googlereader_api::get_new_token() { CURL * handle = curl_easy_init(); std::string result; utils::set_common_curl_options(handle, cfg); configure_handle(handle); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, my_write_data); curl_easy_setopt(handle, CURLOPT_WRITEDATA, &result); curl_easy_setopt(handle, CURLOPT_URL, GREADER_API_TOKEN_URL); curl_easy_perform(handle); curl_easy_cleanup(handle); LOG(LOG_DEBUG, "googlereader_api::get_new_token: token = %s", result.c_str()); return result; } bool googlereader_api::update_article_flags(const std::string& oldflags, const std::string& newflags, const std::string& guid) { std::string star_flag = cfg->get_configvalue("googlereader-flag-star"); std::string share_flag = cfg->get_configvalue("googlereader-flag-share"); bool success = true; if (star_flag.length() > 0) { if (strchr(oldflags.c_str(), star_flag[0])==NULL && strchr(newflags.c_str(), star_flag[0])!=NULL) { success = star_article(guid, true); } else if (strchr(oldflags.c_str(), star_flag[0])!=NULL && strchr(newflags.c_str(), star_flag[0])==NULL) { success = star_article(guid, false); } } if (share_flag.length() > 0) { if (strchr(oldflags.c_str(), share_flag[0])==NULL && strchr(newflags.c_str(), share_flag[0])!=NULL) { success = share_article(guid, true); } else if (strchr(oldflags.c_str(), share_flag[0])!=NULL && strchr(newflags.c_str(), share_flag[0])==NULL) { success = share_article(guid, false); } } return success; } bool googlereader_api::star_article(const std::string& guid, bool star) { std::string token = get_new_token(); std::string postcontent; if (star) { postcontent = utils::strprintf("i=%s&a=user/-/state/com.google/starred&ac=edit&T=%s", guid.c_str(), token.c_str()); } else { postcontent = utils::strprintf("i=%s&r=user/-/state/com.google/starred&ac=edit&T=%s", guid.c_str(), token.c_str()); } std::string result = post_content(GREADER_API_EDIT_TAG_URL, postcontent); return result == "OK"; } bool googlereader_api::share_article(const std::string& guid, bool share) { std::string token = get_new_token(); std::string postcontent; if (share) { postcontent = utils::strprintf("i=%s&a=user/-/state/com.google/broadcast&ac=edit&T=%s", guid.c_str(), token.c_str()); } else { postcontent = utils::strprintf("i=%s&r=user/-/state/com.google/broadcast&ac=edit&T=%s", guid.c_str(), token.c_str()); } std::string result = post_content(GREADER_API_EDIT_TAG_URL, postcontent); return result == "OK"; } std::string googlereader_api::post_content(const std::string& url, const std::string& postdata) { std::string result; CURL * handle = curl_easy_init(); utils::set_common_curl_options(handle, cfg); configure_handle(handle); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, my_write_data); curl_easy_setopt(handle, CURLOPT_WRITEDATA, &result); curl_easy_setopt(handle, CURLOPT_POSTFIELDS, postdata.c_str()); curl_easy_setopt(handle, CURLOPT_URL, url.c_str()); curl_easy_perform(handle); curl_easy_cleanup(handle); LOG(LOG_DEBUG, "googlereader_api::post_content: url = %s postdata = %s result = %s", url.c_str(), postdata.c_str(), result.c_str()); return result; } } newsbeuter-2.7/src/googlereader_urlreader.cpp000066400000000000000000000045411220711462700215520ustar00rootroot00000000000000#include #include namespace newsbeuter { googlereader_urlreader::googlereader_urlreader(configcontainer * c, const std::string& url_file, remote_api * a) : cfg(c), file(url_file), api(a) { } googlereader_urlreader::~googlereader_urlreader() { } void googlereader_urlreader::write_config() { // NOTHING } #define BROADCAST_FRIENDS_URL "http://www.google.com/reader/atom/user/-/state/com.google/broadcast-friends" #define STARRED_ITEMS_URL "http://www.google.com/reader/atom/user/-/state/com.google/starred" #define SHARED_ITEMS_URL "http://www.google.com/reader/atom/user/-/state/com.google/broadcast" #define POPULAR_ITEMS_URL "http://www.google.com/reader/public/atom/pop%2Ftopic%2Ftop%2Flanguage%2Fen" #define ADD_URL(url,caption) do { \ tmptags.clear(); \ urls.push_back((url)); \ tmptags.push_back((caption)); \ tags[(url)] = tmptags; } while(0) void googlereader_urlreader::reload() { urls.clear(); tags.clear(); alltags.clear(); if (cfg->get_configvalue_as_bool("googlereader-show-special-feeds")) { std::vector tmptags; ADD_URL(BROADCAST_FRIENDS_URL, std::string("~") + _("People you follow")); ADD_URL(STARRED_ITEMS_URL, std::string("~") + _("Starred items")); ADD_URL(SHARED_ITEMS_URL, std::string("~") + _("Shared items")); ADD_URL(POPULAR_ITEMS_URL, std::string("~") + _("Popular items")); } file_urlreader ur(file); ur.reload(); std::vector& file_urls(ur.get_urls()); for(std::vector::iterator it=file_urls.begin();it!=file_urls.end();++it) { if (it->substr(0,6) == "query:") { urls.push_back(*it); std::vector& file_tags(ur.get_tags(*it)); tags[*it] = ur.get_tags(*it); for (std::vector::iterator jt=file_tags.begin();jt!=file_tags.end();++jt) { alltags.insert(*jt); } } } std::vector feedurls = api->get_subscribed_urls(); for (std::vector::iterator it=feedurls.begin();it!=feedurls.end();++it) { LOG(LOG_DEBUG, "added %s to URL list", it->first.c_str()); urls.push_back(it->first); tags[it->first] = it->second; for (std::vector::iterator jt=it->second.begin();jt!=it->second.end();++jt) { LOG(LOG_DEBUG, "%s: added tag %s", it->first.c_str(), jt->c_str()); alltags.insert(*jt); } } } std::string googlereader_urlreader::get_source() { return "Google Reader"; } } newsbeuter-2.7/src/help_formaction.cpp000066400000000000000000000130601220711462700202130ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include namespace newsbeuter { help_formaction::help_formaction(view * vv, std::string formstr) : formaction(vv, formstr), quit(false), apply_search(false) { } help_formaction::~help_formaction() { } void help_formaction::process_operation(operation op, bool /* automatic */, std::vector * /* args */) { bool hardquit = false; switch (op) { case OP_QUIT: quit = true; break; case OP_HARDQUIT: hardquit = true; break; case OP_SEARCH: { std::vector qna; qna.push_back(qna_pair(_("Search for: "), "")); this->start_qna(qna, OP_INT_START_SEARCH, &searchhistory); } break; case OP_CLEARFILTER: apply_search = false; do_redraw = true; break; default: break; } if (hardquit) { while (v->formaction_stack_size() > 0) { v->pop_current_formaction(); } } else if (quit) { v->pop_current_formaction(); } } void help_formaction::prepare() { if (do_redraw) { std::string listwidth = f->get("helptext:w"); std::istringstream is(listwidth); unsigned int width; is >> width; fmtstr_formatter fmt; fmt.register_fmt('N', PROGRAM_NAME); fmt.register_fmt('V', PROGRAM_VERSION); f->set("head",fmt.do_format(v->get_cfg()->get_configvalue("help-title-format"), width)); std::vector descs; v->get_keys()->get_keymap_descriptions(descs, v->get_keys()->get_flag_from_context(context)); std::string highlighted_searchphrase = utils::strprintf("%s", searchphrase.c_str()); std::vector colors = utils::tokenize(v->get_cfg()->get_configvalue("search-highlight-colors"), " "); f->set("highlight", make_colorstring(colors)); listformatter listfmt; unsigned int unbound_count = 0; unsigned int syskey_count = 0; for (unsigned int i=0;i<3;i++) { for (std::vector::iterator it=descs.begin();it!=descs.end();++it) { bool condition; switch (i) { case 0: condition = (it->key.length() == 0 || it->flags & KM_SYSKEYS); if (it->key.length() == 0) unbound_count++; if (it->flags & KM_SYSKEYS) syskey_count++; break; case 1: condition = !(it->flags & KM_SYSKEYS); break; case 2: condition = (it->key.length() > 0 || it->flags & KM_SYSKEYS); break; default: condition = true; break; } if (context.length() > 0 && (it->ctx != context || condition)) continue; if (!apply_search || strcasestr(it->key.c_str(), searchphrase.c_str())!=NULL || strcasestr(it->cmd.c_str(), searchphrase.c_str())!=NULL || strcasestr(it->desc.c_str(), searchphrase.c_str())!=NULL) { char tabs_1[] = " "; char tabs_2[] = " "; int how_often_1 = strlen(tabs_1) - it->key.length(); int how_often_2 = strlen(tabs_2) - it->cmd.length(); if (how_often_1 <= 0) how_often_1 = 1; if (how_often_2 <= 0) how_often_2 = 1; tabs_1[how_often_1] = '\0'; tabs_2[how_often_2] = '\0'; std::string line; switch (i) { case 0: case 1: line = utils::strprintf("%s%s%s%s%s", it->key.c_str(), tabs_1, it->cmd.c_str(), tabs_2, it->desc.c_str()); break; case 2: line = utils::strprintf("%s%s%s%s", it->cmd.c_str(), tabs_1, tabs_2, it->desc.c_str()); break; } LOG(LOG_DEBUG, "help_formaction::prepare: step 1 - line = %s", line.c_str()); line = utils::quote_for_stfl(line); LOG(LOG_DEBUG, "help_formaction::prepare: step 2 - line = %s", line.c_str()); if (apply_search && searchphrase.length() > 0) { line = utils::replace_all(line, searchphrase, highlighted_searchphrase); LOG(LOG_DEBUG, "help_formaction::prepare: step 3 - line = %s", line.c_str()); } listfmt.add_line(line); } } switch (i) { case 0: if (syskey_count > 0) { listfmt.add_line(""); listfmt.add_line(_("Generic bindings:")); listfmt.add_line(""); } break; case 1: if (unbound_count > 0) { listfmt.add_line(""); listfmt.add_line(_("Unbound functions:")); listfmt.add_line(""); } break; } } f->modify("helptext","replace_inner", listfmt.format_list()); do_redraw = false; } quit = false; } void help_formaction::init() { set_keymap_hints(); } keymap_hint_entry * help_formaction::get_keymap_hint() { static keymap_hint_entry hints[] = { { OP_QUIT, _("Quit") }, { OP_SEARCH, _("Search") }, { OP_CLEARFILTER, _("Clear") }, { OP_NIL, NULL } }; return hints; } void help_formaction::finished_qna(operation op) { switch (op) { case OP_INT_START_SEARCH: searchphrase = qna_responses[0]; apply_search = true; do_redraw = true; break; default: break; } } void help_formaction::set_context(const std::string& ctx) { if (context != ctx) { do_redraw = true; context = ctx; } } std::string help_formaction::title() { return _("Help"); } std::string help_formaction::make_colorstring(const std::vector& colors) { std::string result; if (colors.size() > 0) { if (colors[0] != "default") { result.append("fg="); result.append(colors[0]); } if (colors.size() > 1) { if (colors[1] != "default") { if (result.length() > 0) result.append(","); result.append("bg="); result.append(colors[1]); } } for (unsigned int i=2;i 0) result.append(","); result.append("attr="); result.append(colors[i]); } } return result; } } newsbeuter-2.7/src/history.cpp000066400000000000000000000024041220711462700165430ustar00rootroot00000000000000#include #include namespace newsbeuter { history::history() : idx(0) { } history::~history() { } void history::add_line(const std::string& line) { /* * When a line is added, we need to do so and * reset the index so that the next prev/next * operations start from the beginning again. */ if (line.length() > 0) { lines.insert(lines.begin(), line); } idx = 0; } std::string history::prev() { if (idx < lines.size()) { return lines[idx++]; } if (lines.size() == 0) { return ""; } return lines[idx-1]; } std::string history::next() { if (idx > 0) { return lines[--idx]; } return ""; } void history::load_from_file(const std::string& file) { std::fstream f; f.open(file.c_str(), std::fstream::in); if (f.is_open()) { std::string line; do { getline(f, line); if (!f.eof() && line.length() > 0) { add_line(line); } } while (!f.eof()); } } void history::save_to_file(const std::string& file, unsigned int limit) { std::fstream f; f.open(file.c_str(), std::fstream::out | std::fstream::trunc); if (f.is_open()) { if (limit > lines.size()) limit = lines.size(); if (limit > 0) { for (unsigned int i=limit-1;i>0;i--) { f << lines[i] << std::endl; } f << lines[0] << std::endl; } } } } newsbeuter-2.7/src/htmlrenderer.cpp000066400000000000000000000567661220711462700175610ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include namespace newsbeuter { htmlrenderer::htmlrenderer(unsigned int width, bool raw) : w(width), raw_(raw) { tags["a"] = TAG_A; tags["embed"] = TAG_EMBED; tags["br"] = TAG_BR; tags["pre"] = TAG_PRE; tags["ituneshack"] = TAG_ITUNESHACK; tags["img"] = TAG_IMG; tags["blockquote"] = TAG_BLOCKQUOTE; tags["aside"] = TAG_BLOCKQUOTE; tags["p"] = TAG_P; tags["h1"] = TAG_H1; tags["h2"] = TAG_H2; tags["h3"] = TAG_H3; tags["h4"] = TAG_H4; tags["ol"] = TAG_OL; tags["ul"] = TAG_UL; tags["li"] = TAG_LI; tags["dt"] = TAG_DT; tags["dd"] = TAG_DD; tags["dl"] = TAG_DL; tags["sup"] = TAG_SUP; tags["sub"] = TAG_SUB; tags["hr"] = TAG_HR; tags["b"] = TAG_STRONG; tags["strong"] = TAG_STRONG; tags["u"] = TAG_UNDERLINE; tags["q"] = TAG_QUOTATION; tags["script"] = TAG_SCRIPT; tags["style"] = TAG_STYLE; tags["table"] = TAG_TABLE; tags["th"] = TAG_TH; tags["tr"] = TAG_TR; tags["td"] = TAG_TD; } void htmlrenderer::render(const std::string& source, std::vector& lines, std::vector& links, const std::string& url) { std::istringstream input(source); render(input, lines, links, url); } unsigned int htmlrenderer::add_link(std::vector& links, const std::string& link, link_type type) { bool found = false; unsigned int i=1; for (std::vector::iterator it=links.begin();it!=links.end();++it, ++i) { if (it->first == link) { found = true; break; } } if (!found) links.push_back(linkpair(link,type)); return i; } void htmlrenderer::render(std::istream& input, std::vector& lines, std::vector& links, const std::string& url) { unsigned int image_count = 0; std::string curline; int indent_level = 0; bool inside_li = false, is_ol = false, inside_pre = false; bool itunes_hack = false; size_t inside_script = 0; size_t inside_style = 0; std::vector ol_counts; std::vector ol_types; htmltag current_tag; int link_num = -1; std::vector
    tables; /* * to render the HTML, we use a self-developed "XML" pull parser. * * A pull parser works like this: * - we feed it with an XML stream * - we then gather an iterator * - we then can iterate over all continuous elements, such as start tag, close tag, text element, ... */ tagsouppullparser xpp; xpp.setInput(input); for (tagsouppullparser::event e = xpp.next(); e != tagsouppullparser::END_DOCUMENT; e = xpp.next()) { std::string tagname; switch (e) { case tagsouppullparser::START_TAG: tagname = xpp.getText(); std::transform(tagname.begin(), tagname.end(), tagname.begin(), ::tolower); current_tag = tags[tagname]; switch (current_tag) { case TAG_A: { std::string link; try { link = xpp.getAttributeValue("href"); } catch (const std::invalid_argument& ) { LOG(LOG_WARN,"htmlrenderer::render: found a tag with no href attribute"); link = ""; } if (link.length() > 0) { link_num = add_link(links,utils::censor_url(utils::absolute_url(url,link)), LINK_HREF); if (!raw_) curline.append(""); } } break; case TAG_STRONG: if (!raw_) curline.append(""); break; case TAG_UNDERLINE: if (!raw_) curline.append(""); break; case TAG_QUOTATION: if (!raw_) curline.append("\""); break; case TAG_EMBED: { std::string type; try { type = xpp.getAttributeValue("type"); } catch (const std::invalid_argument& ) { LOG(LOG_WARN, "htmlrenderer::render: found embed object without type attribute"); type = ""; } if (type == "application/x-shockwave-flash") { std::string link; try { link = xpp.getAttributeValue("src"); } catch (const std::invalid_argument& ) { LOG(LOG_WARN, "htmlrenderer::render: found embed object without src attribute"); link = ""; } if (link.length() > 0) { unsigned int link_num = add_link(links,utils::censor_url(utils::absolute_url(url,link)), LINK_EMBED); curline.append(utils::strprintf("[%s %u]", _("embedded flash:"), link_num)); } } } break; case TAG_BR: add_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_PRE: inside_pre = true; add_nonempty_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_ITUNESHACK: itunes_hack = true; break; case TAG_IMG: { std::string imgurl; try { imgurl = xpp.getAttributeValue("src"); } catch (const std::invalid_argument& ) { LOG(LOG_WARN,"htmlrenderer::render: found img tag with no src attribute"); imgurl = ""; } if (imgurl.length() > 0) { unsigned int link_num = add_link(links,utils::censor_url(utils::absolute_url(url,imgurl)), LINK_IMG); curline.append(utils::strprintf("[%s %u]", _("image"), link_num)); image_count++; } } break; case TAG_BLOCKQUOTE: ++indent_level; add_nonempty_line(curline, tables, lines); add_line("", tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_H1: case TAG_H2: case TAG_H3: case TAG_H4: case TAG_P: add_nonempty_line(curline, tables, lines); if (lines.size() > 0 && lines[lines.size()-1].length() > static_cast(indent_level*2)) add_line("", tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_OL: is_ol = true; { unsigned int ol_count = 1; try { std::string ol_count_str = xpp.getAttributeValue("start"); std::istringstream is(ol_count_str); is >> ol_count; } catch (const std::invalid_argument& ) { ol_count = 1; } ol_counts.push_back(ol_count); std::string ol_type; try { ol_type = xpp.getAttributeValue("type"); if (ol_type != "1" && ol_type != "a" && ol_type != "A" && ol_type != "i" && ol_type != "I") { ol_type = "1"; } } catch (const std::invalid_argument& ) { ol_type = "1"; } ol_types.push_back(ol_type[0]); } add_nonempty_line(curline, tables, lines); add_line("", tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_UL: is_ol = false; add_nonempty_line(curline, tables, lines); add_line("", tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_LI: if (inside_li) { indent_level-=2; if (indent_level < 0) indent_level = 0; add_nonempty_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); } inside_li = true; add_nonempty_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); indent_level+=2; if (is_ol) { curline.append(utils::strprintf("%s.", format_ol_count(ol_counts[ol_counts.size()-1], ol_types[ol_types.size()-1]).c_str())); ++ol_counts[ol_counts.size()-1]; } else { curline.append(" * "); } break; case TAG_DT: add_nonempty_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_DD: indent_level+=4; add_nonempty_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_DL: // ignore tag break; case TAG_SUP: curline.append("^"); break; case TAG_SUB: curline.append("["); break; case TAG_HR: add_nonempty_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); add_line(std::string(" ") + std::string(w - 2, '-') + std::string(" "), tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_SCRIPT: add_nonempty_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); // don't render scripts, ignore current line inside_script++; break; case TAG_STYLE: inside_style++; break; case TAG_TABLE: { add_nonempty_line(curline, tables, lines); prepare_newline(curline, 0); // no indent in tables bool border = false; try { std::string b = xpp.getAttributeValue("border"); border = (utils::to_u(b) > 0); } catch (const std::invalid_argument& ) { // is ok, no border than } tables.push_back(Table(border)); break; } case TAG_TR: if (!tables.empty()) tables.back().start_row(); break; case TAG_TH: { size_t span = 1; try { span = utils::to_u(xpp.getAttributeValue("colspan")); } catch (const std::invalid_argument& ) { // is ok, span 1 than } if (!tables.empty()) tables.back().start_cell(span); curline.append(""); break; } case TAG_TD: { size_t span = 1; try { span = utils::to_u(xpp.getAttributeValue("colspan")); } catch (const std::invalid_argument& ) { // is ok, span 1 than } if (!tables.empty()) tables.back().start_cell(span); break; } default: break; } break; case tagsouppullparser::END_TAG: tagname = xpp.getText(); std::transform(tagname.begin(), tagname.end(), tagname.begin(), ::tolower); current_tag = tags[tagname]; switch (current_tag) { case TAG_BLOCKQUOTE: --indent_level; if (indent_level < 0) indent_level = 0; add_nonempty_line(curline, tables, lines); add_line("", tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_OL: ol_types.pop_back(); ol_counts.pop_back(); // fall-through case TAG_UL: if (inside_li) { indent_level-=2; if (indent_level < 0) indent_level = 0; add_nonempty_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); } add_nonempty_line(curline, tables, lines); add_line("", tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_DT: add_nonempty_line(curline, tables, lines); add_line("", tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_DD: indent_level-=4; if (indent_level < 0) indent_level = 0; add_nonempty_line(curline, tables, lines); add_line("", tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_DL: // ignore tag break; case TAG_LI: indent_level-=2; if (indent_level < 0) indent_level = 0; inside_li = false; add_nonempty_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_H1: if (line_is_nonempty(curline)) { add_line(curline, tables, lines); size_t llen = utils::strwidth_stfl(curline); prepare_newline(curline, tables.size() ? 0 : indent_level); add_line(std::string(llen, '-'), tables, lines); } prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_H2: case TAG_H3: case TAG_H4: case TAG_P: add_nonempty_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_PRE: add_nonempty_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); inside_pre = false; break; case TAG_SUB: curline.append("]"); break; case TAG_SUP: // has closing tag, but we render nothing. break; case TAG_A: if (link_num != -1) { if (!raw_) curline.append(""); curline.append(utils::strprintf("[%d]", link_num)); link_num = -1; } break; case TAG_UNDERLINE: if (!raw_) curline.append(""); break; case TAG_STRONG: if (!raw_) curline.append(""); break; case TAG_QUOTATION: if (!raw_) curline.append("\""); break; case TAG_EMBED: case TAG_BR: case TAG_ITUNESHACK: case TAG_IMG: case TAG_HR: // ignore closing tags break; case TAG_SCRIPT: // don't render scripts, ignore current line if (inside_script) inside_script--; prepare_newline(curline, tables.size() ? 0 : indent_level); break; case TAG_STYLE: if (inside_style) inside_style--; break; case TAG_TABLE: add_nonempty_line(curline, tables, lines); prepare_newline(curline, 0); // no indent in tables if (!tables.empty()) { std::vector table_text; tables.back().complete_cell(); tables.back().complete_row(); render_table(tables.back(), table_text); tables.pop_back(); if (!tables.empty()) { // still a table on the outside? for(size_t idx=0; idx < table_text.size(); ++idx) tables.back().add_text(table_text[idx]); // add rendered table to current cell } else { for(size_t idx=0; idx < table_text.size(); ++idx) { std::string s = table_text[idx]; while (s.length() > 0 && s[0] == '\n') s.erase(0, 1); add_line(s, tables, lines); } } } prepare_newline(curline, tables.size() ? 0: indent_level); break; case TAG_TR: add_nonempty_line(curline, tables, lines); prepare_newline(curline, 0); // no indent in tables if (!tables.empty()) tables.back().complete_row(); break; case TAG_TH: add_nonempty_line(curline, tables, lines); prepare_newline(curline, 0); // no indent in tables if (!tables.empty()) curline.append(""); tables.back().complete_cell(); break; case TAG_TD: add_nonempty_line(curline, tables, lines); prepare_newline(curline, 0); // no indent in tables if (!tables.empty()) tables.back().complete_cell(); break; default: break; } break; case tagsouppullparser::TEXT: { if (itunes_hack) { std::vector words = utils::tokenize_nl(utils::quote_for_stfl(xpp.getText())); for (std::vector::iterator it=words.begin();it!=words.end();++it) { if (*it == "\n") { add_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); } else { std::vector words2 = utils::tokenize_spaced(*it); unsigned int i=0; bool new_line = false; for (std::vector::iterator it2=words2.begin();it2!=words2.end();++it2,++i) { if ((utils::strwidth_stfl(curline) + utils::strwidth_stfl(*it2)) >= w) { add_nonempty_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); new_line = true; } if (new_line) { if (*it2 != " ") curline.append(*it2); new_line = false; } else { curline.append(*it2); } } } } } else if (inside_pre) { std::vector words = utils::tokenize_nl(utils::quote_for_stfl(xpp.getText())); for (std::vector::iterator it=words.begin();it!=words.end();++it) { if (*it == "\n") { add_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); } else { curline.append(*it); } } } else if (inside_script || inside_style) { // skip scripts and CSS styles } else { std::string s = utils::quote_for_stfl(xpp.getText()); while (s.length() > 0 && s[0] == '\n') s.erase(0, 1); std::vector words = utils::tokenize_spaced(s); unsigned int i=0; bool new_line = false; if (!line_is_nonempty(curline) && !words.empty() && words[0] == " ") { words.erase(words.begin()); } for (std::vector::iterator it=words.begin();it!=words.end();++it,++i) { if ((utils::strwidth_stfl(curline) + utils::strwidth_stfl(*it)) >= w) { add_nonempty_line(curline, tables, lines); prepare_newline(curline, tables.size() ? 0 : indent_level); new_line = true; } if (new_line) { if (*it != " ") curline.append(*it); new_line = false; } else { curline.append(*it); } } } } break; default: /* do nothing */ break; } } // and the rest add_nonempty_line(curline, tables, lines); // force all tables to be closed and rendered while(!tables.empty()) { std::vector table_text; render_table(tables.back(), table_text); tables.pop_back(); for(size_t idx=0; idx < table_text.size(); ++idx) { std::string s = table_text[idx]; while (s.length() > 0 && s[0] == '\n') s.erase(0, 1); add_line(s, tables, lines); } } // add link list if (links.size() > 0) { lines.push_back(""); lines.push_back(_("Links: ")); for (unsigned int i=0;i& tables, std::vector& lines) { if (line_is_nonempty(curline)) add_line(curline, tables, lines); } void htmlrenderer::add_line(const std::string& curline, std::vector
    & tables, std::vector& lines) { if (tables.size()) tables.back().add_text(curline); else lines.push_back(curline); } void htmlrenderer::prepare_newline(std::string& line, int indent_level) { line = ""; line.append(indent_level*2, ' '); } bool htmlrenderer::line_is_nonempty(const std::string& line) { for (unsigned int i=0;i& lines) { // get number of rows size_t rows = table.rows.size(); // get maximum number of cells size_t cells = 0; for(size_t row=0; row < rows; row++) { size_t count = 0; for(size_t cell=0; cell < table.rows[row].cells.size(); cell++) { count += table.rows[row].cells[cell].span; } cells = std::max(cells, count); } // get width of each row std::vector cell_widths; cell_widths.resize(cells, 0); for(size_t row=0; row < rows; row++) { for(size_t cell=0; cell < table.rows[row].cells.size(); cell++) { size_t w = 0; if (table.rows[row].cells[cell].text.size()) { for(size_t idx=0; idx < table.rows[row].cells[cell].text.size(); idx++) w = std::max(w, utils::strwidth_stfl(table.rows[row].cells[cell].text[idx])); } if (table.rows[row].cells[cell].span > 1) { w += table.rows[row].cells[cell].span; w /= table.rows[row].cells[cell].span; // devide size evenly on columns (can be done better, I know) } cell_widths[cell] = std::max(cell_widths[cell], w); } } char hsep = '-'; char vsep = '|'; char hvsep = '+'; // create a row separator std::string separator; if (table.border) separator += hvsep; for(size_t cell=0; cell < cells; cell++) { separator += std::string(cell_widths[cell], hsep); separator += hvsep; } if (!table.border) vsep = ' '; // render the table if (table.border) lines.push_back(separator); for(size_t row=0; row < rows; row++) { // calc height of this row size_t height = 0; for(size_t cell=0; cell < table.rows[row].cells.size(); cell++) height = std::max(height, table.rows[row].cells[cell].text.size()); for(size_t idx=0; idx < height; ++idx) { std::string line; if (table.border) line += vsep; for(size_t cell=0; cell < table.rows[row].cells.size(); cell++) { size_t cell_width = 0; if (idx < table.rows[row].cells[cell].text.size()) { cell_width = utils::strwidth_stfl(table.rows[row].cells[cell].text[idx]); line += table.rows[row].cells[cell].text[idx]; } size_t reference_width = cell_widths[cell]; if (table.rows[row].cells[cell].span > 1) { for(size_t ic=cell+1; ic < cell + table.rows[row].cells[cell].span; ++ic) reference_width += cell_widths[ic]+1; } if (cell_width < reference_width) // pad, if necessary line += std::string(reference_width - cell_width, ' '); if (cell < table.rows[row].cells.size()-1) line += vsep; } if (table.border) line += vsep; lines.push_back(line); } if (table.border) lines.push_back(separator); } } std::string htmlrenderer::get_char_numbering(unsigned int count) { std::string result; do { count--; result.append(1, 'a'+(count % 26)); count /= 26; } while (count > 0); std::reverse(result.begin(), result.end()); return result; } std::string htmlrenderer::get_roman_numbering(unsigned int count) { unsigned int values[] = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 }; const char * numerals[] = { "m", "cm", "d", "cd", "c", "xc", "l", "xl", "x", "ix", "v", "iv", "i" }; std::string result; for (unsigned int i=0;i<(sizeof(values)/sizeof(values[0]));i++) { while (count >= values[i]) { count -= values[i]; result.append(numerals[i]); } } return result; } std::string htmlrenderer::format_ol_count(unsigned int count, char type) { switch (type) { case 'a': return get_char_numbering(count); case 'A': { std::string num = get_char_numbering(count); std::transform(num.begin(), num.end(), num.begin(), ::toupper); return num; } case 'i': return get_roman_numbering(count); case 'I': { std::string roman = get_roman_numbering(count); std::transform(roman.begin(), roman.end(), roman.begin(), ::toupper); return roman; } case '1': default: return utils::strprintf("%2u", count); } } } newsbeuter-2.7/src/itemlist_formaction.cpp000066400000000000000000001002371220711462700211200ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #define FILTER_UNREAD_ITEMS "unread != \"no\"" namespace newsbeuter { itemlist_formaction::itemlist_formaction(view * vv, std::string formstr) : formaction(vv,formstr), apply_filter(false), update_visible_items(true), show_searchresult(false), search_dummy_feed(new rss_feed(v->get_ctrl()->get_cache())), set_filterpos(false), filterpos(0), rxman(0), old_width(0), old_itempos(-1) { assert(true==m.parse(FILTER_UNREAD_ITEMS)); old_sort_order = ""; } itemlist_formaction::~itemlist_formaction() { } void itemlist_formaction::process_operation(operation op, bool automatic, std::vector * args) { bool quit = false; bool hardquit = false; /* * most of the operations go like this: * - extract the current position * - if an item was selected, then fetch it and do something with it */ std::string itemposname = f->get("itempos"); unsigned int itempos = utils::to_u(itemposname); switch (op) { case OP_OPEN: { LOG(LOG_INFO, "itemlist_formaction: opening item at pos `%s'", itemposname.c_str()); if (itemposname.length() > 0 && visible_items.size() != 0) { // no need to mark item as read, the itemview already do that old_itempos = itempos; v->push_itemview(feed, visible_items[itempos].first->guid(), show_searchresult ? searchphrase : ""); do_redraw = true; } else { v->show_error(_("No item selected!")); // should not happen } } break; case OP_DELETE: { scope_measure m1("OP_DELETE"); if (itemposname.length() > 0 && visible_items.size() != 0) { // mark as read v->get_ctrl()->mark_article_read(visible_items[itempos].first->guid(), true); visible_items[itempos].first->set_unread(false); // mark as deleted visible_items[itempos].first->set_deleted(!visible_items[itempos].first->deleted()); v->get_ctrl()->mark_deleted(visible_items[itempos].first->guid(), visible_items[itempos].first->deleted()); if (itempos < visible_items.size()-1) f->set("itempos", utils::strprintf("%u", itempos + 1)); do_redraw = true; } else { v->show_error(_("No item selected!")); // should not happen } } break; case OP_PURGE_DELETED: { scope_measure m1("OP_PURGE_DELETED"); feed->purge_deleted_items(); update_visible_items = true; do_redraw = true; } break; case OP_OPENBROWSER_AND_MARK: { LOG(LOG_INFO, "itemlist_formaction: opening item at pos `%s'", itemposname.c_str()); if (itemposname.length() > 0 && visible_items.size() != 0) { if (itempos < visible_items.size()) { visible_items[itempos].first->set_unread(false); v->get_ctrl()->mark_article_read(visible_items[itempos].first->guid(), true); v->open_in_browser(visible_items[itempos].first->link()); if (!v->get_cfg()->get_configvalue_as_bool("openbrowser-and-mark-jumps-to-next-unread")) { if (itempos < visible_items.size()-1) { f->set("itempos", utils::strprintf("%u", itempos + 1)); } } else { process_operation(OP_NEXTUNREAD); } do_redraw = true; } } else { v->show_error(_("No item selected!")); // should not happen } } break; case OP_OPENINBROWSER: { LOG(LOG_INFO, "itemlist_formaction: opening item at pos `%s'", itemposname.c_str()); if (itemposname.length() > 0 && visible_items.size() != 0) { if (itempos < visible_items.size()) { v->open_in_browser(visible_items[itempos].first->link()); do_redraw = true; } } else { v->show_error(_("No item selected!")); // should not happen } } break; case OP_TOGGLEITEMREAD: { LOG(LOG_INFO, "itemlist_formaction: toggling item read at pos `%s'", itemposname.c_str()); if (itemposname.length() > 0) { v->set_status(_("Toggling read flag for article...")); try { if (automatic && args->size() > 0) { if ((*args)[0] == "read") { visible_items[itempos].first->set_unread(false); v->get_ctrl()->mark_article_read(visible_items[itempos].first->guid(), true); } else if ((*args)[0] == "unread") { visible_items[itempos].first->set_unread(true); v->get_ctrl()->mark_article_read(visible_items[itempos].first->guid(), false); } v->set_status(""); } else { bool unread = visible_items[itempos].first->unread(); visible_items[itempos].first->set_unread(!unread); v->get_ctrl()->mark_article_read(visible_items[itempos].first->guid(), unread); v->set_status(""); } } catch (const dbexception& e) { v->set_status(utils::strprintf(_("Error while toggling read flag: %s"), e.what())); } if (!v->get_cfg()->get_configvalue_as_bool("toggleitemread-jumps-to-next-unread")) { if (itempos < visible_items.size()-1) f->set("itempos", utils::strprintf("%u", itempos + 1)); } else { process_operation(OP_NEXTUNREAD); } do_redraw = true; } } break; case OP_SHOWURLS: if (itemposname.length() > 0 && visible_items.size() != 0) { if (itempos < visible_items.size()) { std::string urlviewer = v->get_cfg()->get_configvalue("external-url-viewer"); if (urlviewer == "") { std::vector links; std::vector lines; htmlrenderer rnd(80); std::string baseurl = visible_items[itempos].first->get_base() != "" ? visible_items[itempos].first->get_base() : visible_items[itempos].first->feedurl(); rnd.render(visible_items[itempos].first->description(), lines, links, baseurl); if (!links.empty()) { v->push_urlview(links); } else { v->show_error(_("URL list empty.")); } } else { qna_responses.clear(); qna_responses.push_back(urlviewer); this->finished_qna(OP_PIPE_TO); } } } else { v->show_error(_("No item selected!")); // should not happen } break; case OP_BOOKMARK: { LOG(LOG_INFO, "itemlist_formaction: bookmarking item at pos `%s'", itemposname.c_str()); if (itemposname.length() > 0 && visible_items.size() != 0) { if (itempos < visible_items.size()) { if (automatic) { qna_responses.clear(); qna_responses.push_back(visible_items[itempos].first->title()); qna_responses.push_back(visible_items[itempos].first->link()); qna_responses.push_back(args->size() > 0 ? (*args)[0] : ""); this->finished_qna(OP_INT_BM_END); } else { this->start_bookmark_qna(visible_items[itempos].first->title(), visible_items[itempos].first->link(), ""); } } } else { v->show_error(_("No item selected!")); // should not happen } } break; case OP_EDITFLAGS: { if (itemposname.length() > 0 && visible_items.size() != 0) { if (itempos < visible_items.size()) { if (automatic) { if (args->size() > 0) { qna_responses.clear(); qna_responses.push_back((*args)[0]); finished_qna(OP_INT_EDITFLAGS_END); } } else { std::vector qna; qna.push_back(qna_pair(_("Flags: "), visible_items[itempos].first->flags())); this->start_qna(qna, OP_INT_EDITFLAGS_END); } } } else { v->show_error(_("No item selected!")); // should not happen } } break; case OP_SAVE: { LOG(LOG_INFO, "itemlist_formaction: saving item at pos `%s'", itemposname.c_str()); if (itemposname.length() > 0 && visible_items.size() != 0) { std::string filename ; if (automatic) { if (args->size() > 0) { filename = (*args)[0]; } } else { filename = v->run_filebrowser(v->get_filename_suggestion(visible_items[itempos].first->title())); } save_article(filename, visible_items[itempos].first); } else { v->show_error(_("Error: no item selected!")); } } break; case OP_HELP: v->push_help(); break; case OP_RELOAD: if (!show_searchresult) { LOG(LOG_INFO, "itemlist_formaction: reloading current feed"); v->get_ctrl()->reload(pos); update_visible_items = true; do_redraw = true; } else { v->show_error(_("Error: you can't reload search results.")); } break; case OP_QUIT: LOG(LOG_INFO, "itemlist_formaction: quitting"); v->feedlist_mark_pos_if_visible(pos); feed->purge_deleted_items(); feed->unload(); quit = true; break; case OP_HARDQUIT: LOG(LOG_INFO, "itemlist_formaction: hard quitting"); v->feedlist_mark_pos_if_visible(pos); feed->purge_deleted_items(); hardquit = true; break; case OP_NEXTUNREAD: LOG(LOG_INFO, "itemlist_formaction: jumping to next unread item"); if (!jump_to_next_unread_item(false)) { if (!v->get_next_unread(this)) { v->show_error(_("No unread items.")); } } break; case OP_PREVUNREAD: LOG(LOG_INFO, "itemlist_formaction: jumping to previous unread item"); if (!jump_to_previous_unread_item(false)) { if (!v->get_previous_unread(this)) { v->show_error(_("No unread items.")); } } break; case OP_NEXT: LOG(LOG_INFO, "itemlist_formaction: jumping to next item"); if (!jump_to_next_item(false)) { if (!v->get_next(this)) { v->show_error(_("Already on last item.")); } } break; case OP_PREV: LOG(LOG_INFO, "itemlist_formaction: jumping to previous item"); if (!jump_to_previous_item(false)) { if (!v->get_previous(this)) { v->show_error(_("Already on first item.")); } } break; case OP_RANDOMUNREAD: if (!jump_to_random_unread_item()) { if (!v->get_random_unread(this)) { v->show_error(_("No unread items.")); } } break; case OP_NEXTUNREADFEED: if (!v->get_next_unread_feed(this)) { v->show_error(_("No unread feeds.")); } break; case OP_PREVUNREADFEED: if (!v->get_prev_unread_feed(this)) { v->show_error(_("No unread feeds.")); } break; case OP_NEXTFEED: if (!v->get_next_feed(this)) { v->show_error(_("Already on last feed.")); } break; case OP_PREVFEED: if (!v->get_prev_feed(this)) { v->show_error(_("Already on first feed.")); } break; case OP_MARKFEEDREAD: LOG(LOG_INFO, "itemlist_formaction: marking feed read"); v->set_status(_("Marking feed read...")); try { if (feed->rssurl() != "") { v->get_ctrl()->mark_all_read(pos); } else { { scope_mutex lock(&feed->item_mutex); LOG(LOG_DEBUG, "itemlist_formaction: oh, it looks like I'm in a pseudo-feed (search result, query feed)"); for (std::vector >::iterator it=feed->items().begin();it!=feed->items().end();++it) { (*it)->set_unread_nowrite_notify(false, true); // TODO: do we need to call mark_article_read here, too? } } v->get_ctrl()->catchup_all(feed); } if (v->get_cfg()->get_configvalue_as_bool("markfeedread-jumps-to-next-unread")) process_operation(OP_NEXTUNREAD); do_redraw = true; v->set_status(""); } catch (const dbexception& e) { v->show_error(utils::strprintf(_("Error: couldn't mark feed read: %s"), e.what())); } break; case OP_TOGGLESHOWREAD: m.parse(FILTER_UNREAD_ITEMS); LOG(LOG_DEBUG, "itemlist_formaction: toggling show-read-articles"); if (v->get_cfg()->get_configvalue_as_bool("show-read-articles")) { v->get_cfg()->set_configvalue("show-read-articles", "no"); apply_filter = true; } else { v->get_cfg()->set_configvalue("show-read-articles", "yes"); apply_filter = false; } save_filterpos(); update_visible_items = true; do_redraw = true; break; case OP_PIPE_TO: if(visible_items.size() != 0) { std::vector qna; if (automatic) { if (args->size() > 0) { qna_responses.clear(); qna_responses.push_back((*args)[0]); finished_qna(OP_PIPE_TO); } } else { qna.push_back(qna_pair(_("Pipe article to command: "), "")); this->start_qna(qna, OP_PIPE_TO, &cmdlinehistory); } } else { v->show_error(_("No item selected!")); } break; case OP_SEARCH: { std::vector qna; if (automatic) { if (args->size() > 0) { qna_responses.clear(); qna_responses.push_back((*args)[0]); finished_qna(OP_INT_START_SEARCH); } } else { qna.push_back(qna_pair(_("Search for: "), "")); this->start_qna(qna, OP_INT_START_SEARCH, &searchhistory); } } break; case OP_EDIT_URLS: v->get_ctrl()->edit_urls_file(); break; case OP_SELECTFILTER: if (v->get_ctrl()->get_filters().size() > 0) { std::string newfilter; if (automatic) { if (args->size() > 0) newfilter = (*args)[0]; } else { newfilter = v->select_filter(v->get_ctrl()->get_filters().get_filters()); LOG(LOG_DEBUG,"itemlist_formaction::run: newfilters = %s", newfilter.c_str()); } if (newfilter != "") { filterhistory.add_line(newfilter); if (newfilter.length() > 0) { if (!m.parse(newfilter)) { v->show_error(utils::strprintf(_("Error: couldn't parse filter command `%s': %s"), newfilter.c_str(), m.get_parse_error().c_str())); m.parse(FILTER_UNREAD_ITEMS); } else { apply_filter = true; update_visible_items = true; do_redraw = true; save_filterpos(); } } } } else { v->show_error(_("No filters defined.")); } break; case OP_SETFILTER: if (automatic) { if (args->size() > 0) { qna_responses.clear(); qna_responses.push_back((*args)[0]); this->finished_qna(OP_INT_END_SETFILTER); } } else { std::vector qna; qna.push_back(qna_pair(_("Filter: "), "")); this->start_qna(qna, OP_INT_END_SETFILTER, &filterhistory); } break; case OP_CLEARFILTER: apply_filter = false; update_visible_items = true; do_redraw = true; save_filterpos(); break; case OP_SORT: { char c = v->confirm(_("Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?"), _("dtfalg")); if (!c) break; std::string result(1, c); if (result == _("d")) { v->get_cfg()->set_configvalue("article-sort-order", "date-asc"); } else if (result == _("t")) { v->get_cfg()->set_configvalue("article-sort-order", "title-asc"); } else if (result == _("f")) { v->get_cfg()->set_configvalue("article-sort-order", "flags-asc"); } else if (result == _("a")) { v->get_cfg()->set_configvalue("article-sort-order", "author-asc"); } else if (result == _("l")) { v->get_cfg()->set_configvalue("article-sort-order", "link-asc"); } else if (result == _("g")) { v->get_cfg()->set_configvalue("article-sort-order", "guid-asc"); } } break; case OP_REVSORT: { char c = v->confirm(_("Reverse Sort by (d)ate/(t)itle/(f)lags/(a)uthor/(l)ink/(g)uid?"), _("dtfalg")); if (!c) break; std::string result(1, c); if (result == _("d")) { v->get_cfg()->set_configvalue("article-sort-order", "date-desc"); } else if (result == _("t")) { v->get_cfg()->set_configvalue("article-sort-order", "title-desc"); } else if (result == _("f")) { v->get_cfg()->set_configvalue("article-sort-order", "flags-desc"); } else if (result == _("a")) { v->get_cfg()->set_configvalue("article-sort-order", "author-desc"); } else if (result == _("l")) { v->get_cfg()->set_configvalue("article-sort-order", "link-desc"); } else if (result == _("g")) { v->get_cfg()->set_configvalue("article-sort-order", "guid-desc"); } } break; case OP_INT_RESIZE: do_redraw = true; break; default: break; } if (hardquit) { while (v->formaction_stack_size() > 0) { v->pop_current_formaction(); } } else if (quit) { v->pop_current_formaction(); } } void itemlist_formaction::finished_qna(operation op) { formaction::finished_qna(op); // important! switch (op) { case OP_INT_END_SETFILTER: qna_end_setfilter(); break; case OP_INT_EDITFLAGS_END: qna_end_editflags(); break; case OP_INT_START_SEARCH: qna_start_search(); break; case OP_PIPE_TO: { std::string itemposname = f->get("itempos"); unsigned int itempos = utils::to_u(itemposname); if (itemposname.length() > 0) { std::string cmd = qna_responses[0]; std::ostringstream ostr; v->get_ctrl()->write_item(visible_items[itempos].first, ostr); v->push_empty_formaction(); stfl::reset(); FILE * f = popen(cmd.c_str(), "w"); if (f) { std::string data = ostr.str(); fwrite(data.c_str(), data.length(), 1, f); pclose(f); } v->pop_current_formaction(); } } break; default: break; } } void itemlist_formaction::qna_end_setfilter() { std::string filtertext = qna_responses[0]; filterhistory.add_line(filtertext); if (filtertext.length() > 0) { if (!m.parse(filtertext)) { v->show_error(_("Error: couldn't parse filter command!")); return; } apply_filter = true; update_visible_items = true; do_redraw = true; save_filterpos(); } } void itemlist_formaction::qna_end_editflags() { std::string itemposname = f->get("itempos"); if (itemposname.length() == 0) { v->show_error(_("No item selected!")); // should not happen return; } std::istringstream posname(itemposname); unsigned int itempos = 0; posname >> itempos; if (itempos < visible_items.size()) { visible_items[itempos].first->set_flags(qna_responses[0]); v->get_ctrl()->update_flags(visible_items[itempos].first); v->set_status(_("Flags updated.")); LOG(LOG_DEBUG, "itemlist_formaction::finished_qna: updated flags"); do_redraw = true; } } void itemlist_formaction::qna_start_search() { searchphrase = qna_responses[0]; if (searchphrase.length() == 0) return; v->set_status(_("Searching...")); searchhistory.add_line(searchphrase); std::vector > items; try { std::string utf8searchphrase = utils::convert_text(searchphrase, "utf-8", nl_langinfo(CODESET)); if (show_searchresult) { items = v->get_ctrl()->search_for_items(utf8searchphrase, ""); } else { items = v->get_ctrl()->search_for_items(utf8searchphrase, feed->rssurl()); } } catch (const dbexception& e) { v->show_error(utils::strprintf(_("Error while searching for `%s': %s"), searchphrase.c_str(), e.what())); return; } if (items.empty()) { v->show_error(_("No results.")); return; } { scope_mutex lock(&search_dummy_feed->item_mutex); for (std::vector >::iterator it=items.begin();it!=items.end();++it) { search_dummy_feed->add_item(*it); } } if (show_searchresult) { v->pop_current_formaction(); } v->push_searchresult(search_dummy_feed, searchphrase); } void itemlist_formaction::do_update_visible_items() { if (!update_visible_items) return; update_visible_items = false; scope_mutex lock(&feed->item_mutex); std::vector >& items = feed->items(); std::vector new_visible_items; /* * this method doesn't redraw, all it does is to go through all * items of a feed, and fill the visible_items vector by checking * (if applicable) whether an items matches the currently active filter. */ unsigned int i=0; for (std::vector >::iterator it = items.begin(); it != items.end(); ++it, ++i) { (*it)->set_index(i+1); if (!apply_filter || m.matches(it->get())) { new_visible_items.push_back(itemptr_pos_pair(*it, i)); } } LOG(LOG_DEBUG, "itemlist_formaction::do_update_visible_items: size = %u", visible_items.size()); visible_items = new_visible_items; do_redraw = true; } void itemlist_formaction::prepare() { scope_mutex mtx(&redraw_mtx); std::string sort_order = v->get_cfg()->get_configvalue("article-sort-order"); if (sort_order != old_sort_order) { feed->sort(sort_order); old_sort_order = sort_order; update_visible_items = true; do_redraw = true; } try { do_update_visible_items(); } catch (matcherexception& e) { v->show_error(utils::strprintf(_("Error: applying the filter failed: %s"), e.what())); return; } if (v->get_cfg()->get_configvalue_as_bool("mark-as-read-on-hover")) { std::string itemposname = f->get("itempos"); if (itemposname.length() > 0) { unsigned int itempos = utils::to_u(itemposname); if (visible_items[itempos].first->unread()) { visible_items[itempos].first->set_unread(false); v->get_ctrl()->mark_article_read(visible_items[itempos].first->guid(), true); do_redraw = true; } } } unsigned int width = utils::to_u(f->get("items:w")); if (old_width != width) { do_redraw = true; old_width = width; } if (!do_redraw) return; do_redraw = false; listformatter listfmt; std::string datetimeformat = v->get_cfg()->get_configvalue("datetime-format"); std::string itemlist_format = v->get_cfg()->get_configvalue("articlelist-format"); for (std::vector::iterator it = visible_items.begin(); it != visible_items.end(); ++it) { std::string tmp_itemlist_format = itemlist_format; fmtstr_formatter fmt; fmt.register_fmt('i', utils::strprintf("%u",it->second + 1)); fmt.register_fmt('f', gen_flags(it->first)); fmt.register_fmt('D', gen_datestr(it->first->pubDate_timestamp(), datetimeformat.c_str())); if (feed->rssurl() != it->first->feedurl() && it->first->get_feedptr() != NULL) { fmt.register_fmt('T', utils::replace_all(it->first->get_feedptr()->title(), "<", "<>")); } fmt.register_fmt('t', utils::replace_all(it->first->title(), "<", "<>")); fmt.register_fmt('a', utils::replace_all(it->first->author(), "<", "<>")); fmt.register_fmt('L', it->first->length()); if (rxman) { int id; if ((id = rxman->article_matches(it->first.get())) != -1) { tmp_itemlist_format = utils::strprintf("<%d>%s", id, itemlist_format.c_str()); } } if (it->first->unread()) { tmp_itemlist_format = utils::strprintf("%s", itemlist_format.c_str()); } listfmt.add_line(fmt.do_format(tmp_itemlist_format, width), it->second); } f->modify("items","replace_inner", listfmt.format_list(rxman, "articlelist")); set_head(feed->title(),feed->unread_item_count(),feed->items().size(), feed->rssurl()); prepare_set_filterpos(); } void itemlist_formaction::init() { f->set("itempos","0"); f->set("msg",""); do_redraw = true; set_keymap_hints(); apply_filter = !(v->get_cfg()->get_configvalue_as_bool("show-read-articles")); update_visible_items = true; do_update_visible_items(); if (v->get_cfg()->get_configvalue_as_bool("goto-first-unread")) { jump_to_next_unread_item(true); } f->run(-3); // FRUN - compute all widget dimensions } void itemlist_formaction::set_head(const std::string& s, unsigned int unread, unsigned int total, const std::string &url) { /* * Since the itemlist_formaction is also used to display search results, we always need to set the right title */ std::string title; fmtstr_formatter fmt; std::string listwidth = f->get("items:w"); std::istringstream is(listwidth); unsigned int width; is >> width; fmt.register_fmt('N', PROGRAM_NAME); fmt.register_fmt('V', PROGRAM_VERSION); fmt.register_fmt('u', utils::to_string(unread)); fmt.register_fmt('t', utils::to_string(total)); fmt.register_fmt('T', s); fmt.register_fmt('U', utils::censor_url(url)); if (!show_searchresult) { title = fmt.do_format(v->get_cfg()->get_configvalue("articlelist-title-format")); } else { title = fmt.do_format(v->get_cfg()->get_configvalue("searchresult-title-format")); } f->set("head", title); } bool itemlist_formaction::jump_to_previous_unread_item(bool start_with_last) { int itempos; std::istringstream is(f->get("itempos")); is >> itempos; for (int i=(start_with_last?itempos:(itempos-1));i>=0;--i) { LOG(LOG_DEBUG, "itemlist_formaction::jump_to_previous_unread_item: visible_items[%u] unread = %s", i, visible_items[i].first->unread() ? "true" : "false"); if (visible_items[i].first->unread()) { f->set("itempos", utils::to_string(i)); return true; } } for (int i=visible_items.size()-1;i>=itempos;--i) { if (visible_items[i].first->unread()) { f->set("itempos", utils::to_string(i)); return true; } } return false; } bool itemlist_formaction::jump_to_random_unread_item() { bool has_unread_available = false; for (unsigned int i=0;iunread()) { has_unread_available = true; break; } } if (has_unread_available) { for (;;) { unsigned int pos = utils::get_random_value(visible_items.size()); if (visible_items[pos].first->unread()) { f->set("itempos", utils::to_string(pos)); break; } } } return has_unread_available; } bool itemlist_formaction::jump_to_next_unread_item(bool start_with_first) { unsigned int itempos; std::istringstream is(f->get("itempos")); is >> itempos; LOG(LOG_DEBUG, "itemlist_formaction::jump_to_next_unread_item: itempos = %u visible_items.size = %u", itempos, visible_items.size()); for (unsigned int i=(start_with_first?itempos:(itempos+1));iunread()) { f->set("itempos", utils::to_string(i)); return true; } } for (unsigned int i=0;i<=itempos;++i) { LOG(LOG_DEBUG, "itemlist_formaction::jump_to_next_unread_item: i = %u", i); if (visible_items[i].first->unread()) { f->set("itempos", utils::to_string(i)); return true; } } return false; } bool itemlist_formaction::jump_to_previous_item(bool start_with_last) { int itempos; std::istringstream is(f->get("itempos")); is >> itempos; for (int i=(start_with_last?itempos:(itempos-1));i>=0;--i) { LOG(LOG_DEBUG, "itemlist_formaction::jump_to_previous_item: visible_items[%u]", i); f->set("itempos", utils::to_string(i)); return true; } return false; // not sure if we should exit here or continue // wrap to last item for (int i=visible_items.size()-1;i>=itempos;--i) { f->set("itempos", utils::to_string(i)); return true; } return false; } bool itemlist_formaction::jump_to_next_item(bool start_with_first) { unsigned int itempos; std::istringstream is(f->get("itempos")); is >> itempos; LOG(LOG_DEBUG, "itemlist_formaction::jump_to_next_item: itempos = %u visible_items.size = %u", itempos, visible_items.size()); for (unsigned int i=(start_with_first?itempos:(itempos+1));iset("itempos", utils::to_string(i)); return true; } return false; // not sure if we should exit here or continue // wrap to first item for (unsigned int i=0;i<=itempos;++i) { LOG(LOG_DEBUG, "itemlist_formaction::jump_to_next_item: i = %u", i); f->set("itempos", utils::to_string(i)); return true; } return false; } std::string itemlist_formaction::get_guid() { unsigned int itempos; std::istringstream is(f->get("itempos")); is >> itempos; return visible_items[itempos].first->guid(); } keymap_hint_entry * itemlist_formaction::get_keymap_hint() { static keymap_hint_entry hints[] = { { OP_QUIT, _("Quit") }, { OP_OPEN, _("Open") }, { OP_SAVE, _("Save") }, { OP_RELOAD, _("Reload") }, { OP_NEXTUNREAD, _("Next Unread") }, { OP_MARKFEEDREAD, _("Mark All Read") }, { OP_SEARCH, _("Search") }, { OP_HELP, _("Help") }, { OP_NIL, NULL } }; return hints; } void itemlist_formaction::handle_cmdline_num(unsigned int idx) { if (idx > 0 && idx <= visible_items[visible_items.size()-1].second + 1) { int i = get_pos(idx - 1); if (i == -1) { v->show_error(_("Position not visible!")); } else { f->set("itempos", utils::to_string(i)); } } else { v->show_error(_("Invalid position!")); } } void itemlist_formaction::handle_cmdline(const std::string& cmd) { unsigned int idx = 0; if (1==sscanf(cmd.c_str(),"%u",&idx)) { handle_cmdline_num(idx); } else { std::vector tokens = utils::tokenize_quoted(cmd); if (tokens.empty()) return; if (tokens[0] == "save" && tokens.size() >= 2) { std::string filename = utils::resolve_tilde(tokens[1]); std::string itemposname = f->get("itempos"); LOG(LOG_INFO, "itemlist_formaction::handle_cmdline: saving item at pos `%s' to `%s'", itemposname.c_str(), filename.c_str()); if (itemposname.length() > 0) { std::istringstream posname(itemposname); unsigned int itempos = 0; posname >> itempos; save_article(filename, visible_items[itempos].first); } else { v->show_error(_("Error: no item selected!")); } } else { formaction::handle_cmdline(cmd); } } } int itemlist_formaction::get_pos(unsigned int realidx) { for (unsigned int i=0;iget("itempos"); unsigned int itempos = utils::to_u(itemposname); // If the old position was set and it is less than the itempos, use it for the feed's itempos // Correct the problem when you open itemview and jump to next then exit to itemlist and the itempos is wrong // This only applies when "show-read-articles" is set to false if ( (old_itempos != -1) && itempos > (unsigned int)old_itempos && ! v->get_cfg()->get_configvalue_as_bool("show-read-articles") ) { f->set("itempos", utils::strprintf("%u", old_itempos)); old_itempos = -1; // Reset } } void itemlist_formaction::save_article(const std::string& filename, std::tr1::shared_ptr item) { if (filename == "") { v->show_error(_("Aborted saving.")); } else { try { v->get_ctrl()->write_item(item, filename); v->show_error(utils::strprintf(_("Saved article to %s"), filename.c_str())); } catch (...) { v->show_error(utils::strprintf(_("Error: couldn't save article to %s"), filename.c_str())); } } } void itemlist_formaction::save_filterpos() { std::istringstream is(f->get("itempos")); unsigned int i; is >> i; if (i& attrs = r->get_attrs("articlelist"); unsigned int i=0; std::string attrstr; for (std::vector::iterator it=attrs.begin();it!=attrs.end();++it,++i) { attrstr.append(utils::strprintf("@style_%u_normal:%s ", i, it->c_str())); attrstr.append(utils::strprintf("@style_%u_focus:%s ", i, it->c_str())); } std::string textview = utils::strprintf("{list[items] .expand:vh style_normal[listnormal]: style_focus[listfocus]:fg=yellow,bg=blue,attr=bold pos_name[itemposname]: pos[itempos]:0 %s richtext:1}", attrstr.c_str()); f->modify("items", "replace", textview); } std::string itemlist_formaction::gen_flags(std::tr1::shared_ptr item) { std::string flags; if (item->deleted()) { flags.append("D"); } else if (item->unread()) { flags.append("N"); } else { flags.append(" "); } if (item->flags().length() > 0) { flags.append("!"); } else { flags.append(" "); } return flags; } std::string itemlist_formaction::gen_datestr(time_t t, const char * datetimeformat) { char datebuf[64]; struct tm * stm = localtime(&t); strftime(datebuf,sizeof(datebuf), datetimeformat, stm); return datebuf; } void itemlist_formaction::prepare_set_filterpos() { if (set_filterpos) { set_filterpos = false; unsigned int i=0; for (std::vector::iterator it=visible_items.begin();it!=visible_items.end();++it, ++i) { if (it->second == filterpos) { f->set("itempos", utils::to_string(i)); return; } } f->set("itempos", "0"); } } void itemlist_formaction::set_feed(std::tr1::shared_ptr fd) { LOG(LOG_DEBUG, "itemlist_formaction::set_feed: fd pointer = %p title = `%s'", fd.get(), fd->title().c_str()); feed = fd; feed->load(); update_visible_items = true; do_update_visible_items(); } std::string itemlist_formaction::title() { if (feed->rssurl() == "") { return utils::strprintf(_("Search Result - '%s'"), searchphrase.c_str()); } else { if (feed->rssurl().substr(0,6) == "query:") return utils::strprintf(_("Query Feed - %s"), feed->rssurl().substr(6,feed->rssurl().length()-6).c_str()); else return utils::strprintf(_("Article List - %s"), feed->title().c_str()); } } } newsbeuter-2.7/src/itemview_formaction.cpp000066400000000000000000000455451220711462700211310ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include namespace newsbeuter { itemview_formaction::itemview_formaction(view * vv, std::tr1::shared_ptr il, std::string formstr) : formaction(vv,formstr), show_source(false), quit(false), rxman(0), num_lines(0), itemlist(il), in_search(false) { valid_cmds.push_back("save"); std::sort(valid_cmds.begin(), valid_cmds.end()); } itemview_formaction::~itemview_formaction() { } void itemview_formaction::init() { f->set("msg",""); do_redraw = true; quit = false; links.clear(); num_lines = 0; if (!v->get_cfg()->get_configvalue_as_bool("display-article-progress")) { f->set("percentwidth", "0"); } else { f->set("percentwidth", utils::to_string(utils::max(6, utils::max(strlen(_("Top")), strlen(_("Bottom")))))); update_percent(); } set_keymap_hints(); } void itemview_formaction::prepare() { /* * whenever necessary, the item view is regenerated. This is done * by putting together the feed name, title, link, author, optional * flags and podcast download URL (enclosures) and then render the * HTML. The links extracted by the renderer are then appended, too. */ if (do_redraw) { { scope_measure("itemview::prepare: rendering"); f->run(-3); // XXX HACK: render once so that we get a proper widget width } std::vector lines; std::string widthstr = f->get("article:w"); unsigned int render_width = 80; unsigned int view_width = 0; if (widthstr.length() > 0) { view_width = render_width = utils::to_u(widthstr); if (render_width - 5 > 0) render_width -= 5; } std::tr1::shared_ptr item = feed->get_item_by_guid(guid); listformatter listfmt; std::tr1::shared_ptr feedptr = item->get_feedptr(); std::string title, feedtitle; if (feedptr.get() != NULL) { if (feedptr->title().length() > 0) { title = feedptr->title(); } else if (feedptr->link().length() > 0) { title = feedptr->link(); } else if (feedptr->rssurl().length() > 0) { title = feedptr->rssurl(); } } if (title.length() > 0) { feedtitle = utils::strprintf("%s%s", _("Feed: "), title.c_str()); listfmt.add_line(feedtitle, UINT_MAX, view_width); } if (item->title().length() > 0) { title = utils::strprintf("%s%s", _("Title: "), item->title().c_str()); listfmt.add_line(title, UINT_MAX, view_width); } if (item->author().length() > 0) { std::string author = utils::strprintf("%s%s", _("Author: "), item->author().c_str()); listfmt.add_line(author, UINT_MAX, view_width); } if (item->link().length() > 0) { std::string link = utils::strprintf("%s%s", _("Link: "), utils::censor_url(item->link()).c_str()); listfmt.add_line(link, UINT_MAX, view_width); } std::string date = utils::strprintf("%s%s", _("Date: "), item->pubDate().c_str()); listfmt.add_line(date, UINT_MAX, view_width); if (item->flags().length() > 0) { std::string flags = utils::strprintf("%s%s", _("Flags: "), item->flags().c_str()); listfmt.add_line(flags, UINT_MAX, view_width); } if (item->enclosure_url().length() > 0) { std::string enc_url = utils::strprintf("%s%s", _("Podcast Download URL: "), utils::censor_url(item->enclosure_url()).c_str()); if (item->enclosure_type() != "") { enc_url.append(utils::strprintf(" (%s%s)", _("type: "), item->enclosure_type().c_str())); } listfmt.add_line(enc_url, UINT_MAX, view_width); } listfmt.add_line(""); unsigned int unread_item_count = feed->unread_item_count(); // we need to subtract because the current item isn't yet marked as read if (item->unread()) unread_item_count--; set_head(item->title(), unread_item_count, feed->items().size()); unsigned int textwidth = v->get_cfg()->get_configvalue_as_int("text-width"); if (textwidth > 0) { render_width = textwidth; } if (show_source) { render_source(lines, utils::quote_for_stfl(item->description()), render_width); } else { std::string baseurl = item->get_base() != "" ? item->get_base() : item->feedurl(); lines = render_html(item->description(), links, baseurl, render_width); } listfmt.add_lines(lines, view_width); num_lines = listfmt.get_lines_count(); f->modify("article","replace_inner",listfmt.format_list(rxman, "article")); f->set("articleoffset","0"); if (in_search) { rxman->remove_last_regex("article"); in_search = false; } do_redraw = false; } } void itemview_formaction::process_operation(operation op, bool automatic, std::vector * args) { std::tr1::shared_ptr item = feed->get_item_by_guid(guid); bool hardquit = false; /* * whenever we process an operation, we mark the item * as read. Don't worry: when an item is already marked as * read, and then marked as read again, no database update * is done, since only _changes_ to the unread flag are * recorded in the database. */ try { bool old_unread = item->unread(); item->set_unread(false); if (old_unread) { v->get_ctrl()->mark_article_read(item->guid(), true); } } catch (const dbexception& e) { v->show_error(utils::strprintf(_("Error while marking article as read: %s"), e.what())); } switch (op) { case OP_TOGGLESOURCEVIEW: LOG(LOG_INFO, "view::run_itemview: toggling source view"); show_source = !show_source; do_redraw = true; break; case OP_ENQUEUE: { if (item->enclosure_url().length() > 0 && utils::is_http_url(item->enclosure_url())) { v->get_ctrl()->enqueue_url(item->enclosure_url(), feed); v->set_status(utils::strprintf(_("Added %s to download queue."), item->enclosure_url().c_str())); } else { v->set_status(utils::strprintf(_("Invalid URL: '%s'"), item->enclosure_url().c_str())); } } break; case OP_SAVE: { LOG(LOG_INFO, "view::run_itemview: saving article"); std::string filename; if (automatic) { if (args->size() > 0) filename = (*args)[0]; } else { filename = v->run_filebrowser(v->get_filename_suggestion(item->title())); } if (filename == "") { v->show_error(_("Aborted saving.")); } else { try { v->get_ctrl()->write_item(item, filename); v->show_error(utils::strprintf(_("Saved article to %s."), filename.c_str())); } catch (...) { v->show_error(utils::strprintf(_("Error: couldn't write article to file %s"), filename.c_str())); } } } break; case OP_OPENINBROWSER: LOG(LOG_INFO, "view::run_itemview: starting browser"); v->set_status(_("Starting browser...")); v->open_in_browser(item->link()); v->set_status(""); break; case OP_BOOKMARK: if (automatic) { qna_responses.clear(); qna_responses.push_back(item->link()); qna_responses.push_back(item->title()); qna_responses.push_back(args->size() > 0 ? (*args)[0] : ""); } else { this->start_bookmark_qna(item->title(), item->link(), ""); } break; case OP_SEARCH: { std::vector qna; if (automatic) { if (args->size() > 0) { qna_responses.clear(); qna_responses.push_back((*args)[0]); finished_qna(OP_INT_START_SEARCH); } } else { qna.push_back(qna_pair(_("Search for: "), "")); this->start_qna(qna, OP_INT_START_SEARCH, &searchhistory); } } break; case OP_PIPE_TO: { std::vector qna; if (automatic) { if (args->size() > 0) { qna_responses.clear(); qna_responses.push_back((*args)[0]); finished_qna(OP_PIPE_TO); } } else { qna.push_back(qna_pair(_("Pipe article to command: "), "")); this->start_qna(qna, OP_PIPE_TO, &cmdlinehistory); } } break; case OP_EDITFLAGS: if (automatic) { qna_responses.clear(); if (args->size() > 0) { qna_responses.push_back((*args)[0]); this->finished_qna(OP_INT_EDITFLAGS_END); } } else { std::vector qna; qna.push_back(qna_pair(_("Flags: "), item->flags())); this->start_qna(qna, OP_INT_EDITFLAGS_END); } break; case OP_SHOWURLS: { std::string urlviewer = v->get_cfg()->get_configvalue("external-url-viewer"); LOG(LOG_DEBUG, "view::run_itemview: showing URLs"); if (urlviewer == "") { if (links.size() > 0) { v->push_urlview(links); } else { v->show_error(_("URL list empty.")); } } else { qna_responses.clear(); qna_responses.push_back(urlviewer); this->finished_qna(OP_PIPE_TO); } } break; case OP_DELETE: LOG(LOG_INFO, "view::run_itemview: deleting current article"); item->set_deleted(true); v->get_ctrl()->mark_deleted(guid, true); /* fall-through! */ case OP_NEXTUNREAD: LOG(LOG_INFO, "view::run_itemview: jumping to next unread article"); if (v->get_next_unread(itemlist.get(), this)) { do_redraw = true; } else { v->pop_current_formaction(); v->show_error(_("No unread items.")); } break; case OP_PREVUNREAD: LOG(LOG_INFO, "view::run_itemview: jumping to previous unread article"); if (v->get_previous_unread(itemlist.get(), this)) { do_redraw = true; } else { v->pop_current_formaction(); v->show_error(_("No unread items.")); } break; case OP_NEXT: LOG(LOG_INFO, "view::run_itemview: jumping to next article"); if (v->get_next(itemlist.get(), this)) { do_redraw = true; } else { v->pop_current_formaction(); v->show_error(_("Already on last item.")); } break; case OP_PREV: LOG(LOG_INFO, "view::run_itemview: jumping to previous article"); if (v->get_previous(itemlist.get(), this)) { do_redraw = true; } else { v->pop_current_formaction(); v->show_error(_("Already on first item.")); } break; case OP_RANDOMUNREAD: LOG(LOG_INFO, "view::run_itemview: jumping to random unread article"); if (v->get_random_unread(itemlist.get(), this)) { do_redraw = true; } else { v->pop_current_formaction(); v->show_error(_("No unread items.")); } break; case OP_TOGGLEITEMREAD: LOG(LOG_INFO, "view::run_itemview: setting unread and quitting"); v->set_status(_("Toggling read flag for article...")); try { item->set_unread(true); v->get_ctrl()->mark_article_read(item->guid(), false); } catch (const dbexception& e) { v->show_error(utils::strprintf(_("Error while marking article as unread: %s"), e.what())); } v->set_status(""); quit = true; break; case OP_QUIT: LOG(LOG_INFO, "view::run_itemview: quitting"); quit = true; break; case OP_HARDQUIT: LOG(LOG_INFO, "view::run_itemview: hard quitting"); hardquit = true; break; case OP_HELP: v->push_help(); break; case OP_1: case OP_2: case OP_3: case OP_4: case OP_5: case OP_6: case OP_7: case OP_8: case OP_9: case OP_0: { unsigned int idx = op - OP_1; LOG(LOG_DEBUG, "itemview::run: OP_1 = %d op = %d idx = %u", OP_1, op, idx); if(idx < links.size()) { v->set_status(_("Starting browser...")); v->open_in_browser(links[idx].first); v->set_status(""); } } break; case OP_GOTO_URL: { std::vector qna; if (automatic) { if (args->size() > 0) { qna_responses.clear(); qna_responses.push_back((*args)[0]); finished_qna(OP_INT_GOTO_URL); } } else { qna.push_back(qna_pair(_("Goto URL #"), "")); this->start_qna(qna, OP_INT_GOTO_URL); } } break; default: break; } if (hardquit) { while (v->formaction_stack_size() > 0) { v->pop_current_formaction(); } } else if (quit) { v->pop_current_formaction(); } } keymap_hint_entry * itemview_formaction::get_keymap_hint() { static keymap_hint_entry hints[] = { { OP_QUIT, _("Quit") }, { OP_SAVE, _("Save") }, { OP_NEXTUNREAD, _("Next Unread") }, { OP_OPENINBROWSER, _("Open in Browser") }, { OP_ENQUEUE, _("Enqueue") }, { OP_HELP, _("Help") }, { OP_NIL, NULL } }; return hints; } void itemview_formaction::set_head(const std::string& s, unsigned int unread, unsigned int total) { fmtstr_formatter fmt; fmt.register_fmt('N', PROGRAM_NAME); fmt.register_fmt('V', PROGRAM_VERSION); fmt.register_fmt('T', s); fmt.register_fmt('u', utils::to_string(unread)); fmt.register_fmt('t', utils::to_string(total)); std::string listwidth = f->get("article:w"); std::istringstream is(listwidth); unsigned int width; is >> width; f->set("head",fmt.do_format(v->get_cfg()->get_configvalue("itemview-title-format"), width)); } void itemview_formaction::render_source(std::vector& lines, std::string desc, unsigned int width) { /* * this function is called instead of htmlrenderer::render() when the * user requests to have the source displayed instead of seeing the * rendered HTML. */ std::string line; do { std::string::size_type pos = desc.find_first_of("\r\n"); line = desc.substr(0,pos); if (pos == std::string::npos) desc.erase(); else desc.erase(0,pos+1); while (line.length() > width) { int i = width; while (i > 0 && line[i] != ' ' && line[i] != '<') --i; if (0 == i) { i = width; } std::string subline = line.substr(0, i); line.erase(0, i); pos = subline.find_first_not_of(" "); subline.erase(0,pos); lines.push_back(subline); } pos = line.find_first_not_of(" "); line.erase(0,pos); lines.push_back(line); } while (desc.length() > 0); } void itemview_formaction::handle_cmdline(const std::string& cmd) { std::vector tokens = utils::tokenize_quoted(cmd); if (!tokens.empty()) { if (tokens[0] == "save" && tokens.size() >= 2) { std::string filename = utils::resolve_tilde(tokens[1]); std::tr1::shared_ptr item = feed->get_item_by_guid(guid); if (filename == "") { v->show_error(_("Aborted saving.")); } else { try { v->get_ctrl()->write_item(item, filename); v->show_error(utils::strprintf(_("Saved article to %s"), filename.c_str())); } catch (...) { v->show_error(utils::strprintf(_("Error: couldn't save article to %s"), filename.c_str())); } } } else { formaction::handle_cmdline(cmd); } } } void itemview_formaction::finished_qna(operation op) { formaction::finished_qna(op); // important! std::tr1::shared_ptr item = feed->get_item_by_guid(guid); switch (op) { case OP_INT_EDITFLAGS_END: item->set_flags(qna_responses[0]); v->get_ctrl()->update_flags(item); v->set_status(_("Flags updated.")); do_redraw = true; break; case OP_INT_START_SEARCH: do_search(); break; case OP_PIPE_TO: { std::string cmd = qna_responses[0]; std::ostringstream ostr; v->get_ctrl()->write_item(feed->get_item_by_guid(guid), ostr); v->push_empty_formaction(); stfl::reset(); FILE * f = popen(cmd.c_str(), "w"); if (f) { std::string data = ostr.str(); fwrite(data.c_str(), data.length(), 1, f); pclose(f); } v->pop_current_formaction(); } break; case OP_INT_GOTO_URL: { unsigned int idx = 0; sscanf(qna_responses[0].c_str(),"%u",&idx); if(idx && idx-1 < links.size()) { v->set_status(_("Starting browser...")); v->open_in_browser(links[idx-1].first); v->set_status(""); } } break; default: break; } } std::vector itemview_formaction::render_html(const std::string& source, std::vector& thelinks, const std::string& url, unsigned int render_width) { std::vector lines; std::string renderer = v->get_cfg()->get_configvalue("html-renderer"); if (renderer == "internal") { htmlrenderer rnd(render_width); rnd.render(source, lines, thelinks, url); } else { char * argv[4]; argv[0] = const_cast("/bin/sh"); argv[1] = const_cast("-c"); argv[2] = const_cast(renderer.c_str()); argv[3] = NULL; LOG(LOG_DEBUG, "itemview_formaction::render_html: source = %s", source.c_str()); LOG(LOG_DEBUG, "itemview_formaction::render_html: html-renderer = %s", argv[2]); std::string output = utils::run_program(argv, source); std::istringstream is(output); std::string line; getline(is, line); while (!is.eof()) { lines.push_back(utils::quote_for_stfl(line)); getline(is, line); } } return lines; } void itemview_formaction::set_regexmanager(regexmanager * r) { rxman = r; std::vector& attrs = r->get_attrs("article"); unsigned int i=0; std::string attrstr; for (std::vector::iterator it=attrs.begin();it!=attrs.end();++it,++i) { attrstr.append(utils::strprintf("@style_%u_normal:%s ", i, it->c_str())); } attrstr.append("@style_b_normal[color_bold]:attr=bold @style_u_normal[color_underline]:attr=underline "); std::string textview = utils::strprintf("{textview[article] style_normal[article]: style_end[styleend]:fg=blue,attr=bold %s .expand:vh offset[articleoffset]:0 richtext:1}", attrstr.c_str()); f->modify("article", "replace", textview); } void itemview_formaction::update_percent() { if (v->get_cfg()->get_configvalue_as_bool("display-article-progress")) { std::istringstream is(f->get("articleoffset")); unsigned int offset = 0; unsigned int percent = 0; is >> offset; if (num_lines > 0) percent = (100 * (offset + 1)) / num_lines; else percent = 0; LOG(LOG_DEBUG, "itemview_formaction::update_percent: offset = %u num_lines = %u percent = %u", offset, num_lines, percent); if (offset == 0 || percent == 0) { f->set("percent", _("Top")); } else if (offset == (num_lines - 1)) { f->set("percent", _("Bottom")); } else { f->set("percent", utils::strprintf("%3u %% ", percent)); } } } std::string itemview_formaction::title() { std::tr1::shared_ptr item = feed->get_item_by_guid(guid); return utils::strprintf(_("Article - %s"), item->title().c_str()); } void itemview_formaction::set_highlightphrase(const std::string& text) { highlight_text(text); } void itemview_formaction::do_search() { std::string searchphrase = qna_responses[0]; if (searchphrase.length() == 0) return; searchhistory.add_line(searchphrase); LOG(LOG_DEBUG, "itemview_formaction::do_search: searchphrase = %s", searchphrase.c_str()); highlight_text(searchphrase); } void itemview_formaction::highlight_text(const std::string& searchphrase) { std::vector params; params.push_back("article"); params.push_back(searchphrase); std::vector colors = utils::tokenize(v->get_cfg()->get_configvalue("search-highlight-colors"), " "); std::copy(colors.begin(), colors.end(), std::back_inserter(params)); try { rxman->handle_action("highlight", params); LOG(LOG_DEBUG, "itemview_formaction::highlight_text: configuration manipulation was successful"); set_regexmanager(rxman); in_search = true; do_redraw = true; } catch (const confighandlerexception& e) { LOG(LOG_ERROR, "itemview_formaction::highlight_text: handle_action failed, error = %s", e.what()); v->show_error(_("Error: invalid regular expression!")); } } } newsbeuter-2.7/src/keymap.cpp000066400000000000000000000411001220711462700163240ustar00rootroot00000000000000#include #include #include #include #include #include #include namespace newsbeuter { struct op_desc { operation op; const char * opstr; const char * default_key; const char * help_text; unsigned short flags; }; /* * This is the list of operations, defining operation, operation name (for keybindings), default key, description, and where it's valid */ static op_desc opdescs[] = { { OP_OPEN, "open", "ENTER", _("Open feed/article"), KM_FEEDLIST | KM_FILEBROWSER | KM_HELP | KM_ARTICLELIST | KM_TAGSELECT | KM_FILTERSELECT | KM_URLVIEW | KM_PODBEUTER | KM_DIALOGS }, { OP_QUIT, "quit", "q", _("Return to previous dialog/Quit"), KM_FEEDLIST | KM_FILEBROWSER | KM_HELP | KM_ARTICLELIST | KM_ARTICLE | KM_TAGSELECT | KM_FILTERSELECT | KM_URLVIEW | KM_PODBEUTER | KM_DIALOGS }, { OP_HARDQUIT, "hard-quit", "Q", _("Quit program, no confirmation"), KM_FEEDLIST | KM_FILEBROWSER | KM_HELP | KM_ARTICLELIST | KM_ARTICLE | KM_TAGSELECT | KM_FILTERSELECT | KM_URLVIEW | KM_PODBEUTER | KM_DIALOGS }, { OP_RELOAD, "reload", "r", _("Reload currently selected feed"), KM_FEEDLIST }, { OP_RELOADALL, "reload-all", "R", _("Reload all feeds"), KM_FEEDLIST }, { OP_MARKFEEDREAD, "mark-feed-read", "A", _("Mark feed read"), KM_FEEDLIST | KM_ARTICLELIST }, { OP_MARKALLFEEDSREAD, "mark-all-feeds-read", "C", _("Mark all feeds read"), KM_FEEDLIST }, { OP_SAVE, "save", "s", _("Save article"), KM_ARTICLELIST | KM_ARTICLE }, { OP_NEXT, "next", "J", _("Go to next article"), KM_FEEDLIST | KM_ARTICLELIST | KM_ARTICLE }, { OP_PREV, "prev", "K", _("Go to previous article"), KM_FEEDLIST | KM_ARTICLELIST | KM_ARTICLE }, { OP_NEXTUNREAD, "next-unread", "n", _("Go to next unread article"), KM_FEEDLIST | KM_ARTICLELIST | KM_ARTICLE }, { OP_PREVUNREAD, "prev-unread", "p", _("Go to previous unread article"), KM_FEEDLIST | KM_ARTICLELIST | KM_ARTICLE }, { OP_RANDOMUNREAD, "random-unread", "^K", _("Go to a random unread article"), KM_FEEDLIST | KM_ARTICLELIST | KM_ARTICLE }, { OP_OPENBROWSER_AND_MARK, "open-in-browser-and-mark-read", "O", _("Open article in browser and mark read"), KM_ARTICLELIST }, { OP_OPENINBROWSER, "open-in-browser", "o", _("Open article in browser"), KM_FEEDLIST | KM_ARTICLELIST | KM_ARTICLE }, { OP_HELP, "help", "?", _("Open help dialog"), KM_FEEDLIST | KM_ARTICLELIST | KM_ARTICLE | KM_PODBEUTER }, { OP_TOGGLESOURCEVIEW, "toggle-source-view", "^U", _("Toggle source view"), KM_ARTICLE }, { OP_TOGGLEITEMREAD, "toggle-article-read", "N", _("Toggle read status for article"), KM_ARTICLELIST | KM_ARTICLE }, { OP_TOGGLESHOWREAD, "toggle-show-read-feeds", "l", _("Toggle show read feeds/articles"), KM_FEEDLIST | KM_ARTICLELIST }, { OP_SHOWURLS, "show-urls", "u", _("Show URLs in current article"), KM_ARTICLE | KM_ARTICLELIST }, { OP_CLEARTAG, "clear-tag", "^T", _("Clear current tag"), KM_FEEDLIST }, { OP_SETTAG, "set-tag", "t", _("Select tag"), KM_FEEDLIST }, { OP_SETTAG, "select-tag", "t", _("Select tag"), KM_FEEDLIST }, { OP_SEARCH, "open-search", "/", _("Open search dialog"), KM_FEEDLIST | KM_HELP | KM_ARTICLELIST | KM_ARTICLE }, { OP_GOTO_URL, "goto-url", "#", _("Goto URL #"), KM_ARTICLE }, { OP_ENQUEUE, "enqueue", "e", _("Add download to queue"), KM_ARTICLE }, { OP_RELOADURLS, "reload-urls", "^R", _("Reload the list of URLs from the configuration"), KM_FEEDLIST }, { OP_PB_DOWNLOAD, "pb-download", "d", _("Download file"), KM_PODBEUTER }, { OP_PB_CANCEL, "pb-cancel", "c", _("Cancel download"), KM_PODBEUTER }, { OP_PB_DELETE, "pb-delete", "D", _("Mark download as deleted"), KM_PODBEUTER }, { OP_PB_PURGE, "pb-purge", "P", _("Purge finished and deleted downloads from queue"), KM_PODBEUTER }, { OP_PB_TOGGLE_DLALL, "pb-toggle-download-all", "a", _("Toggle automatic download on/off"), KM_PODBEUTER }, { OP_PB_PLAY, "pb-play", "p", _("Start player with currently selected download"), KM_PODBEUTER }, { OP_PB_MARK_FINISHED, "pb-mark-as-finished", "m", _("Mark file as finished (not played)"), KM_PODBEUTER }, { OP_PB_MOREDL, "pb-increase-max-dls", "+", _("Increase the number of concurrent downloads"), KM_PODBEUTER }, { OP_PB_LESSDL, "pb-decreate-max-dls", "-", _("Decrease the number of concurrent downloads"), KM_PODBEUTER }, { OP_REDRAW, "redraw", "^L", _("Redraw screen"), KM_SYSKEYS }, { OP_CMDLINE, "cmdline", ":", _("Open the commandline"), KM_NEWSBEUTER }, { OP_SETFILTER, "set-filter", "F", _("Set a filter"), KM_FEEDLIST | KM_ARTICLELIST }, { OP_SELECTFILTER, "select-filter", "f", _("Select a predefined filter"), KM_FEEDLIST | KM_ARTICLELIST }, { OP_CLEARFILTER, "clear-filter", "^F", _("Clear currently set filter"), KM_FEEDLIST | KM_HELP | KM_ARTICLELIST }, { OP_BOOKMARK, "bookmark", "^B", _("Bookmark current link/article"), KM_ARTICLELIST | KM_ARTICLE | KM_URLVIEW }, { OP_EDITFLAGS, "edit-flags", "^E", _("Edit flags"), KM_ARTICLELIST | KM_ARTICLE }, { OP_NEXTFEED, "next-feed", "j", _("Go to next feed"), KM_ARTICLELIST }, { OP_PREVFEED, "prev-feed", "k", _("Go to previous feed"), KM_ARTICLELIST }, { OP_NEXTUNREADFEED, "next-unread-feed", "^N", _("Go to next unread feed"), KM_ARTICLELIST }, { OP_PREVUNREADFEED, "prev-unread-feed", "^P", _("Go to previous unread feed"), KM_ARTICLELIST }, { OP_MACROPREFIX, "macro-prefix", ",", _("Call a macro"), KM_NEWSBEUTER }, { OP_DELETE, "delete-article", "D", _("Delete article"), KM_ARTICLELIST | KM_ARTICLE }, { OP_PURGE_DELETED, "purge-deleted", "$", _("Purge deleted articles"), KM_ARTICLELIST }, { OP_EDIT_URLS, "edit-urls", "E", _("Edit subscribed URLs"), KM_FEEDLIST | KM_ARTICLELIST }, { OP_CLOSEDIALOG, "close-dialog", "^X", _("Close currently selected dialog"), KM_DIALOGS }, { OP_VIEWDIALOGS, "view-dialogs", "v", _("View list of open dialogs"), KM_NEWSBEUTER }, { OP_NEXTDIALOG, "next-dialog", "^V", _("Go to next dialog"), KM_NEWSBEUTER }, { OP_PREVDIALOG, "prev-dialog", "^G", _("Go to previous dialog"), KM_NEWSBEUTER }, { OP_PIPE_TO, "pipe-to", "|", _("Pipe article to command"), KM_ARTICLE | KM_ARTICLELIST }, { OP_SORT, "sort", "g", _("Sort current list"), KM_FEEDLIST | KM_ARTICLELIST }, { OP_REVSORT, "rev-sort", "G", _("Sort current list (reverse)"), KM_FEEDLIST | KM_ARTICLELIST }, { OP_0, "zero", "0", _("Open URL 10"), KM_URLVIEW | KM_ARTICLE }, { OP_1, "one", "1", _("Open URL 1"), KM_URLVIEW | KM_ARTICLE}, { OP_2, "two", "2", _("Open URL 2"), KM_URLVIEW | KM_ARTICLE}, { OP_3, "three","3", _("Open URL 3"), KM_URLVIEW | KM_ARTICLE}, { OP_4, "four", "4", _("Open URL 4"), KM_URLVIEW | KM_ARTICLE}, { OP_5, "five", "5", _("Open URL 5"), KM_URLVIEW | KM_ARTICLE}, { OP_6, "six", "6", _("Open URL 6"), KM_URLVIEW | KM_ARTICLE}, { OP_7, "seven","7", _("Open URL 7"), KM_URLVIEW | KM_ARTICLE}, { OP_8, "eight","8", _("Open URL 8"), KM_URLVIEW | KM_ARTICLE}, { OP_9, "nine", "9", _("Open URL 9"), KM_URLVIEW | KM_ARTICLE}, { OP_SK_UP, "up", "UP", _("Move to the previous entry"), KM_SYSKEYS }, { OP_SK_DOWN, "down", "DOWN", _("Move to the next entry"), KM_SYSKEYS }, { OP_SK_PGUP, "pageup", "PAGEUP", _("Move to the previous page"), KM_SYSKEYS }, { OP_SK_PGDOWN, "pagedown", "PAGEDOWN", _("Move to the next page"), KM_SYSKEYS }, { OP_SK_HOME, "home", "HOME", _("Move to the start of page/list"), KM_SYSKEYS }, { OP_SK_END, "end", "END", _("Move to the end of page/list"), KM_SYSKEYS }, { OP_INT_END_QUESTION, "XXXNOKEY-end-question", "end-question", NULL, KM_INTERNAL }, { OP_INT_CANCEL_QNA, "XXXNOKEY-cancel-qna", "cancel-qna", NULL, KM_INTERNAL }, { OP_INT_QNA_NEXTHIST, "XXXNOKEY-qna-next-history", "qna-next-history", NULL, KM_INTERNAL }, { OP_INT_QNA_PREVHIST, "XXXNOKEY-qna-prev-history", "qna-prev-history", NULL, KM_INTERNAL }, { OP_INT_RESIZE, "RESIZE", "internal-resize", NULL, KM_INTERNAL }, { OP_INT_SET, "set", "internal-set", NULL, KM_INTERNAL }, { OP_INT_GOTO_URL, "gotourl", "internal-goto-url", NULL, KM_INTERNAL }, { OP_NIL, NULL, NULL, NULL, 0 } }; // "all" must be first, the following positions must be the same as the KM_* flag definitions (get_flag_from_context() relies on this). static const char * contexts[] = { "all", "feedlist", "filebrowser", "help", "articlelist", "article", "tagselection", "filterselection", "urlview", "podbeuter", "dialogs", NULL }; keymap::keymap(unsigned flags) { /* * At startup, initialize the keymap with the default settings from the list above. */ LOG(LOG_DEBUG, "keymap::keymap: flags = %x", flags); for (unsigned int j=1;contexts[j]!=NULL;j++) { std::string ctx(contexts[j]); for (int i=0;opdescs[i].op != OP_NIL;++i) { if (opdescs[i].flags & (flags | KM_INTERNAL | KM_SYSKEYS)) { keymap_[ctx][opdescs[i].default_key] = opdescs[i].op; } } } } void keymap::get_keymap_descriptions(std::vector& descs, unsigned short flags) { /* * Here we return the keymap descriptions for the specified application (handed to us via flags) * This is used for the help screen. */ for (unsigned int i=1;contexts[i]!=NULL;i++) { std::string ctx(contexts[i]); if (flags & KM_PODBEUTER && ctx != "podbeuter") { continue; } else if (flags & KM_NEWSBEUTER && ctx == "podbeuter") { continue; } for (unsigned int j=0;opdescs[j].op != OP_NIL;++j) { bool already_added = false; for (std::map::iterator it=keymap_[ctx].begin();it!=keymap_[ctx].end();++it) { operation op = it->second; if (op != OP_NIL) { if (opdescs[j].op == op && opdescs[j].flags & flags) { keymap_desc desc; desc.key = it->first; desc.ctx = ctx; if (!already_added) { desc.cmd = opdescs[j].opstr; if (opdescs[j].help_text) desc.desc = gettext(opdescs[j].help_text); already_added = true; } desc.flags = opdescs[j].flags; descs.push_back(desc); } } } if (!already_added) { if (opdescs[j].flags & flags) { LOG(LOG_DEBUG, "keymap::get_keymap_descriptions: found unbound function: %s ctx = %s", opdescs[j].opstr, ctx.c_str()); keymap_desc desc; desc.ctx = ctx; desc.cmd = opdescs[j].opstr; if (opdescs[j].help_text) desc.desc = gettext(opdescs[j].help_text); desc.flags = opdescs[j].flags; descs.push_back(desc); } } } } } keymap::~keymap() { } void keymap::set_key(operation op, const std::string& key, const std::string& context) { LOG(LOG_DEBUG,"keymap::set_key(%d,%s) called", op, key.c_str()); if (context == "all") { for (unsigned int i=0;contexts[i]!=NULL;i++) { keymap_[contexts[i]][key] = op; } } else { keymap_[context][key] = op; } } void keymap::unset_key(const std::string& key, const std::string& context) { LOG(LOG_DEBUG,"keymap::unset_key(%s) called", key.c_str()); if (context == "all") { for (unsigned int i=0;contexts[i]!=NULL;i++) { keymap_[contexts[i]][key] = OP_NIL; } } else { keymap_[context][key] = OP_NIL; } } operation keymap::get_opcode(const std::string& opstr) { for (int i=0;opdescs[i].opstr;++i) { if (opstr == opdescs[i].opstr) { return opdescs[i].op; } } return OP_NIL; } char keymap::get_key(const std::string& keycode) { if (keycode == "ENTER") { return '\n'; } else if (keycode == "ESC") { return 27; } else if (keycode.length() == 2 && keycode[0] == '^') { char chr = keycode[1]; return chr - '@'; } else if (keycode.length() == 1) { // TODO: implement more keys return keycode[0]; } return 0; } operation keymap::get_operation(const std::string& keycode, const std::string& context) { std::string key; LOG(LOG_DEBUG, "keymap::get_operation: keycode = %s context = %s", keycode.c_str(), context.c_str()); if (keycode.length() > 0) { key = keycode; } else { key = "NIL"; } return keymap_[context][key]; } void keymap::dump_config(std::vector& config_output) { for (unsigned int i=1;contexts[i]!=NULL;i++) { // TODO: optimize std::map& x = keymap_[contexts[i]]; for (std::map::iterator it = x.begin();it!=x.end();++it) { if (it->second < OP_INT_MIN) { std::string configline = "bind-key "; configline.append(it->first); configline.append(" "); configline.append(getopname(it->second)); configline.append(" "); configline.append(contexts[i]); config_output.push_back(configline); } } } for (std::map >::iterator it=macros_.begin();it!=macros_.end();++it) { std::string configline = "macro "; configline.append(it->first); configline.append(" "); unsigned int i=0; for (std::vector::iterator jt=it->second.begin();jt!=it->second.end();++jt,i++) { configline.append(getopname(jt->op)); for (std::vector::iterator kt=jt->args.begin();kt!=jt->args.end();++kt) { configline.append(" "); configline.append(utils::quote(*kt)); } if (i < (it->second.size()-1)) configline.append(" ; "); } config_output.push_back(configline); } } std::string keymap::getopname(operation op) { for (unsigned int i=0;opdescs[i].op != OP_NIL;i++) { if (opdescs[i].op == op) return opdescs[i].opstr; } return ""; } void keymap::handle_action(const std::string& action, const std::vector& params) { /* * The keymap acts as config_action_handler so that all the key-related configuration is immediately * handed to it. */ LOG(LOG_DEBUG,"keymap::handle_action(%s, ...) called",action.c_str()); if (action == "bind-key") { if (params.size() < 2) throw confighandlerexception(AHS_TOO_FEW_PARAMS); std::string context = "all"; if (params.size() >= 3) context = params[2]; if (!is_valid_context(context)) throw confighandlerexception(utils::strprintf(_("`%s' is not a valid context"), context.c_str())); operation op = get_opcode(params[1]); if (op > OP_SK_MIN && op < OP_SK_MAX) unset_key(getkey(op, context), context); set_key(op, params[0], context); } else if (action == "unbind-key") { if (params.size() < 1) throw confighandlerexception(AHS_TOO_FEW_PARAMS); std::string context = "all"; if (params.size() >= 2) context = params[1]; unset_key(params[0], context); } else if (action == "macro") { if (params.size() < 1) throw confighandlerexception(AHS_TOO_FEW_PARAMS); std::vector::const_iterator it = params.begin(); std::string macrokey = *it; std::vector cmds; macrocmd tmpcmd; tmpcmd.op = OP_NIL; bool first = true; ++it; while (it != params.end()) { if (first && *it != ";") { tmpcmd.op = get_opcode(*it); LOG(LOG_DEBUG, "keymap::handle_action: new operation `%s' (op = %u)", it->c_str(), tmpcmd.op); if (tmpcmd.op == OP_NIL) throw confighandlerexception(utils::strprintf(_("`%s' is not a valid key command"), it->c_str())); first = false; } else { if (*it == ";") { if (tmpcmd.op != OP_NIL) cmds.push_back(tmpcmd); tmpcmd.op = OP_NIL; tmpcmd.args.clear(); first = true; } else { LOG(LOG_DEBUG, "keymap::handle_action: new parameter `%s' (op = %u)", it->c_str()); tmpcmd.args.push_back(*it); } } ++it; } if (tmpcmd.op != OP_NIL) cmds.push_back(tmpcmd); macros_[macrokey] = cmds; } else throw confighandlerexception(AHS_INVALID_PARAMS); } std::string keymap::getkey(operation op, const std::string& context) { if (context == "all") { for (unsigned int i=0;contexts[i]!=NULL;i++) { std::string ctx(contexts[i]); for (std::map::iterator it=keymap_[ctx].begin(); it!=keymap_[ctx].end(); ++it) { if (it->second == op) return it->first; } } } else { for (std::map::iterator it=keymap_[context].begin(); it!=keymap_[context].end(); ++it) { if (it->second == op) return it->first; } } return ""; } std::vector keymap::get_macro(const std::string& key) { for (std::map >::iterator it=macros_.begin(); it!=macros_.end(); ++it) { if (it->first == key) { return it->second; } } std::vector dummyvector; return dummyvector; } bool keymap::is_valid_context(const std::string& context) { for (unsigned int i=0;contexts[i]!=NULL;i++) { if (context == contexts[i]) return true; } return false; } unsigned short keymap::get_flag_from_context(const std::string& context) { for (unsigned int i=1;contexts[i]!=NULL;i++) { if (context == contexts[i]) return (1<<(i-1)) | KM_SYSKEYS; } return 0; // shouldn't happen } } newsbeuter-2.7/src/listformatter.cpp000066400000000000000000000034651220711462700177510ustar00rootroot00000000000000#include #include #include namespace newsbeuter { listformatter::listformatter() : refresh_cache(true) { } listformatter::~listformatter() { } void listformatter::add_line(const std::string& text, unsigned int id, unsigned int width) { if (width > 0 && text.length() > 0) { std::wstring mytext = utils::clean_nonprintable_characters(utils::str2wstr(text)); while (mytext.length() > 0) { size_t size = mytext.length(); size_t w = utils::wcswidth_stfl(mytext, size); if (w > width) { while (size && (w = utils::wcswidth_stfl(mytext, size)) > width) { size--; } } lines.push_back(line_id_pair(utils::wstr2str(mytext.substr(0, size)), id)); mytext.erase(0, size); } } else { lines.push_back(line_id_pair(utils::wstr2str(utils::clean_nonprintable_characters(utils::str2wstr(text))), id)); } LOG(LOG_DEBUG, "listformatter::add_line: `%s'", text.c_str()); refresh_cache = true; } void listformatter::add_lines(const std::vector& thelines, unsigned int width) { for (std::vector::const_iterator it=thelines.begin();it!=thelines.end();++it) { add_line(utils::replace_all(*it, "\t", " "), UINT_MAX, width); } } std::string listformatter::format_list(regexmanager * rxman, const std::string& location) { format_cache = "{list"; for (std::vector::iterator it=lines.begin();it!=lines.end();++it) { std::string str = it->first; if (rxman) rxman->quote_and_highlight(str, location); if (it->second == UINT_MAX) { format_cache.append(utils::strprintf("{listitem text:%s}", stfl::quote(str).c_str())); } else { format_cache.append(utils::strprintf("{listitem[%u] text:%s}", it->second, stfl::quote(str).c_str())); } } format_cache.append(1, '}'); refresh_cache = false; return format_cache; } } newsbeuter-2.7/src/logger.cpp000066400000000000000000000046561220711462700163340ustar00rootroot00000000000000#include #include #include #include namespace newsbeuter { mutex logger::instanceMutex; logger::logger() : curlevel(LOG_NONE) { } void logger::set_logfile(const char * logfile) { /* * This sets the filename of the debug logfile */ scope_mutex lock(&logMutex); if (f.is_open()) f.close(); f.open(logfile, std::fstream::out); if (!f.is_open()) { throw exception(errno); // the question is whether f.open() sets errno... } } void logger::set_errorlogfile(const char * logfile) { /* * This sets the filename of the error logfile, i.e. the one that can be configured to be generated. */ scope_mutex lock(&logMutex); if (ef.is_open()) ef.close(); ef.open(logfile, std::fstream::out); if (!ef.is_open()) { throw exception(errno); } if (LOG_NONE == curlevel) { curlevel = LOG_USERERROR; } } void logger::set_loglevel(loglevel level) { scope_mutex lock(&logMutex); curlevel = level; if (curlevel == LOG_NONE) f.close(); } const char * loglevel_str[] = { "NONE", "USERERROR", "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG" }; void logger::log(loglevel level, const char * format, ...) { /* * This function checks the loglevel, creates the error message, and then * writes it to the debug logfile and to the error logfile (if applicable). */ scope_mutex lock(&logMutex); if (level <= curlevel && curlevel > LOG_NONE && (f.is_open() || ef.is_open())) { char * buf, * logmsgbuf; char date[128]; time_t t = time(NULL); struct tm * stm = localtime(&t); strftime(date,sizeof(date),"%Y-%m-%d %H:%M:%S",stm); if (curlevel > LOG_DEBUG) curlevel = LOG_DEBUG; va_list ap; va_start(ap, format); unsigned int len = vsnprintf(NULL,0,format,ap); va_end(ap); va_start(ap, format); logmsgbuf = new char[len + 1]; vsnprintf(logmsgbuf, len + 1, format, ap); va_end(ap); len = snprintf(NULL, 0, "[%s] %s: %s",date, loglevel_str[level], logmsgbuf); buf = new char[len + 1]; snprintf(buf,len + 1,"[%s] %s: %s",date, loglevel_str[level], logmsgbuf); if (f.is_open()) { f << buf << std::endl; } if (LOG_USERERROR == level && ef.is_open()) { snprintf(buf, len + 1, "[%s] %s", date, logmsgbuf); ef << buf << std::endl; ef.flush(); } delete[] buf; delete[] logmsgbuf; } } logger &logger::getInstance() { /* * This is the global logger that everyone uses */ scope_mutex lock(&instanceMutex); static logger theLogger; return theLogger; } } newsbeuter-2.7/src/markreadthread.cpp000066400000000000000000000012511220711462700200170ustar00rootroot00000000000000#include #include namespace newsbeuter { markreadthread::markreadthread( ttrss_api* r_api, const std::string& guid, bool read ) : _r_api( r_api ), _guid( guid ), _read( read ) { } markreadthread::~markreadthread() { } void markreadthread::run() { /* * the markreadthread class handles marking a thread as read in a way that * doesn't halt the presentation of the content. this is for remote sources, * like TinyTinyRSS. */ LOG(LOG_DEBUG, "markreadthread::run: inside markreadthread, marking thread as read..."); // Call the ttrss_api's update_article function as a thread. _r_api->update_article( _guid, 2, _read ? 0 : 1 ); } } newsbeuter-2.7/src/matcher.cpp000066400000000000000000000127241220711462700164730ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include namespace newsbeuter { matchable::matchable() { } matchable::~matchable() { } matcher::matcher() { } matcher::matcher(const std::string& expr) : exp(expr) { parse(expr); } const std::string& matcher::get_expression() { return exp; } bool matcher::parse(const std::string& expr) { struct timeval tv1, tv2; gettimeofday(&tv1, NULL); errmsg = ""; bool b = p.parse_string(expr); if (!b) { errmsg = utils::wstr2str(p.get_error()); } gettimeofday(&tv2, NULL); unsigned long diff = (((tv2.tv_sec - tv1.tv_sec) * 1000000) + tv2.tv_usec) - tv1.tv_usec; LOG(LOG_DEBUG, "matcher::parse: parsing `%s' took %lu µs (success = %d)", expr.c_str(), diff, b ? 1 : 0); return b; } bool matcher::matches(matchable* item) { /* * with this method, every class that is derived from matchable can be * matched against a filter expression that was previously passed to the * class with the parse() method. * * This makes it easy to use the matcher virtually everywhere, since C++ * allows multiple inheritance (i.e. deriving from matchable can even be * used in class hierarchies), and deriving from matchable means that you * only have to implement two methods has_attribute() and get_attribute(). * * The whole matching code is speed-critical, as the matching happens on a * lot of different occassions, and slow matching can be easily measured * (and felt by the user) on slow computers with a lot of items to match. */ bool retval = false; if (item) { scope_measure m1("matcher::matches"); retval = matches_r(p.get_root(), item); } return retval; } bool matcher::matchop_lt(expression * e, matchable * item) { if (!item->has_attribute(e->name)) throw matcherexception(matcherexception::ATTRIB_UNAVAIL, e->name); std::istringstream islit(e->literal); std::istringstream isatt(item->get_attribute(e->name)); int ilit, iatt; islit >> ilit; isatt >> iatt; return iatt < ilit; } bool matcher::matchop_between(expression * e, matchable * item) { if (!item->has_attribute(e->name)) throw matcherexception(matcherexception::ATTRIB_UNAVAIL, e->name); std::vector lit = utils::tokenize(e->literal, ":"); std::istringstream isatt(item->get_attribute(e->name)); int att; isatt >> att; if (lit.size() < 2) return false; std::istringstream is1(lit[0]), is2(lit[1]); int i1, i2; is1 >> i1; is2 >> i2; if (i1 > i2) { int tmp = i1; i1 = i2; i2 = tmp; } return (att >= i1 && att <= i2); } bool matcher::matchop_gt(expression * e, matchable * item) { if (!item->has_attribute(e->name)) throw matcherexception(matcherexception::ATTRIB_UNAVAIL, e->name); std::istringstream islit(e->literal); std::istringstream isatt(item->get_attribute(e->name)); int ilit, iatt; islit >> ilit; isatt >> iatt; return iatt > ilit; } bool matcher::matchop_rxeq(expression * e, matchable * item) { if (!item->has_attribute(e->name)) throw matcherexception(matcherexception::ATTRIB_UNAVAIL, e->name); if (!e->regex) { e->regex = new regex_t; int err; if ((err = regcomp(e->regex, e->literal.c_str(), REG_EXTENDED | REG_ICASE | REG_NOSUB)) != 0) { char buf[1024]; regerror(err, e->regex, buf, sizeof(buf)); throw matcherexception(matcherexception::INVALID_REGEX, e->literal, buf); } } if (regexec(e->regex, item->get_attribute(e->name).c_str(), 0, NULL, 0)==0) return true; return false; } bool matcher::matchop_cont(expression * e, matchable * item) { if (!item->has_attribute(e->name)) throw matcherexception(matcherexception::ATTRIB_UNAVAIL, e->name); std::vector elements = utils::tokenize(item->get_attribute(e->name), " "); std::string literal = e->literal; for (std::vector::iterator it=elements.begin();it!=elements.end();++it) { if (literal == *it) { return true; } } return false; } bool matcher::matchop_eq(expression * e, matchable * item) { if (!item->has_attribute(e->name)) { LOG(LOG_WARN, "matcher::matches_r: attribute %s not available", e->name.c_str()); throw matcherexception(matcherexception::ATTRIB_UNAVAIL, e->name); } return (item->get_attribute(e->name)==e->literal); } bool matcher::matches_r(expression * e, matchable * item) { if (e) { switch (e->op) { /* the operator "and" and "or" simply connect two different subexpressions */ case LOGOP_AND: return matches_r(e->l, item) && matches_r(e->r, item); // short-circuit evaulation in C -> short circuit evaluation in the filter language case LOGOP_OR: return matches_r(e->l, item) || matches_r(e->r, item); // same here /* while the other operator connect an attribute with a value */ case MATCHOP_EQ: return matchop_eq(e, item); case MATCHOP_NE: return !matchop_eq(e, item); case MATCHOP_LT: return matchop_lt(e, item); case MATCHOP_BETWEEN: return matchop_between(e, item); case MATCHOP_GT: return matchop_gt(e, item); case MATCHOP_LE: return !matchop_gt(e, item); case MATCHOP_GE: return !matchop_lt(e, item); case MATCHOP_RXEQ: return matchop_rxeq(e, item); case MATCHOP_RXNE: return !matchop_rxeq(e, item); case MATCHOP_CONTAINS: return matchop_cont(e, item); case MATCHOP_CONTAINSNOT: return !matchop_cont(e, item); } return false; } else { return true; // shouldn't happen } } const std::string& matcher::get_parse_error() { return errmsg; } } newsbeuter-2.7/src/mutex.cpp000066400000000000000000000014071220711462700162060ustar00rootroot00000000000000#include #include #include #include namespace newsbeuter { mutex::mutex() { pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); pthread_mutex_init(&mtx, &attr); } mutex::~mutex() { pthread_mutex_destroy(&mtx); pthread_mutexattr_destroy(&attr); } void mutex::lock() { pthread_mutex_lock(&mtx); } void mutex::unlock() { pthread_mutex_unlock(&mtx); } bool mutex::trylock() { int rc = pthread_mutex_trylock(&mtx); if (rc != 0) { if (EBUSY == rc) { return false; } else { throw exception(rc); } } else { return true; } } scope_mutex::scope_mutex(mutex * m) : mtx(m) { if (mtx) { mtx->lock(); } } scope_mutex::~scope_mutex() { if (mtx) { mtx->unlock(); } } } newsbeuter-2.7/src/pb_controller.cpp000066400000000000000000000217671220711462700177230ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace newsbeuter; static std::string lock_file = "pb-lock.pid"; static void ctrl_c_action(int sig) { LOG(LOG_DEBUG,"caugh signal %d",sig); stfl::reset(); utils::remove_fs_lock(lock_file); ::exit(EXIT_FAILURE); } namespace podbeuter { #define LOCK_SUFFIX ".lock" /** * \brief Try to setup XDG style dirs. * * returns false, if that fails */ bool pb_controller::setup_dirs_xdg(const char *env_home) { const char *env_xdg_config; const char *env_xdg_data; std::string xdg_config_dir; std::string xdg_data_dir; env_xdg_config = ::getenv("XDG_CONFIG_HOME"); if (env_xdg_config) { xdg_config_dir = env_xdg_config; } else { xdg_config_dir = env_home; xdg_config_dir.append(NEWSBEUTER_PATH_SEP); xdg_config_dir.append(".config"); } env_xdg_data = ::getenv("XDG_DATA_HOME"); if (env_xdg_data) { xdg_data_dir = env_xdg_data; } else { xdg_data_dir = env_home; xdg_data_dir.append(NEWSBEUTER_PATH_SEP); xdg_data_dir.append(".local"); xdg_data_dir.append(NEWSBEUTER_PATH_SEP); xdg_data_dir.append("share"); } xdg_config_dir.append(NEWSBEUTER_PATH_SEP); xdg_config_dir.append(NEWSBEUTER_SUBDIR_XDG); xdg_data_dir.append(NEWSBEUTER_PATH_SEP); xdg_data_dir.append(NEWSBEUTER_SUBDIR_XDG); if (access(xdg_config_dir.c_str(), R_OK | X_OK) != 0) { std::cout << utils::strprintf(_("XDG: configuration directory '%s' not accessible, using '%s' instead."), xdg_config_dir.c_str(), config_dir.c_str()) << std::endl; return false; } if (access(xdg_data_dir.c_str(), R_OK | X_OK | W_OK) != 0) { std::cout << utils::strprintf(_("XDG: data directory '%s' not accessible, using '%s' instead."), xdg_data_dir.c_str(), config_dir.c_str()) << std::endl; return false; } config_dir = xdg_config_dir; /* in config */ url_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + url_file; config_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + config_file; /* in data */ cache_file = xdg_data_dir + std::string(NEWSBEUTER_PATH_SEP) + cache_file; lock_file = cache_file + LOCK_SUFFIX; queue_file = xdg_data_dir + std::string(NEWSBEUTER_PATH_SEP) + queue_file; searchfile = utils::strprintf("%s%shistory.search", xdg_data_dir.c_str(), NEWSBEUTER_PATH_SEP); cmdlinefile = utils::strprintf("%s%shistory.cmdline", xdg_data_dir.c_str(), NEWSBEUTER_PATH_SEP); return true; } pb_controller::pb_controller() : v(0), config_file("config"), queue_file("queue"), cfg(0), view_update_(true), max_dls(1), ql(0) { char * cfgdir; if (!(cfgdir = ::getenv("HOME"))) { struct passwd * spw = ::getpwuid(::getuid()); if (spw) { cfgdir = spw->pw_dir; } else { std::cout << _("Fatal error: couldn't determine home directory!") << std::endl; std::cout << utils::strprintf(_("Please set the HOME environment variable or add a valid user for UID %u!"), ::getuid()) << std::endl; ::exit(EXIT_FAILURE); } } config_dir = cfgdir; if (setup_dirs_xdg(cfgdir)) return; config_dir.append(NEWSBEUTER_PATH_SEP); config_dir.append(NEWSBEUTER_CONFIG_SUBDIR); ::mkdir(config_dir.c_str(),0700); // create configuration directory if it doesn't exist config_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + config_file; queue_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + queue_file; lock_file = config_dir + std::string(NEWSBEUTER_PATH_SEP) + lock_file; } pb_controller::~pb_controller() { delete cfg; } void pb_controller::run(int argc, char * argv[]) { int c; bool automatic_dl = false; ::signal(SIGINT, ctrl_c_action); do { if ((c = ::getopt(argc, argv, "C:q:d:l:ha")) < 0) continue; switch (c) { case ':': case '?': usage(argv[0]); break; case 'C': config_file = optarg; break; case 'q': queue_file = optarg; break; case 'a': automatic_dl = true; break; case 'd': // this is an undocumented debug commandline option! logger::getInstance().set_logfile(optarg); break; case 'l': // this is an undocumented debug commandline option! { loglevel level = static_cast(atoi(optarg)); if (level > LOG_NONE && level <= LOG_DEBUG) logger::getInstance().set_loglevel(level); } break; case 'h': usage(argv[0]); break; default: std::cout << utils::strprintf(_("%s: unknown option - %c"), argv[0], static_cast(c)) << std::endl; usage(argv[0]); break; } } while (c != -1); std::cout << utils::strprintf(_("Starting %s %s..."), "podbeuter", PROGRAM_VERSION) << std::endl; pid_t pid; if (!utils::try_fs_lock(lock_file, pid)) { std::cout << utils::strprintf(_("Error: an instance of %s is already running (PID: %u)"), "podbeuter", pid) << std::endl; return; } std::cout << _("Loading configuration..."); std::cout.flush(); configparser cfgparser; cfg = new configcontainer(); cfg->register_commands(cfgparser); colormanager * colorman = new colormanager(); colorman->register_commands(cfgparser); keymap keys(KM_PODBEUTER); cfgparser.register_handler("bind-key", &keys); cfgparser.register_handler("unbind-key", &keys); null_config_action_handler null_cah; cfgparser.register_handler("macro", &null_cah); cfgparser.register_handler("ignore-article", &null_cah); cfgparser.register_handler("always-download", &null_cah); cfgparser.register_handler("define-filter", &null_cah); cfgparser.register_handler("highlight", &null_cah); cfgparser.register_handler("highlight-article", &null_cah); cfgparser.register_handler("reset-unread-on-update", &null_cah); try { cfgparser.parse("/etc/newsbeuter/config"); cfgparser.parse(config_file); } catch (const configexception& ex) { std::cout << ex.what() << std::endl; delete colorman; return; } if (colorman->colors_loaded()) colorman->set_pb_colors(v); delete colorman; max_dls = cfg->get_configvalue_as_int("max-downloads"); std::cout << _("done.") << std::endl; ql = new queueloader(queue_file, this); ql->reload(downloads_); v->set_keymap(&keys); v->run(automatic_dl); stfl::reset(); std::cout << _("Cleaning up queue..."); std::cout.flush(); ql->reload(downloads_); delete ql; std::cout << _("done.") << std::endl; utils::remove_fs_lock(lock_file); } void pb_controller::usage(const char * argv0) { std::cout << utils::strprintf(_("%s %s\nusage %s [-C ] [-q ] [-h]\n" "-C read configuration from \n" "-q use as queue file\n" "-a start download on startup\n" "-h this help\n"), "podbeuter", PROGRAM_VERSION, argv0); ::exit(EXIT_FAILURE); } std::string pb_controller::get_dlpath() { return cfg->get_configvalue("download-path"); } unsigned int pb_controller::downloads_in_progress() { unsigned int count = 0; if (downloads_.size() > 0) { for (std::vector::iterator it=downloads_.begin();it!=downloads_.end();++it) { if (it->status() == DL_DOWNLOADING) ++count; } } return count; } unsigned int pb_controller::get_maxdownloads() { return max_dls; } void pb_controller::reload_queue(bool remove_unplayed) { if (ql) { ql->reload(downloads_, remove_unplayed); } } double pb_controller::get_total_kbps() { double result = 0.0; if (downloads_.size() > 0) { for (std::vector::iterator it=downloads_.begin();it!=downloads_.end();++it) { if (it->status() == DL_DOWNLOADING) { result += it->kbps(); } } } return result; } void pb_controller::start_downloads() { int dl2start = get_maxdownloads() - downloads_in_progress(); for (std::vector::iterator it=downloads_.begin();dl2start > 0 && it!=downloads_.end();++it) { if (it->status() == DL_QUEUED) { poddlthread * thread = new poddlthread(&(*it), cfg); thread->start(); --dl2start; } } } void pb_controller::increase_parallel_downloads() { ++max_dls; } void pb_controller::decrease_parallel_downloads() { if (max_dls > 1) --max_dls; } void pb_controller::play_file(const std::string& file) { std::string cmdline; std::string player = cfg->get_configvalue("player"); if (player == "") return; cmdline.append(player); cmdline.append(" \""); cmdline.append(utils::replace_all(file,"\"", "\\\"")); cmdline.append("\""); stfl::reset(); LOG(LOG_DEBUG, "pb_controller::play_file: running `%s'", cmdline.c_str()); ::system(cmdline.c_str()); } } // namespace newsbeuter-2.7/src/pb_view.cpp000066400000000000000000000175711220711462700165100ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include using namespace newsbeuter; namespace podbeuter { pb_view::pb_view(pb_controller * c) : ctrl(c), dllist_form(dllist_str), help_form(help_str), keys(0) { } pb_view::~pb_view() { stfl::reset(); } void pb_view::run(bool auto_download) { bool quit = false; set_dllist_keymap_hint(); do { if (ctrl->view_update_necessary()) { double total_kbps = ctrl->get_total_kbps(); char parbuf[128] = ""; if (ctrl->get_maxdownloads() > 1) { snprintf(parbuf, sizeof(parbuf), _(" - %u parallel downloads"), ctrl->get_maxdownloads()); } char buf[1024]; snprintf(buf, sizeof(buf), _("Queue (%u downloads in progress, %u total) - %.2f kb/s total%s"), static_cast(ctrl->downloads_in_progress()), static_cast(ctrl->downloads().size()), total_kbps, parbuf); dllist_form.set("head", buf); LOG(LOG_DEBUG, "pb_view::run: updating view... downloads().size() = %u", ctrl->downloads().size()); if (ctrl->downloads().size() > 0) { std::string code = "{list"; unsigned int i = 0; for (std::vector::iterator it=ctrl->downloads().begin();it!=ctrl->downloads().end();++it,++i) { char lbuf[1024]; snprintf(lbuf, sizeof(lbuf), " %4u [%6.1fMB/%6.1fMB] [%5.1f %%] [%7.2f kb/s] %-20s %s -> %s", i+1, it->current_size()/(1024*1024), it->total_size()/(1024*1024), it->percents_finished(), it->kbps(), it->status_text(), it->url(), it->filename()); code.append(utils::strprintf("{listitem[%u] text:%s}", i, stfl::quote(lbuf).c_str())); } code.append("}"); dllist_form.modify("dls", "replace_inner", code); } ctrl->set_view_update_necessary(false); } const char * event = dllist_form.run(500); if (auto_download) { if (ctrl->get_maxdownloads() > ctrl->downloads_in_progress()) { ctrl->start_downloads(); } } if (!event || strcmp(event,"TIMEOUT")==0) continue; operation op = keys->get_operation(event, "podbeuter"); if (dllist_form.get("msg").length() > 0) { dllist_form.set("msg", ""); ctrl->set_view_update_necessary(true); } switch (op) { case OP_PB_TOGGLE_DLALL: auto_download = !auto_download; break; case OP_HARDQUIT: case OP_QUIT: if (ctrl->downloads_in_progress() > 0) { dllist_form.set("msg", _("Error: can't quit: download(s) in progress.")); ctrl->set_view_update_necessary(true); } else { quit = true; } break; case OP_PB_MOREDL: ctrl->increase_parallel_downloads(); break; case OP_PB_LESSDL: ctrl->decrease_parallel_downloads(); break; case OP_PB_DOWNLOAD: { std::istringstream os(dllist_form.get("dlposname")); int idx = -1; os >> idx; if (idx != -1) { if (ctrl->downloads()[idx].status() != DL_DOWNLOADING) { poddlthread * thread = new poddlthread(&ctrl->downloads()[idx], ctrl->get_cfgcont()); thread->start(); } } } break; case OP_PB_PLAY: { std::istringstream os(dllist_form.get("dlposname")); int idx = -1; os >> idx; if (idx != -1) { dlstatus_t status = ctrl->downloads()[idx].status(); if (status == DL_FINISHED || status == DL_PLAYED || status == DL_READY) { ctrl->play_file(ctrl->downloads()[idx].filename()); ctrl->downloads()[idx].set_status(DL_PLAYED); } else { dllist_form.set("msg", _("Error: download needs to be finished before the file can be played.")); } } } break; case OP_PB_MARK_FINISHED: { std::istringstream os(dllist_form.get("dlposname")); int idx = -1; os >> idx; if (idx != -1) { dlstatus_t status = ctrl->downloads()[idx].status(); if ( status == DL_PLAYED ) { ctrl->downloads()[idx].set_status(DL_FINISHED); } } } break; case OP_PB_CANCEL: { std::istringstream os(dllist_form.get("dlposname")); int idx = -1; os >> idx; if (idx != -1) { if (ctrl->downloads()[idx].status() == DL_DOWNLOADING) { ctrl->downloads()[idx].set_status(DL_CANCELLED); } } } break; case OP_PB_DELETE: { std::istringstream os(dllist_form.get("dlposname")); int idx = -1; os >> idx; if (idx != -1) { if (ctrl->downloads()[idx].status() != DL_DOWNLOADING) { ctrl->downloads()[idx].set_status(DL_DELETED); } } } break; case OP_PB_PURGE: if (ctrl->downloads_in_progress() > 0) { dllist_form.set("msg", _("Error: unable to perform operation: download(s) in progress.")); } else { ctrl->reload_queue(true); } ctrl->set_view_update_necessary(true); break; case OP_HELP: run_help(); break; default: break; } } while (!quit); } void pb_view::set_bindings() { if (keys) { std::string upkey("** "); upkey.append(keys->getkey(OP_SK_UP, "podbeuter")); std::string downkey("** "); downkey.append(keys->getkey(OP_SK_DOWN, "podbeuter")); std::string pgupkey("** "); pgupkey.append(keys->getkey(OP_SK_PGUP, "podbeuter")); std::string pgdownkey("** "); pgdownkey.append(keys->getkey(OP_SK_PGDOWN, "podbeuter")); std::string homekey("** "); homekey.append(keys->getkey(OP_SK_HOME, "podbeuter")); std::string endkey("** "); endkey.append(keys->getkey(OP_SK_END, "podbeuter")); dllist_form.set("bind_up", upkey); dllist_form.set("bind_down", downkey); dllist_form.set("bind_page_up", pgupkey); dllist_form.set("bind_page_down", pgdownkey); dllist_form.set("bind_home", homekey); dllist_form.set("bind_end", endkey); help_form.set("bind_up", upkey); help_form.set("bind_down", downkey); help_form.set("bind_page_up", pgupkey); help_form.set("bind_page_down", pgdownkey); help_form.set("bind_home", homekey); help_form.set("bind_end", endkey); } } void pb_view::run_help() { set_help_keymap_hint(); help_form.set("head",_("Help")); std::vector descs; keys->get_keymap_descriptions(descs, KM_PODBEUTER); std::string code = "{list"; for (std::vector::iterator it=descs.begin();it!=descs.end();++it) { std::string line = "{listitem text:"; std::string descline; descline.append(it->key); descline.append(8-it->key.length(),' '); descline.append(it->cmd); descline.append(24-it->cmd.length(),' '); descline.append(it->desc); line.append(stfl::quote(descline)); line.append("}"); code.append(line); } code.append("}"); help_form.modify("helptext","replace_inner",code); bool quit = false; do { const char * event = help_form.run(0); if (!event) continue; operation op = keys->get_operation(event, "help"); switch (op) { case OP_HARDQUIT: case OP_QUIT: quit = true; break; default: break; } } while (!quit); } std::string pb_view::prepare_keymaphint(keymap_hint_entry * hints) { std::string keymap_hint; for (int i=0;hints[i].op != OP_NIL; ++i) { keymap_hint.append(keys->getkey(hints[i].op, "podbeuter")); keymap_hint.append(":"); keymap_hint.append(hints[i].text); keymap_hint.append(" "); } return keymap_hint; } void pb_view::set_help_keymap_hint() { keymap_hint_entry hints[] = { { OP_QUIT, _("Quit") }, { OP_NIL, NULL } }; std::string keymap_hint = prepare_keymaphint(hints); help_form.set("help", keymap_hint); } void pb_view::set_dllist_keymap_hint() { keymap_hint_entry hints[] = { { OP_QUIT, _("Quit") }, { OP_PB_DOWNLOAD, _("Download") }, { OP_PB_CANCEL, _("Cancel") }, { OP_PB_DELETE, _("Delete") }, { OP_PB_PURGE, _("Purge Finished") }, { OP_PB_TOGGLE_DLALL, _("Toggle Automatic Download") }, { OP_PB_PLAY, _("Play") }, { OP_PB_MARK_FINISHED, _("Mark as Finished") }, { OP_HELP, _("Help") }, { OP_NIL, NULL } }; std::string keymap_hint = prepare_keymaphint(hints); dllist_form.set("help", keymap_hint); } } newsbeuter-2.7/src/poddlthread.cpp000066400000000000000000000075341220711462700173450ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include using namespace newsbeuter; namespace podbeuter { static size_t my_write_data(void *buffer, size_t size, size_t nmemb, void *userp); static int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow); poddlthread::poddlthread(download * dl_, newsbeuter::configcontainer * c) : dl(dl_), cfg(c) { } poddlthread::~poddlthread() { } void poddlthread::run() { gettimeofday(&tv1, NULL); ++bytecount; CURL * easyhandle = curl_easy_init(); utils::set_common_curl_options(easyhandle, cfg); curl_easy_setopt(easyhandle, CURLOPT_URL, dl->url()); curl_easy_setopt(easyhandle, CURLOPT_TIMEOUT, 0); // set up write functions: curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, my_write_data); curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, this); // set up progress notification: curl_easy_setopt(easyhandle, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(easyhandle, CURLOPT_PROGRESSFUNCTION, progress_callback); curl_easy_setopt(easyhandle, CURLOPT_PROGRESSDATA, this); // set up max download speed int max_dl_speed = cfg->get_configvalue_as_int("max-download-speed"); if (max_dl_speed > 0) { curl_easy_setopt(easyhandle, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t)(max_dl_speed * 1024)); } struct stat sb; if (stat(dl->filename(), &sb) == -1) { LOG(LOG_INFO, "poddlthread::run: stat failed: starting normal download"); mkdir_p(dl->filename()); f.open(dl->filename(), std::fstream::out); dl->set_offset(0); } else { LOG(LOG_INFO, "poddlthread::run: stat ok: starting download from %u", sb.st_size); curl_easy_setopt(easyhandle, CURLOPT_RESUME_FROM, sb.st_size); dl->set_offset(sb.st_size); f.open(dl->filename(), std::fstream::out | std::fstream::app); } if (f.is_open()) { dl->set_status(DL_DOWNLOADING); CURLcode success = curl_easy_perform(easyhandle); f.close(); LOG(LOG_INFO,"poddlthread::run: curl_easy_perform rc = %u (%s)", success, curl_easy_strerror(success)); if (0 == success) dl->set_status(DL_READY); else if (dl->status() != DL_CANCELLED) { dl->set_status(DL_FAILED); ::unlink(dl->filename()); } } else { dl->set_status(DL_FAILED); } curl_easy_cleanup(easyhandle); } static size_t my_write_data(void *buffer, size_t size, size_t nmemb, void *userp) { poddlthread * thread = (poddlthread *)userp; return thread->write_data(buffer, size, nmemb); } static int progress_callback(void *clientp, double dltotal, double dlnow, double /* ultotal */, double /*ulnow*/) { poddlthread * thread = (poddlthread *)clientp; return thread->progress(dlnow, dltotal); } size_t poddlthread::write_data(void * buffer, size_t size, size_t nmemb) { if (dl->status() == DL_CANCELLED) return 0; f.write(static_cast(buffer), size * nmemb); bytecount += (size * nmemb); LOG(LOG_DEBUG, "poddlthread::write_data: bad = %u size = %u", f.bad(), size * nmemb); return f.bad() ? 0 : size * nmemb; } int poddlthread::progress(double dlnow, double dltotal) { if (dl->status() == DL_CANCELLED) return -1; gettimeofday(&tv2, NULL); double kbps = compute_kbps(); if (kbps > 9999.99) { kbps = 0.0; gettimeofday(&tv1, NULL); bytecount = 0; } dl->set_kbps(kbps); dl->set_progress(dlnow, dltotal); return 0; } double poddlthread::compute_kbps() { double result = 0.0; double t1 = tv1.tv_sec + (tv1.tv_usec/(double)1000000); double t2 = tv2.tv_sec + (tv2.tv_usec/(double)1000000); result = (bytecount / (t2 - t1))/1024; return result; } void poddlthread::mkdir_p(const char * file) { char path[2048]; snprintf(path, sizeof(path), "%s", file); for (char * x = path;*x != '\0';x++) { if (*x == '/') { *x = '\0'; mkdir(path, 0755); *x = '/'; } } } } newsbeuter-2.7/src/queueloader.cpp000066400000000000000000000075711220711462700173670ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include using namespace newsbeuter; namespace podbeuter { queueloader::queueloader(const std::string& file, pb_controller * c) : queuefile(file), ctrl(c) { } void queueloader::reload(std::vector& downloads, bool remove_unplayed) { std::vector dltemp; std::fstream f; if (downloads.size() > 0) { for (std::vector::iterator it=downloads.begin();it!=downloads.end();++it) { if (it->status() == DL_DOWNLOADING) { // we are not allowed to reload if a download is in progress! LOG(LOG_INFO, "queueloader::reload: aborting reload due to DL_DOWNLOADING status"); return; } switch (it->status()) { case DL_QUEUED: case DL_CANCELLED: case DL_FAILED: case DL_ALREADY_DOWNLOADED: case DL_READY: LOG(LOG_DEBUG, "queueloader::reload: storing %s to new vector", it->url()); dltemp.push_back(*it); break; case DL_PLAYED: case DL_FINISHED: if (!remove_unplayed) { LOG(LOG_DEBUG, "queueloader::reload: storing %s to new vector", it->url()); dltemp.push_back(*it); } break; default: break; } } } f.open(queuefile.c_str(), std::fstream::in); if (f.is_open()) { std::string line; do { getline(f, line); if (!f.eof() && line.length() > 0) { LOG(LOG_DEBUG, "queueloader::reload: loaded `%s' from queue file", line.c_str()); std::vector fields = utils::tokenize_quoted(line); bool url_found = false; if (!dltemp.empty()) { for (std::vector::iterator it=dltemp.begin();it!=dltemp.end();++it) { if (fields[0] == it->url()) { LOG(LOG_INFO, "queueloader::reload: found `%s' in old vector", fields[0].c_str()); url_found = true; break; } } } if (!downloads.empty()) { for (std::vector::iterator it=downloads.begin();it!=downloads.end();++it) { if (fields[0] == it->url()) { LOG(LOG_INFO, "queueloader::reload: found `%s' in new vector", line.c_str()); url_found = true; break; } } } if (!url_found) { LOG(LOG_INFO, "queueloader::reload: found `%s' nowhere -> storing to new vector", line.c_str()); download d(ctrl); std::string fn; if (fields.size() == 1) fn = get_filename(fields[0]); else fn = fields[1]; d.set_filename(fn); if (access(fn.c_str(), F_OK)==0) { LOG(LOG_INFO, "queueloader::reload: found `%s' on file system -> mark as already downloaded", fn.c_str()); if (fields.size() >= 3) { if (fields[2] == "downloaded") d.set_status(DL_READY); if (fields[2] == "played") d.set_status(DL_PLAYED); } else d.set_status(DL_ALREADY_DOWNLOADED); // TODO: scrap DL_ALREADY_DOWNLOADED state } d.set_url(fields[0]); dltemp.push_back(d); } } } while (!f.eof()); f.close(); } f.open(queuefile.c_str(), std::fstream::out); if (f.is_open()) { for (std::vector::iterator it=dltemp.begin();it!=dltemp.end();++it) { f << it->url() << " " << stfl::quote(it->filename()); if (it->status() == DL_READY) f << " downloaded"; if (it->status() == DL_PLAYED) f << " played"; f << std::endl; } f.close(); } downloads = dltemp; } std::string queueloader::get_filename(const std::string& str) { std::string fn = ctrl->get_dlpath(); if (fn[fn.length()-1] != NEWSBEUTER_PATH_SEP[0]) fn.append(NEWSBEUTER_PATH_SEP); char buf[1024]; snprintf(buf, sizeof(buf), "%s", str.c_str()); char * base = basename(buf); if (!base || strlen(base) == 0) { char lbuf[128]; time_t t = time(NULL); strftime(lbuf, sizeof(lbuf), "%Y-%b-%d-%H%M%S.unknown", localtime(&t)); fn.append(lbuf); } else { fn.append(base); } return fn; } } newsbeuter-2.7/src/regexmanager.cpp000066400000000000000000000161511220711462700175130ustar00rootroot00000000000000#include #include #include #include #include #include namespace newsbeuter { regexmanager::regexmanager() { // this creates the entries in the map. we need them there to have the "all" location work. locations["article"]; locations["articlelist"]; locations["feedlist"]; } regexmanager::~regexmanager() { for (std::map::iterator jt=locations.begin();jt!=locations.end();++jt) { std::vector& regexes(jt->second.first); if (regexes.size() > 0) { for (std::vector::iterator it=regexes.begin();it!=regexes.end();++it) { delete *it; } } } } void regexmanager::dump_config(std::vector& config_output) { for (std::vector::iterator it=cheat_store_for_dump_config.begin();it!=cheat_store_for_dump_config.end();++it) { config_output.push_back(*it); } } void regexmanager::handle_action(const std::string& action, const std::vector& params) { if (action == "highlight") { if (params.size() < 3) throw confighandlerexception(AHS_TOO_FEW_PARAMS); std::string location = params[0]; if (location != "all" && location != "article" && location != "articlelist" && location != "feedlist") throw confighandlerexception(utils::strprintf(_("`%s' is an invalid dialog type"), location.c_str())); regex_t * rx = new regex_t; int err; if ((err = regcomp(rx, params[1].c_str(), REG_EXTENDED | REG_ICASE)) != 0) { delete rx; char buf[1024]; regerror(err, rx, buf, sizeof(buf)); throw confighandlerexception(utils::strprintf(_("`%s' is not a valid regular expression: %s"), params[1].c_str(), buf)); } std::string colorstr; if (params[2] != "default") { colorstr.append("fg="); if (!utils::is_valid_color(params[2])) throw confighandlerexception(utils::strprintf(_("`%s' is not a valid color"), params[2].c_str())); colorstr.append(params[2]); } if (params.size() > 2) { if (params[3] != "default") { if (colorstr.length() > 0) colorstr.append(","); colorstr.append("bg="); if (!utils::is_valid_color(params[3])) throw confighandlerexception(utils::strprintf(_("`%s' is not a valid color"), params[3].c_str())); colorstr.append(params[3]); } for (unsigned int i=4;i 0) colorstr.append(","); colorstr.append("attr="); if (!utils::is_valid_attribute(params[i])) throw confighandlerexception(utils::strprintf(_("`%s' is not a valid attribute"), params[i].c_str())); colorstr.append(params[i]); } } } if (location != "all") { LOG(LOG_DEBUG, "regexmanager::handle_action: adding rx = %s colorstr = %s to location %s", params[1].c_str(), colorstr.c_str(), location.c_str()); locations[location].first.push_back(rx); locations[location].second.push_back(colorstr); } else { delete rx; for (std::map::iterator it=locations.begin();it!=locations.end();++it) { LOG(LOG_DEBUG, "regexmanager::handle_action: adding rx = %s colorstr = %s to location %s", params[1].c_str(), colorstr.c_str(), it->first.c_str()); rx = new regex_t; // we need to create a new one for each push_back, otherwise we'd have double frees. regcomp(rx, params[1].c_str(), REG_EXTENDED | REG_ICASE); it->second.first.push_back(rx); it->second.second.push_back(colorstr); } } std::string line = "highlight"; for (std::vector::const_iterator it=params.begin();it!=params.end();++it) { line.append(" "); line.append(utils::quote(*it)); } cheat_store_for_dump_config.push_back(line); } else if (action == "highlight-article") { if (params.size() < 3) throw confighandlerexception(AHS_TOO_FEW_PARAMS); std::string expr = params[0]; std::string fgcolor = params[1]; std::string bgcolor = params[2]; std::string colorstr; if (fgcolor != "default") { colorstr.append("fg="); if (!utils::is_valid_color(fgcolor)) throw confighandlerexception(utils::strprintf(_("`%s' is not a valid color"), fgcolor.c_str())); colorstr.append(fgcolor); } if (bgcolor != "default") { if (colorstr.length() > 0) colorstr.append(","); colorstr.append("bg="); if (!utils::is_valid_color(bgcolor)) throw confighandlerexception(utils::strprintf(_("`%s' is not a valid color"), bgcolor.c_str())); colorstr.append(bgcolor); } for (unsigned int i=3;i 0) colorstr.append(","); colorstr.append("attr="); if (!utils::is_valid_attribute(params[i])) throw confighandlerexception(utils::strprintf(_("`%s' is not a valid attribute"), params[i].c_str())); colorstr.append(params[i]); } } std::tr1::shared_ptr m(new matcher()); if (!m->parse(params[0])) { throw confighandlerexception(utils::strprintf(_("couldn't parse filter expression `%s': %s"), params[0].c_str(), m->get_parse_error().c_str())); } int pos = locations["articlelist"].first.size(); locations["articlelist"].first.push_back(NULL); locations["articlelist"].second.push_back(colorstr); matchers.push_back(std::pair, int>(m, pos)); } else throw confighandlerexception(AHS_INVALID_COMMAND); } int regexmanager::article_matches(matchable * item) { for (std::vector, int> >::iterator it=matchers.begin();it!=matchers.end();++it) { if (it->first->matches(item)) { return it->second; } } return -1; } void regexmanager::remove_last_regex(const std::string& location) { std::vector& regexes = locations[location].first; std::vector::iterator it=regexes.begin(); for (unsigned int i=0;i", 0); if (pos != std::string::npos) { return str.substr(0, pos+1); } } return ""; } void regexmanager::quote_and_highlight(std::string& str, const std::string& location) { std::vector& regexes = locations[location].first; unsigned int i = 0; for (std::vector::iterator it=regexes.begin();it!=regexes.end();++it, ++i) { if (!*it) continue; std::string initial_marker = extract_initial_marker(str); regmatch_t pmatch; unsigned int offset = 0; int err = regexec(*it, str.c_str(), 1, &pmatch, 0); while (err == 0) { // LOG(LOG_DEBUG, "regexmanager::quote_and_highlight: matched %s rm_so = %u rm_eo = %u", str.c_str() + offset, pmatch.rm_so, pmatch.rm_eo); std::string marker = utils::strprintf("<%u>", i); str.insert(offset + pmatch.rm_eo, std::string("") + initial_marker); // LOG(LOG_DEBUG, "after first insert: %s", str.c_str()); str.insert(offset + pmatch.rm_so, marker); // LOG(LOG_DEBUG, "after second insert: %s", str.c_str()); offset += pmatch.rm_eo + marker.length() + strlen("") + initial_marker.length(); err = regexec(*it, str.c_str() + offset, 1, &pmatch, 0); } } } } newsbeuter-2.7/src/reloadthread.cpp000066400000000000000000000022441220711462700175020ustar00rootroot00000000000000#include #include #include namespace newsbeuter { reloadthread::reloadthread(controller * c, configcontainer * cf) : ctrl(c), oldtime(0), waittime_sec(0), suppressed_first(false), cfg(cf) { LOG(LOG_INFO,"reloadthread: waiting %u seconds between reloads",waittime_sec); } reloadthread::~reloadthread() { } void reloadthread::run() { for (;;) { oldtime = time(NULL); LOG(LOG_INFO,"reloadthread: starting reload"); waittime_sec = 60 * cfg->get_configvalue_as_int("reload-time"); if (waittime_sec == 0) waittime_sec = 60; if (cfg->get_configvalue_as_bool("auto-reload")) { if (suppressed_first) { ctrl->start_reload_all_thread(); } else { suppressed_first = true; if (!cfg->get_configvalue_as_bool("suppress-first-reload")) { ctrl->start_reload_all_thread(); } } } else { waittime_sec = 60; // if auto-reload is disabled, we poll every 60 seconds whether it changed. } time_t seconds_to_wait = 0; if ((oldtime + waittime_sec) > time(NULL)) seconds_to_wait = oldtime + waittime_sec - time(NULL); while (seconds_to_wait > 0) { seconds_to_wait = ::sleep(seconds_to_wait); } } } } newsbeuter-2.7/src/rss.cpp000066400000000000000000000444061220711462700156610ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace newsbeuter { rss_item::rss_item(cache * c) : unread_(true), ch(c), enqueued_(false), deleted_(0), idx(0), override_unread_(false), size_(0) { // LOG(LOG_CRITICAL, "new rss_item"); } rss_item::~rss_item() { // LOG(LOG_CRITICAL, "delete rss_item"); } rss_feed::rss_feed(cache * c) : ch(c), empty(true), is_rtl_(false), idx(0), status_(SUCCESS) { // LOG(LOG_CRITICAL, "new rss_feed"); } rss_feed::~rss_feed() { // LOG(LOG_CRITICAL, "delete rss_feed"); clear_items(); } // rss_item setters void rss_item::set_title(const std::string& t) { title_ = t; utils::trim(title_); } void rss_item::set_link(const std::string& l) { link_ = l; utils::trim(link_); } void rss_item::set_author(const std::string& a) { author_ = a; } void rss_item::set_description(const std::string& d) { description_ = d; } void rss_item::set_size(unsigned int size) { size_ = size; } std::string rss_item::length() const { std::string::size_type l(size_); if (!l) return ""; if (l < 1000) return utils::strprintf("%u ", l); if (l < 1024*1000) return utils::strprintf("%.1fK", l/1024.0); return utils::strprintf("%.1fM", l/1024.0/1024.0); } void rss_item::set_pubDate(time_t t) { pubDate_ = t; } void rss_item::set_guid(const std::string& g) { guid_ = g; } void rss_item::set_unread_nowrite(bool u) { unread_ = u; } void rss_item::set_unread_nowrite_notify(bool u, bool notify) { unread_ = u; if (feedptr && notify) { feedptr->get_item_by_guid(guid_)->set_unread_nowrite(unread_); // notify parent feed } } void rss_item::set_unread(bool u) { if (unread_ != u) { bool old_u = unread_; unread_ = u; if (feedptr) feedptr->get_item_by_guid(guid_)->set_unread_nowrite(unread_); // notify parent feed try { if (ch) ch->update_rssitem_unread_and_enqueued(this, feedurl_); } catch (const dbexception& e) { // if the update failed, restore the old unread flag and rethrow the exception unread_ = old_u; throw; } } } std::string rss_item::pubDate() const { char text[1024]; strftime(text,sizeof(text),"%a, %d %b %Y %T %z", localtime(&pubDate_)); return std::string(text); } unsigned int rss_feed::unread_item_count() { scope_mutex lock(&item_mutex); unsigned int count = 0; for (std::vector >::const_iterator it=items_.begin();it!=items_.end();++it) { if ((*it)->unread()) ++count; } return count; } bool rss_feed::matches_tag(const std::string& tag) { for (std::vector::iterator it=tags_.begin();it!=tags_.end();++it) { if (tag == *it) return true; } return false; } std::string rss_feed::get_firsttag() { if (tags_.size() == 0) return ""; return tags_[0]; } std::string rss_feed::get_tags() { std::string tags; for (std::vector::iterator it=tags_.begin();it!=tags_.end();++it) { if (it->substr(0,1) != "~" && it->substr(0,1) != "!") { tags.append(*it); tags.append(" "); } } return tags; } void rss_feed::set_tags(const std::vector& tags) { tags_.clear(); for (std::vector::const_iterator it=tags.begin();it!=tags.end();++it) { tags_.push_back(*it); } } void rss_item::set_enclosure_url(const std::string& url) { enclosure_url_ = url; } void rss_item::set_enclosure_type(const std::string& type) { enclosure_type_ = type; } std::string rss_item::title() const { std::string retval; if (title_.length()>0) retval = utils::convert_text(title_, nl_langinfo(CODESET), "utf-8"); return retval; } std::string rss_item::author() const { return utils::convert_text(author_, nl_langinfo(CODESET), "utf-8"); } std::string rss_item::description() const { return utils::convert_text(description_, nl_langinfo(CODESET), "utf-8"); } std::string rss_feed::title() const { bool found_title = false; std::string alt_title; for (std::vector::const_iterator it=tags_.begin();it!=tags_.end();++it) { if (it->substr(0,1) == "~" || it->substr(0,1) == "!") { found_title = true; alt_title = it->substr(1, it->length()-1); break; } } return found_title ? alt_title : utils::convert_text(title_, nl_langinfo(CODESET), "utf-8"); } std::string rss_feed::description() const { return utils::convert_text(description_, nl_langinfo(CODESET), "utf-8"); } bool rss_feed::hidden() const { for (std::vector::const_iterator it=tags_.begin();it!=tags_.end();++it) { if (it->substr(0,1) == "!") { return true; } } return false; } std::tr1::shared_ptr rss_feed::get_item_by_guid(const std::string& guid) { scope_mutex lock(&item_mutex); return get_item_by_guid_unlocked(guid); } std::tr1::shared_ptr rss_feed::get_item_by_guid_unlocked(const std::string& guid) { std::tr1::unordered_map >::const_iterator it; if ((it = items_guid_map.find(guid)) != items_guid_map.end()) { return it->second; } LOG(LOG_DEBUG, "rss_feed::get_item_by_guid_unlocked: hit dummy item!"); // abort(); return std::tr1::shared_ptr(new rss_item(ch)); // should never happen! } bool rss_item::has_attribute(const std::string& attribname) { // LOG(LOG_DEBUG, "rss_item::has_attribute(%s) called", attribname.c_str()); if (attribname == "title" || attribname == "link" || attribname == "author" || attribname == "content" || attribname == "date" || attribname == "guid" || attribname == "unread" || attribname == "enclosure_url" || attribname == "enclosure_type" || attribname == "flags" || attribname == "age" || attribname == "articleindex") return true; // if we have a feed, then forward the request if (feedptr) return feedptr->rss_feed::has_attribute(attribname); return false; } std::string rss_item::get_attribute(const std::string& attribname) { if (attribname == "title") return title(); else if (attribname == "link") return link(); else if (attribname == "author") return author(); else if (attribname == "content") return description(); else if (attribname == "date") return pubDate(); else if (attribname == "guid") return guid(); else if (attribname == "unread") return unread_ ? "yes" : "no"; else if (attribname == "enclosure_url") return enclosure_url(); else if (attribname == "enclosure_type") return enclosure_type(); else if (attribname == "flags") return flags(); else if (attribname == "age") return utils::to_string((time(NULL) - pubDate_timestamp()) / 86400); else if (attribname == "articleindex") return utils::to_string(idx); // if we have a feed, then forward the request if (feedptr) return feedptr->rss_feed::get_attribute(attribname); return ""; } void rss_item::update_flags() { if (ch) { ch->update_rssitem_flags(this); } } void rss_item::set_flags(const std::string& ff) { oldflags_ = flags_; flags_ = ff; sort_flags(); } void rss_item::sort_flags() { std::sort(flags_.begin(), flags_.end()); for (std::string::iterator it=flags_.begin();flags_.size() > 0 && it!=flags_.end();++it) { if (!isalpha(*it)) { flags_.erase(it); it = flags_.begin(); } } for (unsigned int i=0;i(unread_item_count()); } else if (attribname == "total_count") { return utils::to_string(items_.size()); } else if (attribname == "tags") { return get_tags(); } else if (attribname == "feedindex") { return utils::to_string(idx); } return ""; } void rss_ignores::handle_action(const std::string& action, const std::vector& params) { if (action == "ignore-article") { if (params.size() < 2) throw confighandlerexception(AHS_TOO_FEW_PARAMS); std::string ignore_rssurl = params[0]; std::string ignore_expr = params[1]; matcher m; if (!m.parse(ignore_expr)) throw confighandlerexception(utils::strprintf(_("couldn't parse filter expression `%s': %s"), ignore_expr.c_str(), m.get_parse_error().c_str())); ignores.push_back(feedurl_expr_pair(ignore_rssurl, new matcher(ignore_expr))); } else if (action == "always-download") { for (std::vector::const_iterator it=params.begin();it!=params.end();++it) { ignores_lastmodified.push_back(*it); } } else if (action == "reset-unread-on-update") { for (std::vector::const_iterator it=params.begin();it!=params.end();++it) { resetflag.push_back(*it); } } else throw confighandlerexception(AHS_INVALID_COMMAND); } void rss_ignores::dump_config(std::vector& config_output) { for (std::vector::iterator it = ignores.begin();it!=ignores.end();++it) { std::string configline = "ignore-article "; if (it->first == "*") configline.append("*"); else configline.append(utils::quote(it->first)); configline.append(" "); configline.append(utils::quote(it->second->get_expression())); config_output.push_back(configline); } for (std::vector::iterator it=ignores_lastmodified.begin();it!=ignores_lastmodified.end();++it) { config_output.push_back(utils::strprintf("always-download %s", utils::quote(*it).c_str())); } for (std::vector::iterator it=resetflag.begin();it!=resetflag.end();++it) { config_output.push_back(utils::strprintf("reset-unread-on-update %s", utils::quote(*it).c_str())); } } rss_ignores::~rss_ignores() { for (std::vector::iterator it=ignores.begin();it!=ignores.end();++it) { delete it->second; } } bool rss_ignores::matches(rss_item* item) { for (std::vector::iterator it=ignores.begin();it!=ignores.end();++it) { LOG(LOG_DEBUG, "rss_ignores::matches: it->first = `%s' item->feedurl = `%s'", it->first.c_str(), item->feedurl().c_str()); if (it->first == "*" || item->feedurl() == it->first) { if (it->second->matches(item)) { LOG(LOG_DEBUG, "rss_ignores::matches: found match"); return true; } } } return false; } bool rss_ignores::matches_lastmodified(const std::string& url) { for (std::vector::iterator it=ignores_lastmodified.begin();it!=ignores_lastmodified.end();++it) { if (url == *it) return true; } return false; } bool rss_ignores::matches_resetunread(const std::string& url) { for (std::vector::iterator it=resetflag.begin();it!=resetflag.end();++it) { if (url == *it) return true; } return false; } void rss_feed::update_items(std::vector > feeds) { scope_mutex lock(&item_mutex); if (query.length() == 0) return; LOG(LOG_DEBUG, "rss_feed::update_items: query = `%s'", query.c_str()); struct timeval tv1, tv2, tvx; gettimeofday(&tv1, NULL); matcher m(query); items_.clear(); items_guid_map.clear(); for (std::vector >::iterator it=feeds.begin();it!=feeds.end();++it) { if ((*it)->rssurl().substr(0,6) != "query:") { // don't fetch items from other query feeds! for (std::vector >::iterator jt=(*it)->items().begin();jt!=(*it)->items().end();++jt) { if (m.matches(jt->get())) { LOG(LOG_DEBUG, "rss_feed::update_items: matcher matches!"); (*jt)->set_feedptr(*it); items_.push_back(*jt); items_guid_map[(*jt)->guid()] = *jt; } } } } gettimeofday(&tvx, NULL); std::sort(items_.begin(), items_.end()); gettimeofday(&tv2, NULL); unsigned long diff = (((tv2.tv_sec - tv1.tv_sec) * 1000000) + tv2.tv_usec) - tv1.tv_usec; unsigned long diffx = (((tv2.tv_sec - tvx.tv_sec) * 1000000) + tv2.tv_usec) - tvx.tv_usec; LOG(LOG_DEBUG, "rss_feed::update_items matching took %lu.%06lu s", diff / 1000000, diff % 1000000); LOG(LOG_DEBUG, "rss_feed::update_items sorting took %lu.%06lu s", diffx / 1000000, diffx % 1000000); } void rss_feed::set_rssurl(const std::string& u) { rssurl_ = u; if (rssurl_.substr(0,6) == "query:") { std::vector tokens = utils::tokenize_quoted(u, ":"); if (tokens.size() < 3) { throw std::string(_("too few arguments")); } LOG(LOG_DEBUG, "rss_feed::set_rssurl: query name = `%s' expr = `%s'", tokens[1].c_str(), tokens[2].c_str()); set_title(tokens[1]); set_query(tokens[2]); } } struct sort_item_by_title : public std::binary_function, std::tr1::shared_ptr, bool> { bool reverse; sort_item_by_title(bool b) : reverse(b) { } bool operator()(std::tr1::shared_ptr a, std::tr1::shared_ptr b) { return reverse ? (strcasecmp(a->title().c_str(), b->title().c_str()) > 0) : (strcasecmp(a->title().c_str(), b->title().c_str()) < 0); } }; struct sort_item_by_flags : public std::binary_function, std::tr1::shared_ptr, bool> { bool reverse; sort_item_by_flags(bool b) : reverse(b) { } bool operator()(std::tr1::shared_ptr a, std::tr1::shared_ptr b) { return reverse ? (strcmp(a->flags().c_str(), b->flags().c_str()) > 0) : (strcmp(a->flags().c_str(), b->flags().c_str()) < 0); } }; struct sort_item_by_author : public std::binary_function, std::tr1::shared_ptr, bool> { bool reverse; sort_item_by_author(bool b) : reverse(b) { } bool operator()(std::tr1::shared_ptr a, std::tr1::shared_ptr b) { return reverse ? (strcmp(a->author().c_str(), b->author().c_str()) > 0) : (strcmp(a->author().c_str(), b->author().c_str()) < 0); } }; struct sort_item_by_link : public std::binary_function, std::tr1::shared_ptr, bool> { bool reverse; sort_item_by_link(bool b) : reverse(b) { } bool operator()(std::tr1::shared_ptr a, std::tr1::shared_ptr b) { return reverse ? (strcmp(a->link().c_str(), b->link().c_str()) > 0) : (strcmp(a->link().c_str(), b->link().c_str()) < 0); } }; struct sort_item_by_guid : public std::binary_function, std::tr1::shared_ptr, bool> { bool reverse; sort_item_by_guid(bool b) : reverse(b) { } bool operator()(std::tr1::shared_ptr a, std::tr1::shared_ptr b) { return reverse ? (strcmp(a->guid().c_str(), b->guid().c_str()) > 0) : (strcmp(a->guid().c_str(), b->guid().c_str()) < 0); } }; struct sort_item_by_date : public std::binary_function, std::tr1::shared_ptr, bool> { bool reverse; sort_item_by_date(bool b) : reverse(b) { } bool operator()(std::tr1::shared_ptr a, std::tr1::shared_ptr b) { return reverse ? (a->pubDate_timestamp() > b->pubDate_timestamp()) : (a->pubDate_timestamp() < b->pubDate_timestamp()); } }; void rss_feed::sort(const std::string& method) { scope_mutex lock(&item_mutex); sort_unlocked(method); } void rss_feed::sort_unlocked(const std::string& method) { std::vector methods = utils::tokenize(method,"-"); bool reverse = false; if (!methods.empty() && methods[0] == "date") { // date is descending by default if (methods.size() > 1 && methods[1] == "asc") { reverse = true; } } else { // all other sort methods are ascending by default if (methods.size() > 1 && methods[1] == "desc") { reverse = true; } } if (!methods.empty()) { if (methods[0] == "title") { std::stable_sort(items_.begin(), items_.end(), sort_item_by_title(reverse)); } else if (methods[0] == "flags") { std::stable_sort(items_.begin(), items_.end(), sort_item_by_flags(reverse)); } else if (methods[0] == "author") { std::stable_sort(items_.begin(), items_.end(), sort_item_by_author(reverse)); } else if (methods[0] == "link") { std::stable_sort(items_.begin(), items_.end(), sort_item_by_link(reverse)); } else if (methods[0] == "guid") { std::stable_sort(items_.begin(), items_.end(), sort_item_by_guid(reverse)); } else if (methods[0] == "date") { std::stable_sort(items_.begin(), items_.end(), sort_item_by_date(reverse)); } } } void rss_feed::remove_old_deleted_items() { scope_mutex lock(&item_mutex); std::vector guids; for (std::vector >::iterator it=items_.begin();it!=items_.end();++it) { guids.push_back((*it)->guid()); } ch->remove_old_deleted_items(rssurl_, guids); } void rss_feed::purge_deleted_items() { scope_mutex lock(&item_mutex); scope_measure m1("rss_feed::purge_deleted_items"); std::vector >::iterator it=items_.begin(); while (it!=items_.end()) { if ((*it)->deleted()) { items_guid_map.erase((*it)->guid()); items_.erase(it); it = items_.begin(); // items_ modified -> iterator invalidated } else { ++it; } } } void rss_feed::set_feedptrs(std::tr1::shared_ptr self) { scope_mutex lock(&item_mutex); for (std::vector >::iterator it=items_.begin();it!=items_.end();++it) { (*it)->set_feedptr(self); } } void rss_item::set_feedptr(std::tr1::shared_ptr ptr) { feedptr = ptr; } std::string rss_feed::get_status() { switch (status_) { case SUCCESS: return " "; case TO_BE_DOWNLOADED: return "_"; case DURING_DOWNLOAD: return "."; case DL_ERROR: return "x"; default: return "?"; } } void rss_feed::unload() { scope_mutex lock(&item_mutex); for (std::vector >::iterator it=items_.begin();it!=items_.end();++it) { (*it)->unload(); } } void rss_feed::load() { scope_mutex lock(&item_mutex); ch->fetch_descriptions(this); } } newsbeuter-2.7/src/rss_parser.cpp000066400000000000000000000337261220711462700172400ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace newsbeuter { rss_parser::rss_parser(const std::string& uri, cache * c, configcontainer * cfg, rss_ignores * ii, remote_api * a) : my_uri(uri), ch(c), cfgcont(cfg), skip_parsing(false), is_valid(false), ign(ii), api(a), easyhandle(0) { is_ttrss = cfgcont->get_configvalue("urls-source") == "ttrss"; } rss_parser::~rss_parser() { } std::tr1::shared_ptr rss_parser::parse() { std::tr1::shared_ptr feed(new rss_feed(ch)); feed->set_rssurl(my_uri); retrieve_uri(my_uri); if (!skip_parsing && is_valid) { /* * After parsing is done, we fill our feed object with title, * description, etc. It's important to note that all data that comes * from rsspp must be converted to UTF-8 before, because all data is * internally stored as UTF-8, and converted on-the-fly in case some * other encoding is required. This is because UTF-8 can hold all * available Unicode characters, unlike other non-Unicode encodings. */ fill_feed_fields(feed); fill_feed_items(feed); feed->remove_old_deleted_items(); } feed->set_empty(false); return feed; } time_t rss_parser::parse_date(const std::string& datestr) { time_t t = curl_getdate(datestr.c_str(), NULL); if (t == -1) { LOG(LOG_INFO, "rss_parser::parse_date: encountered t == -1, trying out W3CDTF parser..."); t = curl_getdate(rsspp::rss_parser::__w3cdtf_to_rfc822(datestr).c_str(), NULL); } if (t == -1) { LOG(LOG_INFO, "rss_parser::parse_date: still t == -1, setting to current time"); t = ::time(NULL); } return t; } void rss_parser::replace_newline_characters(std::string& str) { str = utils::replace_all(str, "\r", " "); str = utils::replace_all(str, "\n", " "); utils::trim(str); } std::string rss_parser::render_xhtml_title(const std::string& title, const std::string& link) { htmlrenderer rnd(1 << 16, true); // a huge number std::vector lines; std::vector links; // not needed rnd.render(title, lines, links, link); if (!lines.empty()) return lines[0]; return ""; } void rss_parser::set_rtl(std::tr1::shared_ptr feed, const char * lang) { // we implement right-to-left support for the languages listed in // http://blogs.msdn.com/rssteam/archive/2007/05/17/reading-feeds-in-right-to-left-order.aspx static const char * rtl_langprefix[] = { "ar", // Arabic "fa", // Farsi "ur", // Urdu "ps", // Pashtu "syr", // Syriac "dv", // Divehi "he", // Hebrew "yi", // Yiddish NULL }; for (unsigned int i=0;rtl_langprefix[i]!=NULL;++i) { if (strncmp(lang,rtl_langprefix[i],strlen(rtl_langprefix[i]))==0) { LOG(LOG_DEBUG, "rss_parser::parse: detected right-to-left order, language code = %s", rtl_langprefix[i]); feed->set_rtl(true); break; } } } void rss_parser::retrieve_uri(const std::string& uri) { /* * - http:// and https:// URLs are downloaded and parsed regularly * - exec: URLs are executed and their output is parsed * - filter: URLs are downloaded, executed, and their output is parsed * - query: URLs are ignored */ if (is_ttrss) { const char * uri = my_uri.c_str(); const char * pound = strrchr(uri, '#'); if (pound != NULL) { fetch_ttrss(pound+1); } } else if (uri.substr(0,5) == "http:" || uri.substr(0,6) == "https:") { download_http(uri); } else if (uri.substr(0,5) == "exec:") { get_execplugin(uri.substr(5,uri.length()-5)); } else if (uri.substr(0,7) == "filter:") { std::string filter, url; utils::extract_filter(uri, filter, url); download_filterplugin(filter, url); } else if (my_uri.substr(0,6) == "query:") { skip_parsing = true; } else if (my_uri.substr(0,7) == "file://") { parse_file(my_uri.substr(7, my_uri.length()-7)); } else throw utils::strprintf(_("Error: unsupported URL: %s"), my_uri.c_str()); } void rss_parser::download_http(const std::string& uri) { unsigned int retrycount = cfgcont->get_configvalue_as_int("download-retries"); char * proxy = NULL; char * proxy_auth = NULL; std::string proxy_type; is_valid = false; if (cfgcont->get_configvalue_as_bool("use-proxy") == true) { proxy = const_cast(cfgcont->get_configvalue("proxy").c_str()); proxy_auth = const_cast(cfgcont->get_configvalue("proxy-auth").c_str()); proxy_type = cfgcont->get_configvalue("proxy-type"); } for (unsigned int i=0;iget_configvalue_as_int("download-timeout"), useragent.c_str(), proxy, proxy_auth, utils::get_proxy_type(proxy_type)); time_t lm = 0; std::string etag; if (!ign || !ign->matches_lastmodified(uri)) { ch->fetch_lastmodified(uri, lm, etag); } f = p.parse_url(uri, lm, etag, api, cfgcont->get_configvalue("cookie-cache"), easyhandle ? easyhandle->ptr() : 0); LOG(LOG_DEBUG, "rss_parser::download_http: lm = %d etag = %s", p.get_last_modified(), p.get_etag().c_str()); if (p.get_last_modified() != 0 || p.get_etag().length() > 0) { LOG(LOG_DEBUG, "rss_parser::download_http: lastmodified old: %d new: %d", lm, p.get_last_modified()); LOG(LOG_DEBUG, "rss_parser::download_http: etag old: %s new %s", etag.c_str(), p.get_etag().c_str()); ch->update_lastmodified(uri, (p.get_last_modified() != lm) ? p.get_last_modified() : 0 , (etag != p.get_etag()) ? p.get_etag() : ""); } is_valid = true; } catch (rsspp::exception& e) { is_valid = false; throw e; } } LOG(LOG_DEBUG, "rss_parser::parse: http URL %s, is_valid = %s", uri.c_str(), is_valid ? "true" : "false"); } void rss_parser::get_execplugin(const std::string& plugin) { std::string buf = utils::get_command_output(plugin); is_valid = false; try { rsspp::parser p; f = p.parse_buffer(buf.c_str(), buf.length()); is_valid = true; } catch (rsspp::exception& e) { is_valid = false; throw e; } LOG(LOG_DEBUG, "rss_parser::parse: execplugin %s, is_valid = %s", plugin.c_str(), is_valid ? "true" : "false"); } void rss_parser::parse_file(const std::string& file) { is_valid = false; try { rsspp::parser p; f = p.parse_file(file); is_valid = true; } catch (rsspp::exception& e) { is_valid = false; throw e; } LOG(LOG_DEBUG, "rss_parser::parse: parsed file %s, is_valid = %s", file.c_str(), is_valid ? "true" : "false"); } void rss_parser::download_filterplugin(const std::string& filter, const std::string& uri) { std::string buf = utils::retrieve_url(uri, cfgcont); char * argv[4] = { const_cast("/bin/sh"), const_cast("-c"), const_cast(filter.c_str()), NULL }; std::string result = utils::run_program(argv, buf); LOG(LOG_DEBUG, "rss_parser::parse: output of `%s' is: %s", filter.c_str(), result.c_str()); is_valid = false; try { rsspp::parser p; f = p.parse_buffer(result.c_str(), result.length()); is_valid = true; } catch (rsspp::exception& e) { is_valid = false; throw e; } LOG(LOG_DEBUG, "rss_parser::parse: filterplugin %s, is_valid = %s", filter.c_str(), is_valid ? "true" : "false"); } void rss_parser::fill_feed_fields(std::tr1::shared_ptr feed) { /* * we fill all the feed members with the appropriate values from the rsspp data structure */ if (is_html_type(f.title_type)) { feed->set_title(render_xhtml_title(f.title, feed->link())); } else { feed->set_title(f.title); } feed->set_description(f.description); feed->set_link(utils::absolute_url(my_uri, f.link)); if (f.pubDate != "") feed->set_pubDate(parse_date(f.pubDate)); else feed->set_pubDate(::time(NULL)); set_rtl(feed, f.language.c_str()); LOG(LOG_DEBUG, "rss_parser::parse: feed title = `%s' link = `%s'", feed->title().c_str(), feed->link().c_str()); } void rss_parser::fill_feed_items(std::tr1::shared_ptr feed) { /* * we iterate over all items of a feed, create an rss_item object for * each item, and fill it with the appropriate values from the data structure. */ for (std::vector::iterator item=f.items.begin();item!=f.items.end();++item) { std::tr1::shared_ptr x(new rss_item(ch)); set_item_title(feed, x, *item); if (item->link != "") { x->set_link(utils::absolute_url(feed->link(), item->link)); } if (x->link().empty() && item->guid_isPermaLink) { x->set_link(item->guid); } set_item_author(x, *item); x->set_feedurl(feed->rssurl()); x->set_feedptr(feed); if ((f.rss_version == rsspp::ATOM_1_0 || f.rss_version == rsspp::TTRSS_JSON) && item->labels.size() > 0) { std::vector::const_iterator start, finish; start = item->labels.begin(); finish = item->labels.end(); if (std::find(start, finish, "fresh") != finish) { x->set_unread_nowrite(true); x->set_override_unread(true); } if (std::find(start, finish, "kept-unread") != finish) { x->set_unread_nowrite(true); x->set_override_unread(true); } if (std::find(start, finish, "read") != finish) { x->set_unread_nowrite(false); x->set_override_unread(true); } if (std::find(start, finish, "ttrss:unread") != finish) { x->set_unread_nowrite(true); x->set_override_unread(true); } if (std::find(start, finish, "ttrss:read") != finish) { x->set_unread_nowrite(false); x->set_override_unread(true); } } set_item_content(x, *item); if (item->pubDate != "") x->set_pubDate(parse_date(item->pubDate)); else x->set_pubDate(::time(NULL)); x->set_guid(get_guid(*item)); x->set_base(item->base); set_item_enclosure(x, *item); LOG(LOG_DEBUG, "rss_parser::parse: item title = `%s' link = `%s' pubDate = `%s' (%d) description = `%s'", x->title().c_str(), x->link().c_str(), x->pubDate().c_str(), x->pubDate_timestamp(), x->description().c_str()); add_item_to_feed(feed, x); } } void rss_parser::set_item_title(std::tr1::shared_ptr feed, std::tr1::shared_ptr x, rsspp::item& item) { if (is_html_type(item.title_type)) { x->set_title(render_xhtml_title(item.title, feed->link())); } else { std::string title = item.title; replace_newline_characters(title); x->set_title(title); } } void rss_parser::set_item_author(std::tr1::shared_ptr x, rsspp::item& item) { /* * some feeds only have a feed-wide managingEditor, which we use as an item's * author if there is no item-specific one available. */ if (item.author == "") { if (f.managingeditor != "") x->set_author(f.managingeditor); else { x->set_author(f.dc_creator); } } else { x->set_author(item.author); } } void rss_parser::set_item_content(std::tr1::shared_ptr x, rsspp::item& item) { handle_content_encoded(x, item); handle_itunes_summary(x, item); if (x->description() == "") { x->set_description(item.description); } else { if (cfgcont->get_configvalue_as_bool("always-display-description") && item.description != "") x->set_description(x->description() + "
    " + item.description); } /* if it's still empty and we shall download the full page, then we do so. */ if (x->description() == "" && cfgcont->get_configvalue_as_bool("download-full-page") && x->link() != "") { x->set_description(utils::retrieve_url(x->link(), cfgcont)); } LOG(LOG_DEBUG, "rss_parser::set_item_content: content = %s", x->description().c_str()); } std::string rss_parser::get_guid(rsspp::item& item) { /* * We try to find a GUID (some unique identifier) for an item. If the regular * GUID is not available (oh, well, there are a few broken feeds around, after * all), we try out the link and the title, instead. This is suboptimal, of course, * because it makes it impossible to recognize duplicates when the title or the * link changes. */ if (item.guid != "") return item.guid; else if (item.link != "") return item.link; else if (item.title != "") return item.title; else return ""; // too bad. } void rss_parser::set_item_enclosure(std::tr1::shared_ptr x, rsspp::item& item) { x->set_enclosure_url(item.enclosure_url); x->set_enclosure_type(item.enclosure_type); LOG(LOG_DEBUG, "rss_parser::parse: found enclosure_url: %s", item.enclosure_url.c_str()); LOG(LOG_DEBUG, "rss_parser::parse: found enclosure_type: %s", item.enclosure_type.c_str()); } void rss_parser::add_item_to_feed(std::tr1::shared_ptr feed, std::tr1::shared_ptr item) { // only add item to feed if it isn't on the ignore list or if there is no ignore list if (!ign || !ign->matches(item.get())) { feed->add_item(item); LOG(LOG_INFO, "rss_parser::parse: added article title = `%s' link = `%s' ign = %p", item->title().c_str(), item->link().c_str(), ign); } else { LOG(LOG_INFO, "rss_parser::parse: ignored article title = `%s' link = `%s'", item->title().c_str(), item->link().c_str()); } } void rss_parser::handle_content_encoded(std::tr1::shared_ptr x, rsspp::item& item) { if (x->description() != "") return; /* here we handle content:encoded tags that are an extension but very widespread */ if (item.content_encoded != "") { x->set_description(item.content_encoded); } else { LOG(LOG_DEBUG, "rss_parser::parse: found no content:encoded"); } } void rss_parser::handle_itunes_summary(std::tr1::shared_ptr x, rsspp::item& item) { if (x->description() != "") return; std::string summary = item.itunes_summary; if (summary != "") { std::string desc = ""; desc.append(summary); desc.append(""); x->set_description(desc); } } bool rss_parser::is_html_type(const std::string& type) { return (type == "html" || type == "xhtml" || type == "application/xhtml+xml"); } void rss_parser::fetch_ttrss(const std::string& feed_id) { ttrss_api * tapi = dynamic_cast(api); if (tapi) { f = tapi->fetch_feed(feed_id); is_valid = true; } LOG(LOG_DEBUG, "rss_parser::fetch_ttrss: f.items.size = %u", f.items.size()); } } newsbeuter-2.7/src/select_formaction.cpp000066400000000000000000000076461220711462700205570ustar00rootroot00000000000000#include #include #include #include #include #include #include #include namespace newsbeuter { /* * The select_formaction is used both for the "select tag" dialog * and the "select filter", as they do practically the same. That's * why there is the decision between SELECTTAG and SELECTFILTER on * a few places. */ select_formaction::select_formaction(view * vv, std::string formstr) : formaction(vv, formstr) { } select_formaction::~select_formaction() { } void select_formaction::handle_cmdline(const std::string& cmd) { unsigned int idx = 0; if (1==sscanf(cmd.c_str(),"%u",&idx)) { if (idx > 0 && idx <= ((type == SELECTTAG) ? tags.size() : filters.size())) { f->set("tagpos", utils::to_string(idx - 1)); } } else { formaction::handle_cmdline(cmd); } } void select_formaction::process_operation(operation op, bool /* automatic */, std::vector * /* args */) { bool hardquit = false; switch (op) { case OP_QUIT: value = ""; quit = true; break; case OP_HARDQUIT: value = ""; hardquit = true; break; case OP_OPEN: { std::string tagposname = f->get("tagposname"); std::istringstream posname(tagposname); unsigned int pos = 0; posname >> pos; if (tagposname.length() > 0) { switch (type) { case SELECTTAG: { if (pos < tags.size()) { value = tags[pos]; quit = true; } } break; case SELECTFILTER: { if (pos < filters.size()) { value = filters[pos].second; quit = true; } } break; default: assert(0); // should never happen } } } break; default: break; } if (hardquit) { while (v->formaction_stack_size() > 0) { v->pop_current_formaction(); } } else if (quit) { v->pop_current_formaction(); } } void select_formaction::prepare() { if (do_redraw) { listformatter listfmt; unsigned int i=0; switch (type) { case SELECTTAG: for (std::vector::const_iterator it=tags.begin();it!=tags.end();++it,++i) { std::string tagstr = utils::strprintf("%4u %s (%u)", i+1, it->c_str(), v->get_ctrl()->get_feed_count_per_tag(*it)); listfmt.add_line(tagstr, i); } break; case SELECTFILTER: for (std::vector::const_iterator it=filters.begin();it!=filters.end();++it,++i) { std::string tagstr = utils::strprintf("%4u %s", i+1, it->first.c_str()); listfmt.add_line(tagstr, i); } break; default: assert(0); } f->modify("taglist", "replace_inner", listfmt.format_list()); do_redraw = false; } } void select_formaction::init() { std::string title; do_redraw = true; quit = false; value = ""; std::string viewwidth = f->get("taglist:w"); std::istringstream is(viewwidth); unsigned int width; is >> width; set_keymap_hints(); fmtstr_formatter fmt; fmt.register_fmt('N', PROGRAM_NAME); fmt.register_fmt('V', PROGRAM_VERSION); switch (type) { case SELECTTAG: title = fmt.do_format(v->get_cfg()->get_configvalue("selecttag-title-format"), width); break; case SELECTFILTER: title = fmt.do_format(v->get_cfg()->get_configvalue("selectfilter-title-format"), width); break; default: assert(0); // should never happen } f->set("head", title); } keymap_hint_entry * select_formaction::get_keymap_hint() { static keymap_hint_entry hints_tag[] = { { OP_QUIT, _("Cancel") }, { OP_OPEN, _("Select Tag") }, { OP_NIL, NULL } }; static keymap_hint_entry hints_filter[] = { { OP_QUIT, _("Cancel") }, { OP_OPEN, _("Select Filter") }, { OP_NIL, NULL } }; switch (type) { case SELECTTAG: return hints_tag; case SELECTFILTER: return hints_filter; } return NULL; } std::string select_formaction::title() { switch (type) { case SELECTTAG: return _("Select Tag"); case SELECTFILTER: return _("Select Filter"); default: return ""; } } } newsbeuter-2.7/src/stflpp.cpp000066400000000000000000000067301220711462700163600ustar00rootroot00000000000000#include #include #include #include #include namespace newsbeuter { /* * This is a wrapper around the low-level C functions of STFL. * In order to make working with std::string easier, this wrapper * was created. This is also useful for logging all stfl-related * operations if necessary, and for working around bugs in STFL, * especially related to stuff like multithreading fuckups. */ stfl::form::form(const std::string& text) : f(0) { ipool = stfl_ipool_create((std::string(nl_langinfo(CODESET)) + "//TRANSLIT").c_str()); if (!ipool) { throw exception(errno); } f = stfl_create(stfl_ipool_towc(ipool, text.c_str())); if (!f) { throw exception(errno); } } stfl::form::~form() { if (f) stfl_free(f); if (ipool) stfl_ipool_destroy(ipool); } const char * stfl::form::run(int timeout) { return stfl_ipool_fromwc(ipool,stfl_run(f,timeout)); } std::string stfl::form::get(const std::string& name) { const char * text = stfl_ipool_fromwc(ipool,stfl_get(f,stfl_ipool_towc(ipool,name.c_str()))); std::string retval; if (text) retval = text; stfl_ipool_flush(ipool); return retval; } void stfl::form::set(const std::string& name, const std::string& value) { stfl_set(f, stfl_ipool_towc(ipool,name.c_str()), stfl_ipool_towc(ipool,value.c_str())); stfl_ipool_flush(ipool); } std::string stfl::form::get_focus() { const char * focus = stfl_ipool_fromwc(ipool,stfl_get_focus(f)); std::string retval; if (focus) retval = focus; stfl_ipool_flush(ipool); return retval; } void stfl::form::set_focus(const std::string& name) { stfl_set_focus(f, stfl_ipool_towc(ipool,name.c_str())); LOG(LOG_DEBUG,"stfl::form::set_focus: %s", name.c_str()); } void stfl::form::modify(const std::string& name, const std::string& mode, const std::string& text) { const wchar_t * wname, * wmode, * wtext; wname = stfl_ipool_towc(ipool,name.c_str()); wmode = stfl_ipool_towc(ipool,mode.c_str()); wtext = stfl_ipool_towc(ipool,text.c_str()); stfl_modify(f, wname, wmode, wtext); stfl_ipool_flush(ipool); } void stfl::reset() { stfl_reset(); } static mutex quote_mtx; std::string stfl::quote(const std::string& text) { scope_mutex lock("e_mtx); stfl_ipool * ipool = stfl_ipool_create((std::string(nl_langinfo(CODESET)) + "//TRANSLIT").c_str()); std::string retval = stfl_ipool_fromwc(ipool,stfl_quote(stfl_ipool_towc(ipool,text.c_str()))); stfl_ipool_destroy(ipool); return retval; } std::string stfl::form::dump(const std::string& name, const std::string& prefix, int focus) { const char * text = stfl_ipool_fromwc(ipool,stfl_dump(f, stfl_ipool_towc(ipool,name.c_str()), stfl_ipool_towc(ipool,prefix.c_str()), focus)); std::string retval; if (text) retval = text; stfl_ipool_flush(ipool); return retval; } /* std::string stfl::form::lookup(const std::string& path, const std::string& newname) { const char * text = stfl_ipool_fromwc(ipool, stfl_lookup(f, stfl_ipool_towc(ipool,path.c_str()), stfl_ipool_towc(ipool,newname.c_str()))); std::string retval; if (text) return retval = text; stfl_ipool_flush(ipool); return retval; } std::string stfl::error() { stfl_ipool * ipool = stfl_ipool_create(nl_langinfo(CODESET)); std::string retval = stfl_ipool_fromwc(ipool,stfl_error()); stfl_ipool_destroy(ipool); return retval; } void stfl::error_action(const std::string& mode) { stfl_ipool * ipool = stfl_ipool_create(nl_langinfo(CODESET)); stfl_error_action(stfl_ipool_towc(ipool,mode.c_str())); stfl_ipool_destroy(ipool); } */ } newsbeuter-2.7/src/tagsouppullparser.cpp000066400000000000000000000304131220711462700206370ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include namespace newsbeuter { /* * This method implements an "XML" pull parser. In reality, it's more liberal * than any XML pull parser, as it basically accepts everything that even only * remotely looks like XML. We use this parser for the HTML renderer. */ tagsouppullparser::tagsouppullparser() : inputstream(0), current_event(START_DOCUMENT) { } tagsouppullparser::~tagsouppullparser() { } void tagsouppullparser::setInput(std::istream& is) { inputstream = &is; current_event = START_DOCUMENT; } std::string tagsouppullparser::getAttributeValue(const std::string& name) const { for (std::vector::const_iterator it=attributes.begin();it!=attributes.end();++it) { if (it->first == name) { return it->second; } } throw std::invalid_argument(_("attribute not found")); } tagsouppullparser::event tagsouppullparser::getEventType() const { return current_event; } std::string tagsouppullparser::getText() const { return text; } tagsouppullparser::event tagsouppullparser::next() { /* * the next() method returns the next event by parsing the * next element of the XML stream, depending on the current * event. */ attributes.clear(); text = ""; if (inputstream->eof()) { current_event = END_DOCUMENT; } switch (current_event) { case START_DOCUMENT: case START_TAG: case END_TAG: skip_whitespace(); if (inputstream->eof()) { current_event = END_DOCUMENT; break; } if (c != '<') { handle_text(); break; } case TEXT: handle_tag(); break; case END_DOCUMENT: break; } return getEventType(); } void tagsouppullparser::skip_whitespace() { c = '\0'; ws = ""; do { inputstream->read(&c,1); if (!inputstream->eof()) { if (!isspace(c)) break; else ws.append(1,c); } } while (!inputstream->eof()); } void tagsouppullparser::add_attribute(std::string s) { if (s.length() > 0 && s[s.length()-1] == '/') s.erase(s.length()-1,1); if (s.length() == 0) return; std::string::size_type equalpos = s.find_first_of("=",0); std::string attribname, attribvalue; if (equalpos != std::string::npos) { attribname = s.substr(0,equalpos); attribvalue = s.substr(equalpos+1,s.length()-(equalpos+1)); } else { attribname = attribvalue = s; } attribvalue = decode_attribute(attribvalue); std::transform(attribname.begin(), attribname.end(), attribname.begin(), ::tolower); attributes.push_back(attribute(attribname,attribvalue)); } std::string tagsouppullparser::read_tag() { std::string s; getline(*inputstream,s,'>'); if (inputstream->eof()) { throw xmlexception(_("EOF found while reading XML tag")); // TODO: test whether this works reliably } return s; } tagsouppullparser::event tagsouppullparser::determine_tag_type() { if (text.length() > 0 && text[0] == '/') { text.erase(0,1); return END_TAG; } return START_TAG; } std::string tagsouppullparser::decode_attribute(const std::string& s) { std::string s1 = s; if ((s1[0] == '"' && s1[s1.length()-1] == '"') || (s1[0] == '\'' && s1[s1.length()-1] == '\'')) { if (s1.length() > 0) s1.erase(0,1); if (s1.length() > 0) s1.erase(s1.length()-1,1); } return decode_entities(s1); } std::string tagsouppullparser::decode_entities(const std::string& s) { std::string result, current_entity; std::istringstream sbuf(s); std::string tmp; getline(sbuf,tmp,'&'); while (!sbuf.eof()) { result.append(tmp); getline(sbuf,tmp,';'); result.append(decode_entity(tmp)); getline(sbuf,tmp,'&'); } result.append(tmp); return result; } static struct { const char * entity; unsigned int value; } entity_table[] = { /* semi-automatically generated from: - http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent - http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent - http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent */ { "nbsp", ' ' }, { "iexcl", 161 }, { "cent", 162 }, { "pound", 163 }, { "curren", 164 }, { "yen", 165 }, { "brvbar", 166 }, { "sect", 167 }, { "uml", 168 }, { "copy", 169 }, { "ordf", 170 }, { "laquo", 171 }, { "not", 172 }, { "shy", 173 }, { "reg", 174 }, { "macr", 175 }, { "deg", 176 }, { "plusmn", 177 }, { "sup2", 178 }, { "sup3", 179 }, { "acute", 180 }, { "micro", 181 }, { "para", 182 }, { "middot", 183 }, { "cedil", 184 }, { "sup1", 185 }, { "ordm", 186 }, { "raquo", 187 }, { "frac14", 188 }, { "frac12", 189 }, { "frac34", 190 }, { "iquest", 191 }, { "Agrave", 192 }, { "Aacute", 193 }, { "Acirc", 194 }, { "Atilde", 195 }, { "Auml", 196 }, { "Aring", 197 }, { "AElig", 198 }, { "Ccedil", 199 }, { "Egrave", 200 }, { "Eacute", 201 }, { "Ecirc", 202 }, { "Euml", 203 }, { "Igrave", 204 }, { "Iacute", 205 }, { "Icirc", 206 }, { "Iuml", 207 }, { "ETH", 208 }, { "Ntilde", 209 }, { "Ograve", 210 }, { "Oacute", 211 }, { "Ocirc", 212 }, { "Otilde", 213 }, { "Ouml", 214 }, { "times", 215 }, { "Oslash", 216 }, { "Ugrave", 217 }, { "Uacute", 218 }, { "Ucirc", 219 }, { "Uuml", 220 }, { "Yacute", 221 }, { "THORN", 222 }, { "szlig", 223 }, { "agrave", 224 }, { "aacute", 225 }, { "acirc", 226 }, { "atilde", 227 }, { "auml", 228 }, { "aring", 229 }, { "aelig", 230 }, { "ccedil", 231 }, { "egrave", 232 }, { "eacute", 233 }, { "ecirc", 234 }, { "euml", 235 }, { "igrave", 236 }, { "iacute", 237 }, { "icirc", 238 }, { "iuml", 239 }, { "eth", 240 }, { "ntilde", 241 }, { "ograve", 242 }, { "oacute", 243 }, { "ocirc", 244 }, { "otilde", 245 }, { "ouml", 246 }, { "divide", 247 }, { "oslash", 248 }, { "ugrave", 249 }, { "uacute", 250 }, { "ucirc", 251 }, { "uuml", 252 }, { "yacute", 253 }, { "thorn", 254 }, { "yuml", 255 }, { "quot", 34 }, { "amp", 38 }, { "lt", 60 }, { "gt", 62 }, { "apos", 39 }, { "OElig", 338 }, { "oelig", 339 }, { "Scaron", 352 }, { "scaron", 353 }, { "Yuml", 376 }, { "circ", 710 }, { "tilde", 732 }, { "ensp", 8194 }, { "emsp", 8195 }, { "thinsp", 8201 }, { "zwnj", 8204 }, { "zwj", 8205 }, { "lrm", 8206 }, { "rlm", 8207 }, { "ndash", 8211 }, { "mdash", 8212 }, { "lsquo", 8216 }, { "rsquo", 8217 }, { "sbquo", 8218 }, { "ldquo", 8220 }, { "rdquo", 8221 }, { "bdquo", 8222 }, { "dagger", 8224 }, { "Dagger", 8225 }, { "permil", 8240 }, { "lsaquo", 8249 }, { "rsaquo", 8250 }, { "euro", 8364 }, { "fnof", 402 }, { "Alpha", 913 }, { "Beta", 914 }, { "Gamma", 915 }, { "Delta", 916 }, { "Epsilon", 917 }, { "Zeta", 918 }, { "Eta", 919 }, { "Theta", 920 }, { "Iota", 921 }, { "Kappa", 922 }, { "Lambda", 923 }, { "Mu", 924 }, { "Nu", 925 }, { "Xi", 926 }, { "Omicron", 927 }, { "Pi", 928 }, { "Rho", 929 }, { "Sigma", 931 }, { "Tau", 932 }, { "Upsilon", 933 }, { "Phi", 934 }, { "Chi", 935 }, { "Psi", 936 }, { "Omega", 937 }, { "alpha", 945 }, { "beta", 946 }, { "gamma", 947 }, { "delta", 948 }, { "epsilon", 949 }, { "zeta", 950 }, { "eta", 951 }, { "theta", 952 }, { "iota", 953 }, { "kappa", 954 }, { "lambda", 955 }, { "mu", 956 }, { "nu", 957 }, { "xi", 958 }, { "omicron", 959 }, { "pi", 960 }, { "rho", 961 }, { "sigmaf", 962 }, { "sigma", 963 }, { "tau", 964 }, { "upsilon", 965 }, { "phi", 966 }, { "chi", 967 }, { "psi", 968 }, { "omega", 969 }, { "thetasym", 977 }, { "upsih", 978 }, { "piv", 982 }, { "bull", 8226 }, { "hellip", 8230 }, { "prime", 8242 }, { "Prime", 8243 }, { "oline", 8254 }, { "frasl", 8260 }, { "weierp", 8472 }, { "image", 8465 }, { "real", 8476 }, { "trade", 8482 }, { "alefsym", 8501 }, { "larr", 8592 }, { "uarr", 8593 }, { "rarr", 8594 }, { "darr", 8595 }, { "harr", 8596 }, { "crarr", 8629 }, { "lArr", 8656 }, { "uArr", 8657 }, { "rArr", 8658 }, { "dArr", 8659 }, { "hArr", 8660 }, { "forall", 8704 }, { "part", 8706 }, { "exist", 8707 }, { "empty", 8709 }, { "nabla", 8711 }, { "isin", 8712 }, { "notin", 8713 }, { "ni", 8715 }, { "prod", 8719 }, { "sum", 8721 }, { "minus", 8722 }, { "lowast", 8727 }, { "radic", 8730 }, { "prop", 8733 }, { "infin", 8734 }, { "ang", 8736 }, { "and", 8743 }, { "or", 8744 }, { "cap", 8745 }, { "cup", 8746 }, { "int", 8747 }, { "there4", 8756 }, { "sim", 8764 }, { "cong", 8773 }, { "asymp", 8776 }, { "ne", 8800 }, { "equiv", 8801 }, { "le", 8804 }, { "ge", 8805 }, { "sub", 8834 }, { "sup", 8835 }, { "nsub", 8836 }, { "sube", 8838 }, { "supe", 8839 }, { "oplus", 8853 }, { "otimes", 8855 }, { "perp", 8869 }, { "sdot", 8901 }, { "lceil", 8968 }, { "rceil", 8969 }, { "lfloor", 8970 }, { "rfloor", 8971 }, { "lang", 9001 }, { "rang", 9002 }, { "loz", 9674 }, { "spades", 9824 }, { "clubs", 9827 }, { "hearts", 9829 }, { "diams", 9830 }, { 0, 0 } }; std::string tagsouppullparser::decode_entity(std::string s) { LOG(LOG_DEBUG, "tagsouppullparser::decode_entity: decoding '%s'...", s.c_str()); if (s.length() > 1 && s[0] == '#') { std::string result; unsigned int wc; char mbc[MB_CUR_MAX]; mbc[0] = '\0'; if (s[1] == 'x') { s.erase(0,2); std::istringstream is(s); is >> std::hex >> wc; } else { s.erase(0,1); std::istringstream is(s); is >> wc; } int pos; // convert some common but unknown numeric entities switch (wc) { case 133: wc = 8230; break; // … case 134: wc = 8224; break; // † case 135: wc = 8225; break; // ‡ (double dagger) case 150: wc = 8211; break; // – case 151: wc = 8212; break; // — case 152: wc = 732; break; // ˜ case 153: wc = 8482; break; // ™ case 156: wc = 339; break; // œ } // std::cerr << "value: " << wc << " " << static_cast(wc) << " pos: " << pos << std::endl; pos = wctomb(mbc,static_cast(wc)); if (pos > 0) { mbc[pos] = '\0'; result.append(mbc); } LOG(LOG_DEBUG,"tagsouppullparser::decode_entity: wc = %u pos = %d mbc = '%s'", wc, pos, mbc); return result; } else { for (unsigned int i=0;entity_table[i].entity;++i) { if (s == entity_table[i].entity) { char mbc[MB_CUR_MAX]; int pos = wctomb(mbc, entity_table[i].value); mbc[pos] = '\0'; return std::string(mbc); } } } return ""; } void tagsouppullparser::parse_tag(const std::string& tagstr) { std::string::size_type last_pos = tagstr.find_first_not_of(" \r\n\t", 0); std::string::size_type pos = tagstr.find_first_of(" \r\n\t", last_pos); unsigned int count = 0; LOG(LOG_DEBUG, "parse_tag: parsing '%s', pos = %d, last_pos = %d", tagstr.c_str(), pos, last_pos); while (last_pos != std::string::npos) { if (count == 0) { // first token: tag name if (pos == std::string::npos) pos = tagstr.length(); text = tagstr.substr(last_pos, pos - last_pos); LOG(LOG_DEBUG, "parse_tag: tag name = %s", text.c_str()); } else { pos = tagstr.find_first_of("= ", last_pos); std::string attr; if (pos != std::string::npos) { LOG(LOG_DEBUG, "parse_tag: found = or space"); if (tagstr[pos] == '=') { LOG(LOG_DEBUG, "parse_tag: found ="); if (tagstr[pos+1] == '\'' || tagstr[pos+1] == '"') { pos = tagstr.find_first_of(tagstr[pos+1], pos+2); if (pos != std::string::npos) pos++; LOG(LOG_DEBUG, "parse_tag: finding ending quote, pos = %d", pos); } else { pos = tagstr.find_first_of(" \r\n\t", pos+1); LOG(LOG_DEBUG, "parse_tag: finding end of unquoted attribute"); } } } if (pos == std::string::npos) { LOG(LOG_DEBUG, "parse_tag: found end of string, correcting end position"); pos = tagstr.length(); } attr = tagstr.substr(last_pos, pos - last_pos); LOG(LOG_DEBUG, "parse_tag: extracted attribute is '%s', adding", attr.c_str()); add_attribute(attr); } last_pos = tagstr.find_first_not_of(" \r\n\t", pos); count++; } } void tagsouppullparser::handle_tag() { std::string s; try { s = read_tag(); } catch (const xmlexception &) { current_event = END_DOCUMENT; return; } parse_tag(s); current_event = determine_tag_type(); } void tagsouppullparser::handle_text() { if (current_event != START_DOCUMENT) text.append(ws); text.append(1,c); std::string tmp; getline(*inputstream,tmp,'<'); text.append(tmp); text = decode_entities(text); /* Remove all soft-hyphens as they can behave unpredictable and inadvertently render as hyphens */ text.erase(std::remove(text.begin(), text.end(), 0xad), text.end()); current_event = TEXT; } } newsbeuter-2.7/src/thread.cpp000066400000000000000000000020521220711462700163100ustar00rootroot00000000000000#include #include #include namespace newsbeuter { /* * The thread class is a wrapper around the pthread functions found on virtually * all modern Unix systems. * * To run a thread, you need to derive your own class from thread and implement the * run() method. Then you create an instance of your derived class with the new * operator (very important!), and run the start() method of the object. */ thread::thread() { } thread::~thread() { } pthread_t thread::start() { int rc = pthread_create(&pt, 0, run_thread, this); LOG(LOG_DEBUG, "thread::start: created new thread %d rc = %d", pt, rc); if (rc != 0) { throw exception(rc); } return pt; } void thread::join() { pthread_join(pt, NULL); } void thread::detach() { LOG(LOG_DEBUG, "thread::detach: detaching thread %d", pt); pthread_detach(pt); } void * run_thread(void * p) { thread * t = reinterpret_cast(p); LOG(LOG_DEBUG, "run_thread: p = %p", p); t->run(); delete t; return 0; } void thread::cleanup(thread * p) { delete p; } } newsbeuter-2.7/src/ttrss_api.cpp000066400000000000000000000234501220711462700170560ustar00rootroot00000000000000#include #include #include #include #include #include namespace newsbeuter { ttrss_api::ttrss_api(configcontainer * c) : remote_api(c) { single = (cfg->get_configvalue("ttrss-mode") == "single"); auth_info = utils::strprintf("%s:%s", cfg->get_configvalue("ttrss-login").c_str(), cfg->get_configvalue("ttrss-password").c_str()); auth_info_ptr = auth_info.c_str(); sid = ""; } ttrss_api::~ttrss_api() { } bool ttrss_api::authenticate() { if (auth_lock.trylock()) { sid = retrieve_sid(); auth_lock.unlock(); } else { // wait for other thread to finish and return its result: auth_lock.lock(); auth_lock.unlock(); } return sid != ""; } std::string ttrss_api::retrieve_sid() { std::map args; args["user"] = single ? "admin" : cfg->get_configvalue("ttrss-login"); args["password"] = cfg->get_configvalue("ttrss-password"); struct json_object * content = run_op("login", args); if (content == NULL) return ""; std::string sid; struct json_object * session_id = json_object_object_get(content, "session_id"); sid = json_object_get_string(session_id); json_object_put(content); LOG(LOG_DEBUG, "ttrss_api::retrieve_sid: sid = '%s'", sid.c_str()); return sid; } struct json_object * ttrss_api::run_op(const std::string& op, const std::map& args, bool try_login) { std::string url = utils::strprintf("%s/api/", cfg->get_configvalue("ttrss-url").c_str()); std::string req_data = "{\"op\":\"" + op + "\",\"sid\":\"" + sid + "\""; for (std::map::const_iterator it = args.begin(); it != args.end(); it++) { req_data += ",\"" + it->first + "\":\"" + it->second + "\""; } req_data += "}"; std::string result = utils::retrieve_url(url, cfg, auth_info_ptr, &req_data); LOG(LOG_DEBUG, "ttrss_api::run_op(%s,...): post=%s reply = %s", op.c_str(), req_data.c_str(), result.c_str()); struct json_object * reply = json_tokener_parse(result.c_str()); if (is_error(reply)) { LOG(LOG_ERROR, "ttrss_api::run_op: reply failed to parse: %s", result.c_str()); return NULL; } struct json_object * status = json_object_object_get(reply, "status"); if (is_error(status)) { LOG(LOG_ERROR, "ttrss_api::run_op: no status code"); return NULL; } struct json_object * content = json_object_object_get(reply, "content"); if (is_error(content)) { LOG(LOG_ERROR, "ttrss_api::run_op: no content part in answer from server"); return NULL; } if (json_object_get_int(status) != 0) { struct json_object * error = json_object_object_get(content, "error"); if ((strcmp(json_object_get_string(error), "NOT_LOGGED_IN") == 0) && try_login) { json_object_put(reply); if (authenticate()) return run_op(op, args, false); else return NULL; } else { json_object_put(reply); return NULL; } } // free the parent object, without freeing content as well: json_object_get(content); json_object_put(reply); return content; } std::vector ttrss_api::get_subscribed_urls() { std::vector feeds; struct json_object * content = run_op("getCategories", std::map()); if (!content) return feeds; if (json_object_get_type(content) != json_type_array) return feeds; struct array_list * categories = json_object_get_array(content); int catsize = array_list_length(categories); // first fetch feeds within no category fetch_feeds_per_category(NULL, feeds); // then fetch the feeds of all categories for (int i=0;i args; args["feed_id"] = url_to_id(feed_url); struct json_object * content = run_op("catchupFeed", args); if(!content) return false; json_object_put(content); return true; } bool ttrss_api::mark_article_read(const std::string& guid, bool read) { // Do this in a thread, as we don't care about the result enough to wait for // it. thread * mrt = new markreadthread( this, guid, read ); mrt->start(); return true; } bool ttrss_api::update_article_flags(const std::string& oldflags, const std::string& newflags, const std::string& guid) { std::string star_flag = cfg->get_configvalue("ttrss-flag-star"); std::string publish_flag = cfg->get_configvalue("ttrss-flag-publish"); bool success = true; if (star_flag.length() > 0) { if (strchr(oldflags.c_str(), star_flag[0])==NULL && strchr(newflags.c_str(), star_flag[0])!=NULL) { success = star_article(guid, true); } else if (strchr(oldflags.c_str(), star_flag[0])!=NULL && strchr(newflags.c_str(), star_flag[0])==NULL) { success = star_article(guid, false); } } if (publish_flag.length() > 0) { if (strchr(oldflags.c_str(), publish_flag[0])==NULL && strchr(newflags.c_str(), publish_flag[0])!=NULL) { success = publish_article(guid, true); } else if (strchr(oldflags.c_str(), publish_flag[0])!=NULL && strchr(newflags.c_str(), publish_flag[0])==NULL) { success = publish_article(guid, false); } } return success; } static bool sort_by_pubdate(const rsspp::item& a, const rsspp::item& b) { return a.pubDate_ts > b.pubDate_ts; } rsspp::feed ttrss_api::fetch_feed(const std::string& id) { rsspp::feed f; f.rss_version = rsspp::TTRSS_JSON; std::map args; args["feed_id"] = id; args["show_content"] = "1"; struct json_object * content = run_op("getHeadlines", args); if (!content) return f; if (json_object_get_type(content) != json_type_array) { LOG(LOG_ERROR, "ttrss_api::fetch_feed: content is not an array"); return f; } struct array_list * items = json_object_get_array(content); int items_size = array_list_length(items); LOG(LOG_DEBUG, "ttrss_api::fetch_feed: %d items", items_size); for (int i=0;i& feeds) { const char * cat_name = NULL; struct json_object * cat_title_obj = NULL; int cat_id; if (cat) { struct json_object * cat_id_obj = json_object_object_get(cat, "id"); cat_id = json_object_get_int(cat_id_obj); // ignore special categories, for now if(cat_id < 0) return; cat_title_obj = json_object_object_get(cat, "title"); cat_name = json_object_get_string(cat_title_obj); LOG(LOG_DEBUG, "ttrss_api::fetch_feeds_per_category: id = %d title = %s", cat_id, cat_name); } else { // As uncategorized is a category itself (id = 0) and the default value // for a getFeeds is id = 0, the feeds in uncategorized will appear twice return; } std::map args; if (cat) args["cat_id"] = utils::to_string(cat_id); struct json_object * feed_list_obj = run_op("getFeeds", args); if (!feed_list_obj) return; struct array_list * feed_list = json_object_get_array(feed_list_obj); int feed_list_size = array_list_length(feed_list); for (int j=0;j tags; tags.push_back(std::string("~") + feed_title); if (cat_name) { tags.push_back(cat_name); } feeds.push_back(tagged_feedurl(utils::strprintf("%s#%d", feed_url, feed_id), tags)); // TODO: cache feed_id -> feed_url (or feed_url -> feed_id ?) } json_object_put(feed_list_obj); } bool ttrss_api::star_article(const std::string& guid, bool star) { return update_article(guid, 0, star ? 1 : 0); } bool ttrss_api::publish_article(const std::string& guid, bool publish) { return update_article(guid, 1, publish ? 1 : 0); } bool ttrss_api::update_article(const std::string& guid, int field, int mode) { std::map args; args["article_ids"] = guid; args["field"] = utils::to_string(field); args["mode"] = utils::to_string(mode); struct json_object * content = run_op("updateArticle", args); if (!content) return false; json_object_put(content); return true; } std::string ttrss_api::url_to_id(const std::string& url) { const char * uri = url.c_str(); const char * pound = strrchr(uri, '#'); if (!pound) return ""; return std::string(pound+1); } } newsbeuter-2.7/src/ttrss_urlreader.cpp000066400000000000000000000026021220711462700202660ustar00rootroot00000000000000#include #include namespace newsbeuter { ttrss_urlreader::ttrss_urlreader(configcontainer * c, const std::string& url_file, remote_api * a) : cfg(c), file(url_file), api(a) { } ttrss_urlreader::~ttrss_urlreader() { } void ttrss_urlreader::write_config() { // NOTHING } void ttrss_urlreader::reload() { urls.clear(); tags.clear(); alltags.clear(); file_urlreader ur(file); ur.reload(); std::vector& file_urls(ur.get_urls()); for(std::vector::iterator it=file_urls.begin();it!=file_urls.end();++it) { if (it->substr(0,6) == "query:") { urls.push_back(*it); std::vector& file_tags(ur.get_tags(*it)); tags[*it] = ur.get_tags(*it); for (std::vector::iterator jt=file_tags.begin();jt!=file_tags.end();++jt) { alltags.insert(*jt); } } } std::vector feedurls = api->get_subscribed_urls(); for (std::vector::iterator it=feedurls.begin();it!=feedurls.end();++it) { LOG(LOG_DEBUG, "added %s to URL list", it->first.c_str()); urls.push_back(it->first); tags[it->first] = it->second; for (std::vector::iterator jt=it->second.begin();jt!=it->second.end();++jt) { LOG(LOG_DEBUG, "%s: added tag %s", it->first.c_str(), jt->c_str()); alltags.insert(*jt); } } } std::string ttrss_urlreader::get_source() { return "Tiny Tiny RSS"; } // TODO } newsbeuter-2.7/src/urlreader.cpp000066400000000000000000000105171220711462700170330ustar00rootroot00000000000000#include #include #include #include #include #include #include namespace newsbeuter { urlreader::urlreader() : offline(false) { } urlreader::~urlreader() { } std::vector& urlreader::get_urls() { return urls; } std::vector& urlreader::get_tags(const std::string& url) { return tags[url]; } std::vector urlreader::get_alltags() { std::vector tmptags; for (std::set::iterator it=alltags.begin();it!=alltags.end();++it) { if (it->substr(0,1) != "~") tmptags.push_back(*it); } return tmptags; } file_urlreader::file_urlreader(const std::string& file) : filename(file) { } file_urlreader::~file_urlreader() { } std::string file_urlreader::get_source() { return filename; } void file_urlreader::reload() { if (offline) return; urls.clear(); tags.clear(); alltags.clear(); std::fstream f; f.open(filename.c_str(),std::fstream::in); if (f.is_open()) { std::string line; do { getline(f,line); if (!f.eof() && line.length() > 0 && line[0] != '#') { std::vector tokens = utils::tokenize_quoted(line); if (!tokens.empty()) { std::string url = tokens[0]; urls.push_back(url); tokens.erase(tokens.begin()); if (!tokens.empty()) { tags[url] = tokens; for (std::vector::iterator it=tokens.begin();it!=tokens.end();++it) { alltags.insert(*it); } } } } } while (!f.eof()); } } void file_urlreader::load_config(const std::string& file) { filename = file; reload(); } void file_urlreader::write_config() { std::fstream f; f.open(filename.c_str(),std::fstream::out); if (f.is_open()) { for (std::vector::iterator it=urls.begin(); it != urls.end(); ++it) { f << *it; if (tags[*it].size() > 0) { for (std::vector::iterator jt=tags[*it].begin();jt!=tags[*it].end();++jt) { f << " \"" << *jt << "\""; } } f << std::endl; } } } opml_urlreader::opml_urlreader(configcontainer * c) : cfg(c) { } opml_urlreader::~opml_urlreader() { } void opml_urlreader::write_config() { // do nothing. } void opml_urlreader::reload() { if (offline) return; urls.clear(); tags.clear(); alltags.clear(); std::string user_agent = utils::get_useragent(cfg); std::vector urls = utils::tokenize_quoted(this->get_source(), " "); for (std::vector::iterator it=urls.begin();it!=urls.end();++it) { LOG(LOG_DEBUG, "opml_urlreader::reload: downloading `%s'", it->c_str()); std::string urlcontent = utils::retrieve_url(*it, cfg, this->get_auth()); xmlDoc * doc = xmlParseMemory(urlcontent.c_str(), urlcontent.length()); if (doc == NULL) { LOG(LOG_ERROR, "opml_urlreader::reload: parsing XML file failed"); continue; } xmlNode * root = xmlDocGetRootElement(doc); if (root) { for (xmlNode * node = root->children; node != NULL; node = node->next) { if (strcmp((const char *)node->name, "body")==0) { LOG(LOG_DEBUG, "opml_urlreader::reload: found body"); rec_find_rss_outlines(node->children, ""); } } } xmlFreeDoc(doc); } } void opml_urlreader::handle_node(xmlNode * node, const std::string& tag) { if (node) { char * rssurl = (char *)xmlGetProp(node, (const xmlChar *)"xmlUrl"); if (rssurl && strlen(rssurl) > 0) { std::string theurl(rssurl); urls.push_back(theurl); if (tag.length() > 0) { std::vector tmptags; tmptags.push_back(tag); tags[theurl] = tmptags; alltags.insert(tag); } } if (rssurl) xmlFree(rssurl); } } void opml_urlreader::rec_find_rss_outlines(xmlNode * node, std::string tag) { while (node) { char * type = (char *)xmlGetProp(node, (const xmlChar *)"type"); std::string newtag = tag; if (strcmp((const char *)node->name, "outline")==0) { if (type && strcmp(type,"rss")==0) { handle_node(node, tag); } else { char * text = (char *)xmlGetProp(node, (const xmlChar *)"title"); if (text) { if (newtag.length() > 0) { newtag.append("/"); } newtag.append(text); xmlFree(text); } } } rec_find_rss_outlines(node->children, newtag); node = node->next; } } std::string opml_urlreader::get_source() { return cfg->get_configvalue("opml-url"); } const char * opml_urlreader::get_auth() { return NULL; } } newsbeuter-2.7/src/urlview_formaction.cpp000066400000000000000000000064611220711462700207670ustar00rootroot00000000000000#include #include #include #include #include #include #include namespace newsbeuter { /* * The urlview_formaction is probably the simplest dialog of all. It * displays a list of URLs, and makes it possible to open the URLs * in a browser or to bookmark them. */ urlview_formaction::urlview_formaction(view * vv, std::string formstr) : formaction(vv, formstr), quit(false) { } urlview_formaction::~urlview_formaction() { } void urlview_formaction::process_operation(operation op, bool /* automatic */, std::vector * /* args */) { bool hardquit = false; switch (op) { case OP_OPEN: { std::string posstr = f->get("feedpos"); if (posstr.length() > 0) { std::istringstream is(posstr); unsigned int idx; is >> idx; v->set_status(_("Starting browser...")); v->open_in_browser(links[idx].first); v->set_status(""); } else { v->show_error(_("No link selected!")); } } break; case OP_BOOKMARK: { std::string posstr = f->get("feedpos"); if (posstr.length() > 0) { std::istringstream is(posstr); unsigned int idx; is >> idx; this->start_bookmark_qna("", links[idx].first, ""); } else { v->show_error(_("No link selected!")); } } break; case OP_1: case OP_2: case OP_3: case OP_4: case OP_5: case OP_6: case OP_7: case OP_8: case OP_9: case OP_0: { unsigned int idx = op - OP_1; if(idx < links.size()) { v->set_status(_("Starting browser...")); v->open_in_browser(links[idx].first); v->set_status(""); } } break; case OP_QUIT: quit = true; break; case OP_HARDQUIT: hardquit = true; break; default: // nothing break; } if (hardquit) { while (v->formaction_stack_size() > 0) { v->pop_current_formaction(); } } else if (quit) { v->pop_current_formaction(); } } void urlview_formaction::prepare() { if (do_redraw) { listformatter listfmt; unsigned int i=0; for (std::vector::iterator it = links.begin(); it != links.end(); ++it, ++i) { listfmt.add_line(utils::strprintf("%2u %s",i+1,it->first.c_str()), i); } f->modify("urls","replace_inner", listfmt.format_list()); } } void urlview_formaction::init() { v->set_status(""); std::string viewwidth = f->get("urls:w"); std::istringstream is(viewwidth); unsigned int width; is >> width; fmtstr_formatter fmt; fmt.register_fmt('N', PROGRAM_NAME); fmt.register_fmt('V', PROGRAM_VERSION); f->set("head", fmt.do_format(v->get_cfg()->get_configvalue("urlview-title-format"), width)); do_redraw = true; quit = false; set_keymap_hints(); } keymap_hint_entry * urlview_formaction::get_keymap_hint() { static keymap_hint_entry hints[] = { { OP_QUIT, _("Quit") }, { OP_OPEN, _("Open in Browser") }, { OP_BOOKMARK, _("Save Bookmark") }, { OP_NIL, NULL } }; return hints; } void urlview_formaction::handle_cmdline(const std::string& cmd) { unsigned int idx = 0; if (1==sscanf(cmd.c_str(),"%u",&idx)) { if (idx < 1 || idx > links.size()) { v->show_error(_("Invalid position!")); } else { f->set("feedpos", utils::to_string(idx-1)); } } else { formaction::handle_cmdline(cmd); } } std::string urlview_formaction::title() { return _("URLs"); } } newsbeuter-2.7/src/utils.cpp000066400000000000000000000632511220711462700162110ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_GCRYPT #include #include #include #include GCRY_THREAD_OPTION_PTHREAD_IMPL; #endif #if HAVE_OPENSSL #include #endif namespace newsbeuter { std::vector utils::tokenize_quoted(const std::string& str, std::string delimiters) { /* * This function tokenizes strings, obeying quotes and throwing away comments that start * with a '#'. * * e.g. line: foo bar "foo bar" "a test" * is parsed to 4 elements: * [0]: foo * [1]: bar * [2]: foo bar * [3]: a test * * e.g. line: yes great "x\ny" # comment * is parsed to 3 elements: * [0]: yes * [1]: great * [2]: x * y * * \", \r, \n, \t and \v are replaced with the literals that you know from C/C++ strings. * */ bool attach_backslash = true; std::vector tokens; std::string::size_type last_pos = str.find_first_not_of(delimiters, 0); std::string::size_type pos = last_pos; while (pos != std::string::npos && last_pos != std::string::npos) { if (str[last_pos] == '#') // stop as soon as we found a comment break; if (str[last_pos] == '"') { ++last_pos; pos = last_pos; int backslash_count = 0; while (pos < str.length() && (str[pos] != '"' || (backslash_count%2))) { if (str[pos] == '\\') { ++backslash_count; } else { backslash_count = 0; } ++pos; } if (pos >= str.length()) { pos = std::string::npos; std::string token; while (last_pos < str.length()) { if (str[last_pos] == '\\') { if (str[last_pos-1] == '\\') { if (attach_backslash) { token.append("\\"); } attach_backslash = !attach_backslash; } } else { if (str[last_pos-1] == '\\') { append_escapes(token, str[last_pos]); } else { token.append(1, str[last_pos]); } } ++last_pos; } tokens.push_back(token); } else { std::string token; while (last_pos < pos) { if (str[last_pos] == '\\') { if (str[last_pos-1] == '\\') { if (attach_backslash) { token.append("\\"); } attach_backslash = !attach_backslash; } } else { if (str[last_pos-1] == '\\') { append_escapes(token, str[last_pos]); } else { token.append(1, str[last_pos]); } } ++last_pos; } tokens.push_back(token); ++pos; } } else { pos = str.find_first_of(delimiters, last_pos); tokens.push_back(str.substr(last_pos, pos - last_pos)); } last_pos = str.find_first_not_of(delimiters, pos); } return tokens; } std::vector utils::tokenize(const std::string& str, std::string delimiters) { /* * This function tokenizes a string by the delimiters. Plain and simple. */ std::vector tokens; std::string::size_type last_pos = str.find_first_not_of(delimiters, 0); std::string::size_type pos = str.find_first_of(delimiters, last_pos); while (std::string::npos != pos || std::string::npos != last_pos) { tokens.push_back(str.substr(last_pos, pos - last_pos)); last_pos = str.find_first_not_of(delimiters, pos); pos = str.find_first_of(delimiters, last_pos); } return tokens; } std::vector utils::wtokenize(const std::wstring& str, std::wstring delimiters) { /* * This function tokenizes a string by the delimiters. Plain and simple. */ std::vector tokens; std::wstring::size_type last_pos = str.find_first_not_of(delimiters, 0); std::wstring::size_type pos = str.find_first_of(delimiters, last_pos); while (std::string::npos != pos || std::string::npos != last_pos) { tokens.push_back(str.substr(last_pos, pos - last_pos)); last_pos = str.find_first_not_of(delimiters, pos); pos = str.find_first_of(delimiters, last_pos); } return tokens; } std::vector utils::tokenize_spaced(const std::string& str, std::string delimiters) { std::vector tokens; std::string::size_type last_pos = str.find_first_not_of(delimiters, 0); std::string::size_type pos = str.find_first_of(delimiters, last_pos); if (last_pos != 0) { tokens.push_back(std::string(" ")); } while (std::string::npos != pos || std::string::npos != last_pos) { tokens.push_back(str.substr(last_pos, pos - last_pos)); last_pos = str.find_first_not_of(delimiters, pos); if (last_pos > pos) tokens.push_back(std::string(" ")); pos = str.find_first_of(delimiters, last_pos); } return tokens; } std::vector utils::tokenize_nl(const std::string& str, std::string delimiters) { std::vector tokens; std::string::size_type last_pos = str.find_first_not_of(delimiters, 0); std::string::size_type pos = str.find_first_of(delimiters, last_pos); unsigned int i; LOG(LOG_DEBUG,"utils::tokenize_nl: last_pos = %u",last_pos); if (last_pos != std::string::npos) { for (i=0;i(getpid()); // locking successful -> truncate file and write own PID into it ftruncate(fd, 0); write(fd, pidtext.c_str(), pidtext.length()); return true; } // locking was not successful -> read PID of locking process from it fd = ::open(lock_file.c_str(), O_RDONLY); if (fd >= 0) { char buf[32]; int len = read(fd, buf, sizeof(buf)-1); unsigned int upid = 0; buf[len] = '\0'; sscanf(buf, "%u", &upid); pid = upid; close(fd); } return false; } std::string utils::convert_text(const std::string& text, const std::string& tocode, const std::string& fromcode) { std::string result; if (strcasecmp(tocode.c_str(), fromcode.c_str())==0) return text; iconv_t cd = ::iconv_open((tocode + "//TRANSLIT").c_str(), fromcode.c_str()); if (cd == reinterpret_cast(-1)) return result; size_t inbytesleft; size_t outbytesleft; /* * of all the Unix-like systems around there, only Linux/glibc seems to * come with a SuSv3-conforming iconv implementation. */ #if !(__linux) && !defined(__GLIBC__) && !defined(__APPLE__) const char * inbufp; #else char * inbufp; #endif char outbuf[16]; char * outbufp = outbuf; outbytesleft = sizeof(outbuf); inbufp = const_cast(text.c_str()); // evil, but spares us some trouble inbytesleft = strlen(inbufp); do { char * old_outbufp = outbufp; int rc = ::iconv(cd, &inbufp, &inbytesleft, &outbufp, &outbytesleft); if (-1 == rc) { switch (errno) { case E2BIG: result.append(old_outbufp, outbufp - old_outbufp); outbufp = outbuf; outbytesleft = sizeof(outbuf); inbufp += strlen(inbufp) - inbytesleft; inbytesleft = strlen(inbufp); break; case EILSEQ: case EINVAL: result.append(old_outbufp, outbufp - old_outbufp); result.append("?"); inbufp += strlen(inbufp) - inbytesleft + 1; inbytesleft = strlen(inbufp); break; default: break; } } else { result.append(old_outbufp, outbufp - old_outbufp); } } while (inbytesleft > 0); iconv_close(cd); return result; } std::string utils::get_command_output(const std::string& cmd) { FILE * f = popen(cmd.c_str(), "r"); std::string buf; char cbuf[1024]; if (f) { size_t s; while ((s = fread(cbuf, 1, sizeof(cbuf), f)) > 0) { buf.append(cbuf, s); } pclose(f); } return buf; } void utils::extract_filter(const std::string& line, std::string& filter, std::string& url) { std::string::size_type pos = line.find_first_of(":", 0); std::string::size_type pos1 = line.find_first_of(":", pos + 1); filter = line.substr(pos+1, pos1 - pos - 1); pos = pos1; url = line.substr(pos+1, line.length() - pos); LOG(LOG_DEBUG, "utils::extract_filter: %s -> filter: %s url: %s", line.c_str(), filter.c_str(), url.c_str()); } static size_t my_write_data(void *buffer, size_t size, size_t nmemb, void *userp) { std::string * pbuf = static_cast(userp); pbuf->append(static_cast(buffer), size * nmemb); return size * nmemb; } std::string utils::retrieve_url(const std::string& url, configcontainer * cfgcont, const char * authinfo, const std::string* postdata) { std::string buf; CURL * easyhandle = curl_easy_init(); set_common_curl_options(easyhandle, cfgcont); curl_easy_setopt(easyhandle, CURLOPT_URL, url.c_str()); curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, my_write_data); curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, &buf); if(postdata != NULL) { curl_easy_setopt(easyhandle, CURLOPT_POST, 1); curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, postdata->c_str()); } if (authinfo) { curl_easy_setopt(easyhandle, CURLOPT_HTTPAUTH, get_auth_method(cfgcont->get_configvalue("http-auth-method"))); curl_easy_setopt(easyhandle, CURLOPT_USERPWD, authinfo); } curl_easy_perform(easyhandle); curl_easy_cleanup(easyhandle); if(postdata != NULL) { LOG(LOG_DEBUG, "utils::retrieve_url(%s)[%s]: %s", url.c_str(), postdata->c_str(), buf.c_str()); } else { LOG(LOG_DEBUG, "utils::retrieve_url(%s)[-]: %s", url.c_str(), buf.c_str()); } return buf; } void utils::run_command(const std::string& cmd, const std::string& input) { int rc = fork(); switch (rc) { case -1: break; case 0: { // child: int fd = ::open("/dev/null", O_RDWR); close(0); close(1); close(2); dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); LOG(LOG_DEBUG, "utils::run_command: %s '%s'", cmd.c_str(), input.c_str()); execlp(cmd.c_str(), cmd.c_str(), input.c_str(), NULL); LOG(LOG_DEBUG, "utils::run_command: execlp of %s failed: %s", cmd.c_str(), strerror(errno)); exit(1); } default: break; } } std::string utils::run_program(char * argv[], const std::string& input) { std::string buf; int ipipe[2]; int opipe[2]; pipe(ipipe); pipe(opipe); int rc = fork(); switch (rc) { case -1: break; case 0: { // child: close(ipipe[1]); close(opipe[0]); dup2(ipipe[0], 0); dup2(opipe[1], 1); close(2); int errfd = ::open("/dev/null", O_WRONLY); if (errfd != -1) dup2(errfd, 2); execvp(argv[0], argv); exit(1); } break; default: { close(ipipe[0]); close(opipe[1]); write(ipipe[1], input.c_str(), input.length()); close(ipipe[1]); char cbuf[1024]; int rc2; while ((rc2 = read(opipe[0], cbuf, sizeof(cbuf))) > 0) { buf.append(cbuf, rc2); } close(opipe[0]); } break; } return buf; } std::string utils::resolve_tilde(const std::string& str) { const char * homedir; std::string filepath; if (!(homedir = ::getenv("HOME"))) { struct passwd * spw = ::getpwuid(::getuid()); if (spw) { homedir = spw->pw_dir; } else { homedir = ""; } } if (strcmp(homedir,"")!=0) { if (str == "~") { filepath.append(homedir); } else if (str.substr(0,2) == "~/") { filepath.append(homedir); filepath.append(1,'/'); filepath.append(str.substr(2,str.length()-2)); } else { filepath.append(str); } } else { filepath.append(str); } return filepath; } std::string utils::replace_all(std::string str, const std::string& from, const std::string& to) { std::string::size_type s = str.find(from); while (s != std::string::npos) { str.replace(s,from.length(), to); s = str.find(from, s + to.length()); } return str; } std::wstring utils::utf8str2wstr(const std::string& utf8str) { stfl_ipool * pool = stfl_ipool_create("utf-8"); std::wstring wstr = stfl_ipool_towc(pool, utf8str.c_str()); stfl_ipool_destroy(pool); return wstr; } std::wstring utils::str2wstr(const std::string& str) { const char * codeset = nl_langinfo(CODESET); struct stfl_ipool * ipool = stfl_ipool_create(codeset); std::wstring result = stfl_ipool_towc(ipool, str.c_str()); stfl_ipool_destroy(ipool); return result; } std::string utils::wstr2str(const std::wstring& wstr) { std::string codeset = nl_langinfo(CODESET); codeset.append("//TRANSLIT"); struct stfl_ipool * ipool = stfl_ipool_create(codeset.c_str()); std::string result = stfl_ipool_fromwc(ipool, wstr.c_str()); stfl_ipool_destroy(ipool); return result; } template std::string utils::to_string(T var) { std::stringstream ret; ret << var; return ret.str(); } // to avoid linker errors template std::string utils::to_string(int var); template std::string utils::to_string(unsigned long var); template std::string utils::to_string(unsigned int var); std::string utils::absolute_url(const std::string& url, const std::string& link) { xmlChar * newurl = xmlBuildURI((const xmlChar *)link.c_str(), (const xmlChar *)url.c_str()); std::string retval; if (newurl) { retval = (const char *)newurl; xmlFree(newurl); } else { retval = link; } return retval; } std::string utils::strprintf(const char * format, ...) { if (!format) return std::string(); char buffer[1024]; va_list ap; va_start(ap, format); unsigned int len = vsnprintf(buffer, sizeof(buffer), format, ap)+1; va_end(ap); if (len <= sizeof(buffer)) return buffer; va_start(ap, format); char * buf = new char[len]; vsnprintf(buf, len, format, ap); va_end(ap); std::string ret(buf); delete[] buf; return ret; } std::string utils::get_useragent(configcontainer * cfgcont) { std::string ua_pref = cfgcont->get_configvalue("user-agent"); if (ua_pref.length() == 0) { struct utsname buf; uname(&buf); if (strcmp(buf.sysname, "Darwin") == 0) { /* Assume it is a Mac from the last decade or at least Mac-like */ const char* PROCESSOR = ""; if (strcmp(buf.machine, "x86_64") == 0 || strcmp(buf.machine, "i386") == 0) { PROCESSOR = "Intel "; } return utils::strprintf("%s/%s (Macintosh; %sMac OS X)", PROGRAM_NAME, PROGRAM_VERSION, PROCESSOR); } return utils::strprintf("%s/%s (%s %s)", PROGRAM_NAME, PROGRAM_VERSION, buf.sysname, buf.machine); } return ua_pref; } unsigned int utils::to_u(const std::string& str) { std::istringstream is(str); unsigned int u = 0; is >> u; return u; } scope_measure::scope_measure(const std::string& func, loglevel ll) : lvl(ll) { funcname = func; gettimeofday(&tv1, NULL); } void scope_measure::stopover(const std::string& son) { gettimeofday(&tv2, NULL); unsigned long diff = (((tv2.tv_sec - tv1.tv_sec) * 1000000) + tv2.tv_usec) - tv1.tv_usec; LOG(lvl, "scope_measure: function `%s' (stop over `%s') took %lu.%06lu s so far", funcname.c_str(), son.c_str(), diff / 1000000, diff % 1000000); } scope_measure::~scope_measure() { gettimeofday(&tv2, NULL); unsigned long diff = (((tv2.tv_sec - tv1.tv_sec) * 1000000) + tv2.tv_usec) - tv1.tv_usec; LOG(LOG_INFO, "scope_measure: function `%s' took %lu.%06lu s", funcname.c_str(), diff / 1000000, diff % 1000000); } void utils::append_escapes(std::string& str, char c) { switch (c) { case 'n': str.append("\n"); break; case 'r': str.append("\r"); break; case 't': str.append("\t"); break; case '"': str.append("\""); break; case '\\': break; default: str.append(1, c); break; } } bool utils::is_valid_color(const std::string& color) { const char * colors[] = { "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", "default", NULL }; for (unsigned int i=0;colors[i];i++) { if (color == colors[i]) return true; } if (strncmp(color.c_str(), "color", 5)==0) return true; return false; } bool utils::is_valid_attribute(const std::string& attrib) { const char * attribs[] = { "standout", "underline", "reverse", "blink", "dim", "bold", "protect", "invis", "default", NULL }; for (unsigned int i=0;attribs[i];i++) { if (attrib == attribs[i]) return true; } return false; } std::vector > utils::partition_indexes(unsigned int start, unsigned int end, unsigned int parts) { std::vector > partitions; unsigned int count = end - start + 1; unsigned int size = count / parts; for (unsigned int i=0;i(start, start + size - 1)); start += size; } partitions.push_back(std::pair(start, end)); return partitions; } size_t utils::strwidth(const std::string& str) { std::wstring wstr = str2wstr(str); int width = wcswidth(wstr.c_str(), wstr.length()); if (width < 1) // a non-printable character found? return wstr.length(); // return a sane width (which might be larger than necessary) return width; // exact width } size_t utils::strwidth_stfl(const std::string& str) { size_t reduce_count = 0; size_t len = str.length(); if (len > 1) { for (size_t idx=0;idx 1) { for (size_t idx=0;idx') { reduce_count += 3; idx += 3; } } } int width = wcswidth(str.c_str(), size); if (width < 0) { LOG(LOG_ERROR, "oh, oh, wcswidth just failed"); // : %ls", str.c_str()); return str.length() - reduce_count; } return width - reduce_count; } std::string utils::join(const std::vector& strings, const std::string& separator) { std::string result; for (std::vector::const_iterator it=strings.begin();it!=strings.end();++it) { result.append(*it); result.append(separator); } if (result.length() > 0) result.erase(result.length()-separator.length(), result.length()); return result; } bool utils::is_special_url(const std::string& url) { return url.substr(0,6) == "query:" || url.substr(0,7) == "filter:" || url.substr(0,5) == "exec:"; } bool utils::is_http_url(const std::string& url) { return url.substr(0,7) == "http://" || url.substr(0,8) == "https://"; } std::string utils::censor_url(const std::string& url) { std::string rv; if (url.length() > 0 && !utils::is_special_url(url)) { const char * myuri = url.c_str(); xmlURIPtr uri = xmlParseURI(myuri); if (uri) { if (uri->user) { xmlFree(uri->user); uri->user = (char *)xmlStrdup((const xmlChar *)"*:*"); } xmlChar * uristr = xmlSaveUri(uri); rv = (const char *)uristr; xmlFree(uristr); xmlFreeURI(uri); } else return url; } else { rv = url; } return rv; } std::string utils::quote_for_stfl(std::string str) { unsigned int len = str.length(); for (unsigned int i=0;i"); ++len; } } return str; } void utils::trim(std::string& str) { while (str.length() > 0 && ::isspace(str[0])) { str.erase(0,1); } trim_end(str); } void utils::trim_end(std::string& str) { std::string::size_type pos = str.length()-1; while (str.length()>0 && (str[pos] == '\n' || str[pos] == '\r')) { str.erase(pos); pos--; } } std::string utils::quote(const std::string& str) { std::string rv = replace_all(str, "\"", "\\\""); rv.insert(0, "\""); rv.append("\""); return rv; } unsigned int utils::get_random_value(unsigned int max) { static bool initialized = false; if (!initialized) { initialized = true; srand(~(time(NULL) ^ getpid() ^ getppid())); } return static_cast(rand() % max); } std::string utils::quote_if_necessary(const std::string& str) { std::string result; if (str.find_first_of(" ", 0) == std::string::npos) { result = str; } else { result = utils::replace_all(str, "\"", "\\\""); result.insert(0, "\""); result.append("\""); } return result; } void utils::set_common_curl_options(CURL * handle, configcontainer * cfg) { std::string proxy; std::string proxyauth; std::string proxyauthmethod; std::string proxytype; std::string useragent; std::string cookie_cache; unsigned int dl_timeout = 0; if (cfg) { if (cfg->get_configvalue_as_bool("use-proxy")) { proxy = cfg->get_configvalue("proxy"); proxyauth = cfg->get_configvalue("proxy-auth"); proxyauthmethod = cfg->get_configvalue("proxy-auth-method"); proxytype = cfg->get_configvalue("proxy-type"); } useragent = utils::get_useragent(cfg); dl_timeout = cfg->get_configvalue_as_int("download-timeout"); cookie_cache = cfg->get_configvalue("cookie-cache"); } curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(handle, CURLOPT_ENCODING, "gzip, deflate"); curl_easy_setopt(handle, CURLOPT_TIMEOUT, dl_timeout); if (proxy != "") curl_easy_setopt(handle, CURLOPT_PROXY, proxy.c_str()); if (proxyauth != "") { curl_easy_setopt(handle, CURLOPT_PROXYAUTH, get_auth_method(proxyauthmethod)); curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, proxyauth.c_str()); } if (proxytype != "") { LOG(LOG_DEBUG, "utils::set_common_curl_options: proxytype = %s", proxytype.c_str()); curl_easy_setopt(handle, CURLOPT_PROXYTYPE, get_proxy_type(proxytype)); } curl_easy_setopt(handle, CURLOPT_USERAGENT, useragent.c_str()); curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(handle, CURLOPT_MAXREDIRS, 10); curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1); if (cookie_cache != "") { curl_easy_setopt(handle, CURLOPT_COOKIEFILE, cookie_cache.c_str()); curl_easy_setopt(handle, CURLOPT_COOKIEJAR, cookie_cache.c_str()); } } std::string utils::get_content(xmlNode * node) { std::string retval; if (node) { xmlChar * content = xmlNodeGetContent(node); if (content) { retval = (const char *)content; xmlFree(content); } } return retval; } std::string utils::get_prop(xmlNode * node, const char * prop, const char * ns) { std::string retval; if (node) { xmlChar * value; if (ns) value = xmlGetProp(node, (xmlChar *)prop); else value = xmlGetNsProp(node, (xmlChar *)prop, (xmlChar *)ns); if (value) { retval = (const char*)value; xmlFree(value); } } return retval; } unsigned long utils::get_auth_method(const std::string& type) { if (type == "any") return CURLAUTH_ANY; if (type == "basic") return CURLAUTH_BASIC; if (type == "digest") return CURLAUTH_DIGEST; #ifdef CURLAUTH_DIGEST_IE if (type == "digest_ie") return CURLAUTH_DIGEST_IE; #else # warning "proxy-auth-method digest_ie not added due to libcurl older than 7.19.3" #endif if (type == "gssnegotiate") return CURLAUTH_GSSNEGOTIATE; if (type == "ntlm") return CURLAUTH_NTLM; if (type == "anysafe") return CURLAUTH_ANYSAFE; if (type != "") { LOG(LOG_USERERROR, "you configured an invalid proxy authentication method: %s", type.c_str()); } return CURLAUTH_ANY; } curl_proxytype utils::get_proxy_type(const std::string& type) { if (type == "http") return CURLPROXY_HTTP; if (type == "socks4") return CURLPROXY_SOCKS4; if (type == "socks5") return CURLPROXY_SOCKS5; #ifdef CURLPROXY_SOCKS4A if (type == "socks4a") return CURLPROXY_SOCKS4A; #endif if (type != "") { LOG(LOG_USERERROR, "you configured an invalid proxy type: %s", type.c_str()); } return CURLPROXY_HTTP; } std::string utils::escape_url(const std::string& url) { return replace_all(replace_all(url,"?","%3F"), "&", "%26"); } std::string utils::unescape_url(const std::string& url) { return replace_all(replace_all(url,"%3F","?"), "%26", "&"); } std::wstring utils::clean_nonprintable_characters(std::wstring text) { for (size_t idx=0;idx= openssl_mutexes_size) { LOG(LOG_ERROR,"openssl_mth_locking_function: index is out of bounds (called by %s:%d)", file, line); return; } if (mode & CRYPTO_LOCK) { LOG(LOG_DEBUG, "OpenSSL lock %d: %s:%d", n, file, line); openssl_mutexes[n].lock(); } else { LOG(LOG_DEBUG, "OpenSSL unlock %d: %s:%d", n, file, line); openssl_mutexes[n].unlock(); } } static unsigned long openssl_mth_id_function(void) { return (unsigned long)pthread_self(); } #endif void utils::initialize_ssl_implementation(void) { #if HAVE_OPENSSL openssl_mutexes_size = CRYPTO_num_locks(); openssl_mutexes = new mutex[openssl_mutexes_size]; CRYPTO_set_id_callback(openssl_mth_id_function); CRYPTO_set_locking_callback(openssl_mth_locking_function); #endif #if HAVE_GCRYPT gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); gnutls_global_init(); #endif } } newsbeuter-2.7/src/view.cpp000066400000000000000000001037431220711462700160240ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern "C" { #include } #include #include #include #include #include namespace newsbeuter { view::view(controller * c) : ctrl(c), cfg(0), keys(0), mtx(0), current_formaction(0), is_inside_qna(false), is_inside_cmdline(false), tab_count(0) { mtx = new mutex(); } view::~view() { stfl::reset(); delete mtx; } void view::set_config_container(configcontainer * cfgcontainer) { cfg = cfgcontainer; } void view::set_keymap(keymap * k) { keys = k; } void view::update_bindings() { for (std::vector >::iterator it=formaction_stack.begin();it!=formaction_stack.end();++it) { if (*it) { set_bindings(*it); } } } void view::set_bindings(std::tr1::shared_ptr fa) { std::string upkey("** "); upkey.append(keys->getkey(OP_SK_UP, fa->id())); std::string downkey("** "); downkey.append(keys->getkey(OP_SK_DOWN, fa->id())); fa->get_form()->set("bind_up", upkey); fa->get_form()->set("bind_down", downkey); std::string pgupkey; std::string pgdownkey; if (fa->id() == "article" || fa->id() == "help") { pgupkey.append("** b "); pgdownkey.append("** SPACE "); } else { pgupkey.append("** "); pgdownkey.append("** "); } pgupkey.append(keys->getkey(OP_SK_PGUP, fa->id())); pgdownkey.append(keys->getkey(OP_SK_PGDOWN, fa->id())); fa->get_form()->set("bind_page_up", pgupkey); fa->get_form()->set("bind_page_down", pgdownkey); std::string homekey("** "); homekey.append(keys->getkey(OP_SK_HOME, fa->id())); std::string endkey("** "); endkey.append(keys->getkey(OP_SK_END, fa->id())); fa->get_form()->set("bind_home", homekey); fa->get_form()->set("bind_end", endkey); } std::tr1::shared_ptr view::get_current_formaction() { if (formaction_stack.size() > 0 && current_formaction < formaction_stack.size()) { return formaction_stack[current_formaction]; } return std::tr1::shared_ptr(); } void view::set_status_unlocked(const std::string& msg) { if (formaction_stack.size() > 0 && get_current_formaction() != NULL) { std::tr1::shared_ptr form = get_current_formaction()->get_form(); if (form != NULL) { form->set("msg",msg); form->run(-1); } else { LOG(LOG_ERROR, "view::set_status_unlocked: form for formaction of type %s is NULL!", get_current_formaction()->id().c_str()); } } } void view::set_status(const std::string& msg) { scope_mutex lock(mtx); set_status_unlocked(msg); } void view::show_error(const std::string& msg) { set_status(msg); } void view::run() { bool have_macroprefix = false; std::vector macrocmds; // create feedlist std::tr1::shared_ptr feedlist(new feedlist_formaction(this, feedlist_str)); set_bindings(feedlist); feedlist->set_regexmanager(rxman); feedlist->set_tags(tags); apply_colors(feedlist); formaction_stack.push_back(feedlist); current_formaction = formaction_stack_size() - 1; get_current_formaction()->init(); stfl::reset(); /* * This is the main "event" loop of newsbeuter. */ while (formaction_stack.size() > 0) { // first, we take the current formaction. std::tr1::shared_ptr fa = get_current_formaction(); // we signal "oh, you will receive an operation soon" fa->prepare(); if (!macrocmds.empty()) { // if there is any macro command left to process, we do so fa->get_form()->run(-1); fa->process_op(macrocmds[0].op, true, ¯ocmds[0].args); macrocmds.erase(macrocmds.begin()); // remove first macro command, since it has already been processed } else { // we then receive the event and ignore timeouts. const char * event = fa->get_form()->run(60000); if (ctrl_c_hit) { ctrl_c_hit = 0; cancel_input(fa); if (!get_cfg()->get_configvalue_as_bool("confirm-exit") || confirm(_("Do you really want to quit (y:Yes n:No)? "), _("yn")) == *_("y")) { stfl::reset(); utils::remove_fs_lock(lock_file); ::exit(EXIT_FAILURE); } } if (!event || strcmp(event,"TIMEOUT")==0) { if (fa->id() == "article") std::tr1::dynamic_pointer_cast(fa)->update_percent(); continue; } if (is_inside_qna) { LOG(LOG_DEBUG, "view::run: we're inside QNA input"); if (is_inside_cmdline && strcmp(event, "TAB")==0) { handle_cmdline_completion(fa); continue; } if (strcmp(event, "^U")==0) { clear_line(fa); continue; } else if (strcmp(event, "^K")==0) { clear_eol(fa); continue; } else if (strcmp(event, "^G")==0) { cancel_input(fa); continue; } else if (strcmp(event, "^W")==0) { delete_word(fa); continue; } } LOG(LOG_DEBUG, "view::run: event = %s", event); // retrieve operation code through the keymap operation op; if (have_macroprefix) { have_macroprefix = false; LOG(LOG_DEBUG, "view::run: running macro `%s'", event); macrocmds = keys->get_macro(event); set_status(""); } else { op = keys->get_operation(event, fa->id()); LOG(LOG_DEBUG, "view::run: event = %s op = %u", event, op); if (OP_MACROPREFIX == op) { have_macroprefix = true; set_status("macro-"); } // now we handle the operation to the formaction. fa->process_op(op); } } } stfl::reset(); } std::string view::run_modal(std::tr1::shared_ptr f, const std::string& value) { f->init(); unsigned int stacksize = formaction_stack.size(); formaction_stack.push_back(f); current_formaction = formaction_stack_size() - 1; while (formaction_stack.size() > stacksize) { std::tr1::shared_ptr fa = get_current_formaction(); fa->prepare(); const char * event = fa->get_form()->run(1000); LOG(LOG_DEBUG, "view::run: event = %s", event); if (!event || strcmp(event,"TIMEOUT")==0) continue; operation op = keys->get_operation(event, fa->id()); if (OP_REDRAW == op) { stfl::reset(); continue; } fa->process_op(op); } if (value == "") return ""; else return f->get_value(value); } std::string view::get_filename_suggestion(const std::string& s) { /* * With this function, we generate normalized filenames for saving * articles to files. */ std::string retval; for (unsigned int i=0;i %s", s.c_str(), retval.c_str()); return retval; } void view::push_empty_formaction() { formaction_stack.push_back(std::tr1::shared_ptr()); current_formaction = formaction_stack_size() - 1; } void view::open_in_pager(const std::string& filename) { formaction_stack.push_back(std::tr1::shared_ptr()); current_formaction = formaction_stack_size() - 1; std::string cmdline; std::string pager = cfg->get_configvalue("pager"); if (pager.find("%f") != std::string::npos) { fmtstr_formatter fmt; fmt.register_fmt('f', filename); cmdline = fmt.do_format(pager, 0); } else { const char * env_pager = NULL; if (pager != "") cmdline.append(pager); else if ((env_pager = getenv("PAGER")) != NULL) cmdline.append(env_pager); else cmdline.append("more"); cmdline.append(" "); cmdline.append(filename); } stfl::reset(); LOG(LOG_DEBUG, "view::open_in_browser: running `%s'", cmdline.c_str()); ::system(cmdline.c_str()); pop_current_formaction(); } void view::open_in_browser(const std::string& url) { formaction_stack.push_back(std::tr1::shared_ptr()); current_formaction = formaction_stack_size() - 1; std::string cmdline; std::string browser = cfg->get_configvalue("browser"); if (browser.find("%u") != std::string::npos) { fmtstr_formatter fmt; std::string newurl; newurl = utils::replace_all(url, "'", "%27"); newurl.insert(0, "'"); newurl.append("'"); fmt.register_fmt('u', newurl); cmdline = fmt.do_format(browser, 0); } else { if (browser != "") cmdline.append(browser); else cmdline.append("lynx"); cmdline.append(" '"); cmdline.append(utils::replace_all(url,"'", "%27")); cmdline.append("'"); } stfl::reset(); LOG(LOG_DEBUG, "view::open_in_browser: running `%s'", cmdline.c_str()); ::system(cmdline.c_str()); pop_current_formaction(); } void view::update_visible_feeds(std::vector > feeds) { try { if (formaction_stack_size() > 0) { scope_mutex lock(mtx); std::tr1::shared_ptr feedlist = std::tr1::dynamic_pointer_cast(formaction_stack[0]); feedlist->update_visible_feeds(feeds); } } catch (const matcherexception& e) { set_status(utils::strprintf(_("Error: applying the filter failed: %s"), e.what())); LOG(LOG_DEBUG, "view::update_visible_feeds: inside catch: %s", e.what()); } } void view::set_feedlist(std::vector > feeds) { try { scope_mutex lock(mtx); for (std::vector >::iterator it=feeds.begin();it!=feeds.end();++it) { if ((*it)->rssurl().substr(0,6) != "query:") { (*it)->set_feedptrs(*it); } } if (formaction_stack_size() > 0) { std::tr1::shared_ptr feedlist = std::tr1::dynamic_pointer_cast(formaction_stack[0]); feedlist->set_feedlist(feeds); } } catch (const matcherexception& e) { set_status(utils::strprintf(_("Error: applying the filter failed: %s"), e.what())); } } void view::set_tags(const std::vector& t) { tags = t; } void view::push_searchresult(std::tr1::shared_ptr feed, const std::string& phrase) { assert(feed != NULL); LOG(LOG_DEBUG, "view::push_searchresult: pushing search result"); if (feed->items().size() > 0) { std::tr1::shared_ptr searchresult(new itemlist_formaction(this, itemlist_str)); set_bindings(searchresult); searchresult->set_regexmanager(rxman); searchresult->set_feed(feed); searchresult->set_show_searchresult(true); searchresult->set_searchphrase(phrase); apply_colors(searchresult); searchresult->set_parent_formaction(get_current_formaction()); searchresult->init(); formaction_stack.push_back(searchresult); current_formaction = formaction_stack_size() - 1; } else { show_error(_("Error: feed contains no items!")); } } void view::push_itemlist(std::tr1::shared_ptr feed) { assert(feed != NULL); feed->purge_deleted_items(); prepare_query_feed(feed); if (feed->items().size() > 0) { std::tr1::shared_ptr itemlist(new itemlist_formaction(this, itemlist_str)); set_bindings(itemlist); itemlist->set_regexmanager(rxman); itemlist->set_feed(feed); itemlist->set_show_searchresult(false); apply_colors(itemlist); itemlist->set_parent_formaction(get_current_formaction()); itemlist->init(); formaction_stack.push_back(itemlist); current_formaction = formaction_stack_size() - 1; } else { show_error(_("Error: feed contains no items!")); } } void view::push_itemlist(unsigned int pos) { std::tr1::shared_ptr feed = ctrl->get_feed(pos); LOG(LOG_DEBUG, "view::push_itemlist: retrieved feed at position %d", pos); push_itemlist(feed); if (feed->items().size() > 0) { std::tr1::shared_ptr itemlist = std::tr1::dynamic_pointer_cast(get_current_formaction()); itemlist->set_pos(pos); } } void view::push_itemview(std::tr1::shared_ptr f, const std::string& guid, const std::string& searchphrase) { std::string pager; if ((pager = cfg->get_configvalue("pager")) == "internal") { std::tr1::shared_ptr itemlist = std::tr1::dynamic_pointer_cast(get_current_formaction()); assert(itemlist != NULL); std::tr1::shared_ptr itemview(new itemview_formaction(this, itemlist, itemview_str)); set_bindings(itemview); itemview->set_regexmanager(rxman); itemview->set_feed(f); itemview->set_guid(guid); itemview->set_parent_formaction(get_current_formaction()); if (searchphrase.length() > 0) itemview->set_highlightphrase(searchphrase); apply_colors(itemview); itemview->init(); formaction_stack.push_back(itemview); current_formaction = formaction_stack_size() - 1; } else { std::string filename = get_ctrl()->write_temporary_item(f->get_item_by_guid(guid)); open_in_pager(filename); ::unlink(filename.c_str()); } } void view::view_dialogs() { if (get_current_formaction() != NULL && get_current_formaction()->id() != "dialogs") { std::tr1::shared_ptr dialogs(new dialogs_formaction(this, dialogs_str)); dialogs->set_parent_formaction(get_current_formaction()); apply_colors(dialogs); dialogs->init(); formaction_stack.push_back(dialogs); current_formaction = formaction_stack_size() - 1; } } void view::push_help() { std::tr1::shared_ptr helpview(new help_formaction(this, help_str)); set_bindings(helpview); apply_colors(helpview); helpview->set_context(get_current_formaction()->id()); helpview->set_parent_formaction(get_current_formaction()); helpview->init(); formaction_stack.push_back(helpview); current_formaction = formaction_stack_size() - 1; } void view::push_urlview(const std::vector& links) { std::tr1::shared_ptr urlview(new urlview_formaction(this, urlview_str)); set_bindings(urlview); apply_colors(urlview); urlview->set_parent_formaction(get_current_formaction()); urlview->init(); urlview->set_links(links); formaction_stack.push_back(urlview); current_formaction = formaction_stack_size() - 1; } std::string view::run_filebrowser(const std::string& default_filename, const std::string& dir) { std::tr1::shared_ptr filebrowser(new filebrowser_formaction(this, filebrowser_str)); set_bindings(filebrowser); apply_colors(filebrowser); filebrowser->set_dir(dir); filebrowser->set_default_filename(default_filename); filebrowser->set_parent_formaction(get_current_formaction()); return run_modal(filebrowser, "filenametext"); } std::string view::select_tag(const std::vector& tags) { std::tr1::shared_ptr selecttag(new select_formaction(this, selecttag_str)); set_bindings(selecttag); apply_colors(selecttag); selecttag->set_parent_formaction(get_current_formaction()); selecttag->set_type(select_formaction::SELECTTAG); selecttag->set_tags(tags); run_modal(selecttag, ""); return selecttag->get_selected_value(); } std::string view::select_filter(const std::vector& filters) { std::tr1::shared_ptr selecttag(new select_formaction(this, selecttag_str)); set_bindings(selecttag); apply_colors(selecttag); selecttag->set_parent_formaction(get_current_formaction()); selecttag->set_type(select_formaction::SELECTFILTER); selecttag->set_filters(filters); run_modal(selecttag, ""); return selecttag->get_selected_value(); } char view::confirm(const std::string& prompt, const std::string& charset) { LOG(LOG_DEBUG, "view::confirm: charset = %s", charset.c_str()); std::tr1::shared_ptr f = get_current_formaction(); formaction_stack.push_back(std::tr1::shared_ptr()); current_formaction = formaction_stack_size() - 1; f->get_form()->set("msg", prompt); char result = 0; do { const char * event = f->get_form()->run(0); LOG(LOG_DEBUG,"view::confirm: event = %s", event); if (!event) continue; if (strcmp(event, "ESC")==0 || strcmp(event, "ENTER")==0) { result = 0; LOG(LOG_DEBUG, "view::confirm: user pressed ESC or ENTER, we cancel confirmation dialog"); break; } result = keys->get_key(event); LOG(LOG_DEBUG, "view::confirm: key = %c (%u)", result, result); } while (!result || strchr(charset.c_str(), result)==NULL); f->get_form()->set("msg", ""); f->get_form()->run(-1); pop_current_formaction(); return result; } void view::notify_itemlist_change(std::tr1::shared_ptr feed) { for (std::vector >::iterator it=formaction_stack.begin();it!=formaction_stack.end();++it) { if (*it != NULL && (*it)->id() == "articlelist") { std::tr1::shared_ptr itemlist = std::tr1::dynamic_pointer_cast(*it); if (itemlist != NULL) { std::tr1::shared_ptr f = itemlist->get_feed(); if (f != NULL && f->rssurl() == feed->rssurl()) { itemlist->set_feed(feed); itemlist->set_redraw(true); } } } } } bool view::get_random_unread(itemlist_formaction * itemlist, itemview_formaction * itemview) { unsigned int feedpos; std::tr1::shared_ptr feedlist = std::tr1::dynamic_pointer_cast(formaction_stack[0]); if (!cfg->get_configvalue_as_bool("goto-next-feed")) { return false; } if (feedlist->jump_to_random_unread_feed(feedpos)) { LOG(LOG_DEBUG, "view::get_previous_unread: found feed with unread articles"); prepare_query_feed(feedlist->get_feed()); itemlist->set_feed(feedlist->get_feed()); itemlist->set_pos(feedpos); itemlist->init(); if (itemlist->jump_to_random_unread_item()) { if (itemview) { itemview->init(); itemview->set_feed(itemlist->get_feed()); itemview->set_guid(itemlist->get_guid()); } return true; } } return false; } bool view::get_previous_unread(itemlist_formaction * itemlist, itemview_formaction * itemview) { unsigned int feedpos; LOG(LOG_DEBUG, "view::get_previous_unread: trying to find previous unread"); std::tr1::shared_ptr feedlist = std::tr1::dynamic_pointer_cast(formaction_stack[0]); if (itemlist->jump_to_previous_unread_item(false)) { LOG(LOG_DEBUG, "view::get_previous_unread: found unread article in same feed"); if (itemview) { itemview->init(); itemview->set_feed(itemlist->get_feed()); itemview->set_guid(itemlist->get_guid()); } return true; } else if (cfg->get_configvalue_as_bool("goto-next-feed")==false) { LOG(LOG_DEBUG, "view::get_previous_unread: goto-next-feed = false"); show_error(_("No unread items.")); } else if (feedlist->jump_to_previous_unread_feed(feedpos)) { LOG(LOG_DEBUG, "view::get_previous_unread: found feed with unread articles"); prepare_query_feed(feedlist->get_feed()); itemlist->set_feed(feedlist->get_feed()); itemlist->set_pos(feedpos); itemlist->init(); if (itemlist->jump_to_previous_unread_item(true)) { if (itemview) { itemview->init(); itemview->set_feed(itemlist->get_feed()); itemview->set_guid(itemlist->get_guid()); } return true; } } return false; } bool view::get_next_unread_feed(itemlist_formaction * itemlist) { std::tr1::shared_ptr feedlist = std::tr1::dynamic_pointer_cast(formaction_stack[0]); unsigned int feedpos; assert(feedlist != NULL); if (feedlist->jump_to_next_unread_feed(feedpos)) { prepare_query_feed(feedlist->get_feed()); itemlist->set_feed(feedlist->get_feed()); itemlist->set_pos(feedpos); itemlist->init(); return true; } return false; } bool view::get_prev_unread_feed(itemlist_formaction * itemlist) { std::tr1::shared_ptr feedlist = std::tr1::dynamic_pointer_cast(formaction_stack[0]); unsigned int feedpos; assert(feedlist != NULL); if (feedlist->jump_to_previous_unread_feed(feedpos)) { prepare_query_feed(feedlist->get_feed()); itemlist->set_feed(feedlist->get_feed()); itemlist->set_pos(feedpos); itemlist->init(); return true; } return false; } bool view::get_next_unread(itemlist_formaction * itemlist, itemview_formaction * itemview) { unsigned int feedpos; std::tr1::shared_ptr feedlist = std::tr1::dynamic_pointer_cast(formaction_stack[0]); LOG(LOG_DEBUG, "view::get_next_unread: trying to find next unread"); if (itemlist->jump_to_next_unread_item(false)) { LOG(LOG_DEBUG, "view::get_next_unread: found unread article in same feed"); if (itemview) { itemview->init(); itemview->set_feed(itemlist->get_feed()); itemview->set_guid(itemlist->get_guid()); } return true; } else if (cfg->get_configvalue_as_bool("goto-next-feed")==false) { LOG(LOG_DEBUG, "view::get_next_unread: goto-next-feed = false"); show_error(_("No unread items.")); } else if (feedlist->jump_to_next_unread_feed(feedpos)) { LOG(LOG_DEBUG, "view::get_next_unread: found feed with unread articles"); prepare_query_feed(feedlist->get_feed()); itemlist->set_feed(feedlist->get_feed()); itemlist->set_pos(feedpos); itemlist->init(); if (itemlist->jump_to_next_unread_item(true)) { if (itemview) { itemview->init(); itemview->set_feed(itemlist->get_feed()); itemview->set_guid(itemlist->get_guid()); } return true; } } return false; } bool view::get_previous(itemlist_formaction * itemlist, itemview_formaction * itemview) { unsigned int feedpos; std::tr1::shared_ptr feedlist = std::tr1::dynamic_pointer_cast(formaction_stack[0]); if (itemlist->jump_to_previous_item(false)) { LOG(LOG_DEBUG, "view::get_previous: article in same feed"); if (itemview) { itemview->init(); itemview->set_feed(itemlist->get_feed()); itemview->set_guid(itemlist->get_guid()); } return true; } else if (cfg->get_configvalue_as_bool("goto-next-feed")==false) { LOG(LOG_DEBUG, "view::get_previous: goto-next-feed = false"); show_error(_("Already on first item.")); } else if (feedlist->jump_to_previous_feed(feedpos)) { LOG(LOG_DEBUG, "view::get_previous: previous feed"); prepare_query_feed(feedlist->get_feed()); itemlist->set_feed(feedlist->get_feed()); itemlist->set_pos(feedpos); itemlist->init(); if (itemlist->jump_to_previous_item(true)) { if (itemview) { itemview->init(); itemview->set_feed(itemlist->get_feed()); itemview->set_guid(itemlist->get_guid()); } return true; } } return false; } bool view::get_next(itemlist_formaction * itemlist, itemview_formaction * itemview) { unsigned int feedpos; std::tr1::shared_ptr feedlist = std::tr1::dynamic_pointer_cast(formaction_stack[0]); if (itemlist->jump_to_next_item(false)) { LOG(LOG_DEBUG, "view::get_next: article in same feed"); if (itemview) { itemview->init(); itemview->set_feed(itemlist->get_feed()); itemview->set_guid(itemlist->get_guid()); } return true; } else if (cfg->get_configvalue_as_bool("goto-next-feed")==false) { LOG(LOG_DEBUG, "view::get_next: goto-next-feed = false"); show_error(_("Already on last item.")); } else if (feedlist->jump_to_next_feed(feedpos)) { LOG(LOG_DEBUG, "view::get_next: next feed"); prepare_query_feed(feedlist->get_feed()); itemlist->set_feed(feedlist->get_feed()); itemlist->set_pos(feedpos); itemlist->init(); if (itemlist->jump_to_next_item(true)) { if (itemview) { itemview->init(); itemview->set_feed(itemlist->get_feed()); itemview->set_guid(itemlist->get_guid()); } return true; } } return false; } bool view::get_next_feed(itemlist_formaction * itemlist) { std::tr1::shared_ptr feedlist = std::tr1::dynamic_pointer_cast(formaction_stack[0]); unsigned int feedpos; assert(feedlist != NULL); if (feedlist->jump_to_next_feed(feedpos)) { prepare_query_feed(feedlist->get_feed()); itemlist->set_feed(feedlist->get_feed()); itemlist->set_pos(feedpos); itemlist->init(); return true; } return false; } bool view::get_prev_feed(itemlist_formaction * itemlist) { std::tr1::shared_ptr feedlist = std::tr1::dynamic_pointer_cast(formaction_stack[0]); unsigned int feedpos; assert(feedlist != NULL); if (feedlist->jump_to_previous_feed(feedpos)) { prepare_query_feed(feedlist->get_feed()); itemlist->set_feed(feedlist->get_feed()); itemlist->set_pos(feedpos); itemlist->init(); return true; } return false; } void view::prepare_query_feed(std::tr1::shared_ptr feed) { if (feed->rssurl().substr(0,6) == "query:") { LOG(LOG_DEBUG, "view::prepare_query_feed: %s", feed->rssurl().c_str()); set_status(_("Updating query feed...")); feed->update_items(ctrl->get_all_feeds()); feed->sort(cfg->get_configvalue("article-sort-order")); notify_itemlist_change(feed); set_status(""); } } void view::force_redraw() { std::tr1::shared_ptr fa = get_current_formaction(); if (fa != NULL) { fa->set_redraw(true); fa->prepare(); fa->get_form()->run(-1); } } void view::pop_current_formaction() { std::tr1::shared_ptr f = get_current_formaction(); std::vector >::iterator it=formaction_stack.begin(); for (unsigned int i=0;i 0) { // first, we set back the parent formactions of those who reference the formaction we just removed for (std::vector >::iterator it=formaction_stack.begin();it!=formaction_stack.end();++it) { if ((*it)->get_parent_formaction() == f) { (*it)->set_parent_formaction(formaction_stack[0]); } } // we set the new formaction based on the removed formaction's parent. unsigned int i=0; for (std::vector >::iterator it=formaction_stack.begin();it!=formaction_stack.end();++it,i++) { if (*it == f->get_parent_formaction()) { current_formaction = i; break; } } std::tr1::shared_ptr f = get_current_formaction(); if (f) { f->set_redraw(true); f->get_form()->set("msg",""); f->recalculate_form(); } } } void view::set_current_formaction(unsigned int pos) { remove_formaction(current_formaction); current_formaction = pos; } void view::remove_formaction(unsigned int pos) { std::tr1::shared_ptr f = formaction_stack[pos]; std::vector >::iterator it=formaction_stack.begin(); for (unsigned int i=0;i 0) { // we set back the parent formactions of those who reference the formaction we just removed for (std::vector >::iterator it=formaction_stack.begin();it!=formaction_stack.end();++it) { if ((*it)->get_parent_formaction() == f) { (*it)->set_parent_formaction(formaction_stack[0]); } } } } void view::set_colors(std::map& fgc, std::map& bgc, std::map >& attribs) { fg_colors = fgc; bg_colors = bgc; attributes = attribs; } void view::apply_colors_to_all_formactions() { for (std::vector >::iterator it=formaction_stack.begin();it!=formaction_stack.end();++it) { apply_colors(*it); } if (formaction_stack.size() > 0 && formaction_stack[current_formaction]) { formaction_stack[current_formaction]->set_redraw(true); } } void view::apply_colors(std::tr1::shared_ptr fa) { std::map::const_iterator fgcit = fg_colors.begin(); std::map::const_iterator bgcit = bg_colors.begin(); std::map >::const_iterator attit = attributes.begin(); LOG(LOG_DEBUG, "view::apply_colors: fa = %s", fa->id().c_str()); std::string article_colorstr; for (;fgcit != fg_colors.end(); ++fgcit, ++bgcit, ++attit) { std::string colorattr; if (fgcit->second != "default") { colorattr.append("fg="); colorattr.append(fgcit->second); } if (bgcit->second != "default") { if (colorattr.length() > 0) colorattr.append(","); colorattr.append("bg="); colorattr.append(bgcit->second); } for (std::vector::const_iterator it=attit->second.begin(); it!= attit->second.end(); ++it) { if (colorattr.length() > 0) colorattr.append(","); colorattr.append("attr="); colorattr.append(*it); } if (fgcit->first == "article") { article_colorstr = colorattr; if (fa->id() == "article") { std::string bold = article_colorstr; std::string ul = article_colorstr; if (bold.length() > 0) bold.append(","); if (ul.length() > 0) ul.append(","); bold.append("attr=bold"); ul.append("attr=underline"); fa->get_form()->set("color_bold", bold.c_str()); fa->get_form()->set("color_underline", ul.c_str()); } } LOG(LOG_DEBUG,"view::apply_colors: %s %s %s\n", fa->id().c_str(), fgcit->first.c_str(), colorattr.c_str()); fa->get_form()->set(fgcit->first, colorattr); if (fgcit->first == "article") { if (fa->id() == "article" || fa->id() == "help") { std::string styleend_str; if (bgcit->second != "default") { styleend_str.append("bg="); styleend_str.append(bgcit->second); } if (styleend_str.length() > 0) styleend_str.append(","); styleend_str.append("attr=bold"); fa->get_form()->set("styleend", styleend_str.c_str()); } } } } void view::feedlist_mark_pos_if_visible(unsigned int pos) { if (formaction_stack_size() > 0) { std::tr1::dynamic_pointer_cast(formaction_stack[0])->mark_pos_if_visible(pos); } } void view::set_regexmanager(regexmanager * r) { rxman = r; } std::vector > view::get_formaction_names() { std::vector > formaction_names; unsigned int i=0; for (std::vector >::iterator it=formaction_stack.begin();it!=formaction_stack.end();++it,i++) { if (*it && (*it)->id() != "dialogs") { formaction_names.push_back(std::pair(i, (*it)->title())); } } return formaction_names; } void view::goto_next_dialog() { current_formaction++; if (current_formaction >= formaction_stack.size()) current_formaction = 0; } void view::goto_prev_dialog() { if (current_formaction > 0) { current_formaction--; } else { current_formaction = formaction_stack.size() - 1; } } void view::inside_qna(bool f) { is_inside_qna = f; } void view::inside_cmdline(bool f) { is_inside_cmdline = f; } void view::clear_line(std::tr1::shared_ptr fa) { fa->get_form()->set("qna_value", ""); fa->get_form()->set("qna_value_pos", "0"); LOG(LOG_DEBUG, "view::clear_line: cleared line"); } void view::clear_eol(std::tr1::shared_ptr fa) { unsigned int pos = utils::to_u(fa->get_form()->get("qna_value_pos")); std::string val = fa->get_form()->get("qna_value"); val.erase(pos, val.length()); fa->get_form()->set("qna_value", val); fa->get_form()->set("qna_value_pos", utils::to_string(val.length())); LOG(LOG_DEBUG, "view::clear_eol: cleared to end of line"); } void view::cancel_input(std::tr1::shared_ptr fa) { fa->process_op(OP_INT_CANCEL_QNA); LOG(LOG_DEBUG, "view::cancel_input: cancelled input"); } void view::delete_word(std::tr1::shared_ptr fa) { std::string::size_type curpos = utils::to_u(fa->get_form()->get("qna_value_pos")); std::string val = fa->get_form()->get("qna_value"); std::string::size_type firstpos = curpos; LOG(LOG_DEBUG, "view::delete_word: before val = %s", val.c_str()); if (firstpos >= val.length() || ::isspace(val[firstpos])) { if (firstpos != 0 && firstpos >= val.length()) firstpos = val.length() - 1; while (firstpos > 0 && ::isspace(val[firstpos])) { --firstpos; } } while (firstpos > 0 && !::isspace(val[firstpos])) { --firstpos; } if (firstpos != 0) firstpos++; val.erase(firstpos, curpos - firstpos); LOG(LOG_DEBUG, "view::delete_word: after val = %s", val.c_str()); fa->get_form()->set("qna_value", val); fa->get_form()->set("qna_value_pos", utils::to_string(firstpos)); } void view::handle_cmdline_completion(std::tr1::shared_ptr fa) { std::string fragment = fa->get_form()->get("qna_value"); if (fragment != last_fragment || fragment == "") { last_fragment = fragment; suggestions = fa->get_suggestions(fragment); tab_count = 0; } tab_count++; std::string suggestion; switch (suggestions.size()) { case 0: LOG(LOG_DEBUG, "view::handle_cmdline_completion: found no suggestion for `%s'", fragment.c_str()); ::beep(); // direct call to ncurses - we beep to signal that there is no suggestion available, just like vim return; case 1: suggestion = suggestions[0]; break; default: suggestion = suggestions[(tab_count-1) % suggestions.size()]; break; } fa->get_form()->set("qna_value", suggestion); fa->get_form()->set("qna_value_pos", utils::to_string(suggestion.length())); last_fragment = suggestion; } void view::dump_current_form() { std::string formtext = formaction_stack[current_formaction]->get_form()->dump("", "", 0); char fnbuf[128]; time_t t = ::time(NULL); struct tm * stm = localtime(&t); strftime(fnbuf, sizeof(fnbuf), "dumpform-%Y%m%d-%H%M%S.stfl", stm); std::fstream f(fnbuf, std::ios_base::out); if (!f.is_open()) { show_error(utils::strprintf("Error: couldn't open file %s: %s", fnbuf, strerror(errno))); return; } f << formtext; f.close(); set_status(utils::strprintf("Dumped current form to file %s", fnbuf)); } } newsbeuter-2.7/stfl/000077500000000000000000000000001220711462700145175ustar00rootroot00000000000000newsbeuter-2.7/stfl/dialogs.stfl000066400000000000000000000012141220711462700170310ustar00rootroot00000000000000vbox @style_normal[background]: @info#style_normal[info]:bg=blue,fg=yellow,attr=bold @bind_up[bind_up]:** @bind_down[bind_down]:** @bind_page_up[bind_page_up]:** @bind_page_down[bind_page_down]:** label#info text[head]:"Dialogs" .expand:h !list[dialogs] style_normal[listnormal]: style_focus[listfocus]:fg=yellow,bg=blue,attr=bold .expand:vh pos_name[dialogposname]: pos[dialogpos]:0 vbox .expand:0 .display[showhint]:1 label#info text[help]:"q:Close ENTER:Goto Dialog ^X:Close Dialog" .expand:h hbox[lastline] .expand:0 label[msglabel] text[msg]:"" .expand:h newsbeuter-2.7/stfl/dllist.stfl000066400000000000000000000012341220711462700167040ustar00rootroot00000000000000vbox @style_normal[background]: @info#style_normal[info]:bg=blue,fg=yellow,attr=bold @bind_up[bind_up]:** @bind_down[bind_down]:** @bind_page_up[bind_page_up]:** @bind_page_down[bind_page_down]:** @bind_home[bind_home]:** @bind_end[bind_end]:** label#info[title] text[head]:"Queue" .expand:h !list[dls] style_normal[listnormal]: style_focus[listfocus]:fg=yellow,bg=blue,attr=bold .expand:vh pos_name[dlposname]: pos[dlpos]:0 vbox[hints] .expand:0 .display[showhint]:1 label#info text[help]:"q:Quit d:Download c:Cancel D:Delete P:Purge Finished" .expand:h label text[msg]:"" .expand:h newsbeuter-2.7/stfl/feedlist.stfl000066400000000000000000000013471220711462700172150ustar00rootroot00000000000000vbox @style_normal[background]: @info#style_normal[info]:bg=blue,fg=yellow,attr=bold @bind_up[bind_up]:** @bind_down[bind_down]:** @bind_page_up[bind_page_up]:** @bind_page_down[bind_page_down]:** @bind_home[bind_home]:** @bind_end[bind_end]:** label#info[title] text[head]:"Your feeds" .expand:h !list[feeds] style_normal[listnormal]: style_focus[listfocus]:fg=yellow,bg=blue,attr=bold .expand:vh pos_name[feedposname]: pos[feedpos]:0 vbox[hints] .expand:0 .display[showhint]:1 label#info text[help]:"q:Quit ENTER:Open r:Reload R:Reload All A:Mark All Read C:Catchup All" .expand:h hbox[lastline] .expand:0 label[msglabel] text[msg]:"" .expand:h newsbeuter-2.7/stfl/filebrowser.stfl000066400000000000000000000016421220711462700177370ustar00rootroot00000000000000vbox @style_normal[background]: @info#style_normal[info]:bg=blue,fg=yellow,attr=bold @bind_up[bind_up]:** @bind_down[bind_down]:** @bind_page_up[bind_page_up]:** @bind_page_down[bind_page_down]:** @bind_home[bind_home]:** @bind_end[bind_end]:** label#info[title] text[head]:"File Browser" .expand:h list[files] * this height is only a hack to expand the list correctly (bug?) .expand:vh .height:65535 style_normal[listnormal]: style_focus[listfocus]:fg=yellow,bg=blue,attr=bold pos_name[listposname]: pos[listpos]:0 table[hints] .expand:0 .height:1 label .expand:0 text[fileprompt]:"File: " !input[filename] .expand:h text[filenametext]:"" vbox .expand:0 .display[showhint]:1 label#info .expand:h .height:1 text[help]:"q:Abort" hbox[lastline] .expand:0 label[msglabel] text[msg]:"" .expand:h newsbeuter-2.7/stfl/help.stfl000066400000000000000000000012621220711462700163420ustar00rootroot00000000000000vbox @style_normal[background]: @info#style_normal[info]:bg=blue,fg=yellow,attr=bold @bind_up[bind_up]:** @bind_down[bind_down]:** @bind_page_up[bind_page_up]:** @bind_page_down[bind_page_down]:** @bind_home[bind_home]:** @bind_end[bind_end]:** label#info[title] text[head]:"Help" .expand:h textview[helptext] richtext:1 style_hl_normal[highlight]: style_normal[article]: style_end[styleend]:fg=blue,attr=bold .expand:vh offset[helpoffset]:0 vbox[hints] .expand:0 .display[showhint]:1 label#info text[help]:"q:Quit" .expand:h hbox[lastline] .expand:0 label[msglabel] text[msg]:"" .expand:h newsbeuter-2.7/stfl/itemlist.stfl000066400000000000000000000015461220711462700172510ustar00rootroot00000000000000vbox @style_normal[background]: @info#style_normal[info]:bg=blue,fg=yellow,attr=bold @bind_up[bind_up]:** @bind_down[bind_down]:** @bind_page_up[bind_page_up]:** @bind_page_down[bind_page_down]:** @bind_home[bind_home]:** @bind_end[bind_end]:** @style_unread_normal[listnormal_unread]:fg=magenta @style_unread_focus[listfocus_unread]:fg=magenta,bg=blue,attr=bold label#info[title] text[head]:"Articles for '#'" .expand:h list[items] .expand:vh richtext:1 style_normal[listnormal]: style_focus[listfocus]:fg=yellow,bg=blue,attr=bold pos_name[itemposname]: pos[itempos]:0 vbox[hints] .expand:0 .display[showhint]:1 label#info text[help]:"q:Quit ENTER:Open s:Save n:Next Unread A:Mark All Read" .expand:h hbox[lastline] .expand:0 label[msglabel] text[msg]:"" .expand:h newsbeuter-2.7/stfl/itemview.stfl000066400000000000000000000015101220711462700172370ustar00rootroot00000000000000vbox @style_normal[background]: @info#style_normal[info]:bg=blue,fg=yellow,attr=bold @bind_up[bind_up]:** @bind_down[bind_down]:** @bind_page_up[bind_page_up]:"** b" @bind_page_down[bind_page_down]:"** SPACE" @bind_home[bind_home]:** @bind_end[bind_end]:** label#info[title] text[head]:"Article '#'" .expand:h textview[article] style_normal[article]: style_end[styleend]:fg=blue,attr=bold .expand:vh offset[articleoffset]:0 richtext:1 vbox[hints] .expand:0 .display[showhint]:1 hbox .expand:0 label#info text[help]:"q:Quit s:Save o:Open in Browser n:Next Unread" .expand:h label#info text[percent]:"" .expand:0 .width[percentwidth]:6 hbox[lastline] .expand:0 label[msglabel] text[msg]:"" .expand:h newsbeuter-2.7/stfl/selecttag.stfl000066400000000000000000000012721220711462700173660ustar00rootroot00000000000000vbox @style_normal[background]: @info#style_normal[info]:bg=blue,fg=yellow,attr=bold @bind_up[bind_up]:** @bind_down[bind_down]:** @bind_page_up[bind_page_up]:** @bind_page_down[bind_page_down]:** @bind_home[bind_home]:** @bind_end[bind_end]:** label#info[title] text[head]:"Select Tag" .expand:h list[taglist] .expand:vh style_normal[listnormal]: style_focus[listfocus]:fg=yellow,bg=blue,attr=bold pos_name[tagposname]: pos[tagpos]:0 vbox[hints] .expand:0 .display[showhint]:1 label#info text[help]:"q:Cancel ENTER:Select Tag" .expand:h hbox[lastline] .expand:0 label[msglabel] text[msg]:"" .expand:h newsbeuter-2.7/stfl/urlview.stfl000066400000000000000000000012611220711462700171060ustar00rootroot00000000000000vbox @style_normal[background]: @info#style_normal[info]:bg=blue,fg=yellow,attr=bold @bind_up[bind_up]:** @bind_down[bind_down]:** @bind_page_up[bind_page_up]:** @bind_page_down[bind_page_down]:** @bind_home[bind_home]:** @bind_end[bind_end]:** label#info[title] text[head]:"URLs" .expand:h !list[urls] style_normal[listnormal]: style_focus[listfocus]:fg=yellow,bg=blue,attr=bold .expand:vh pos_name[feedposname]: pos[feedpos]:0 vbox[hints] .expand:0 .display[showhint]:1 label#info text[help]:"q:Quit ENTER:Open Feed" .expand:h hbox[lastline] .expand:0 label[msglabel] text[msg]:"" .expand:h newsbeuter-2.7/test/000077500000000000000000000000001220711462700145265ustar00rootroot00000000000000newsbeuter-2.7/test/config-example000066400000000000000000000363231220711462700173560ustar00rootroot00000000000000#################################### # newsbeuter example configuration # #################################### ## configuration option: always-display-description ## description: If true, then the description will always displayed even if e.g. a content:encoded tag has been found. ## parameter syntax: [true/false] # always-display-description false ## configuration option: article-sort-order ## description: The sortfield specifies which article property shall be used for sorting (currently available: date, title, flags, author, link, guid). The optional direction specifies the sort direction ("asc" specifies ascending sorting, "desc" specifies descending sorting. for date, "desc" is default, for all others, "asc" is default). ## parameter syntax: [-] # article-sort-order date ## configuration option: articlelist-format ## description: This variable defines the format of entries in the article list. See the respective section in the documentation for more information on format strings. ## parameter syntax: # articlelist-format "%4i %f %D %6L %?T?|%-17T| ?%t" ## configuration option: auto-reload ## description: If enabled, all feeds will be automatically reloaded at start up and then continuously after a certain time has passed (see reload-time). ## parameter syntax: [yes/no] # auto-reload no ## configuration option: bookmark-cmd ## description: If set, then will be used as bookmarking plugin. See the documentation on bookmarking for further information. ## parameter syntax: # bookmark-cmd "" ## configuration option: bookmark-interactive ## description: If set to yes, then the configured bookmark command is an interactive program. ## parameter syntax: [yes/no] # bookmark-interactive no ## configuration option: browser ## description: Set the browser command to use when opening an article in the browser. If contains %u, it will be used as complete commandline and %u will be replaced with the URL that shall be opened. ## parameter syntax: # browser lynx ## configuration option: cache-file ## description: This configuration option sets the cache file. This is especially useful if the filesystem of your home directory doesn't support proper locking (e.g. NFS). ## parameter syntax: # cache-file "~/.newsbeuter/cache.db" ## configuration option: cleanup-on-quit ## description: If yes, then the cache gets locked and superfluous feeds and items are removed, such as feeds that can't be found in the urls configuration file anymore. ## parameter syntax: [yes/no] # cleanup-on-quit yes ## configuration option: confirm-exit ## description: If set to yes, then newsbeuter will ask for confirmation whether the user really wants to quit newsbeuter. ## parameter syntax: [yes/no] # confirm-exit no ## configuration option: datetime-format ## description: This format specifies the date/time format in the article list. For a detailed documentation on the allowed formats, consult the manpage of strftime(3). ## parameter syntax: # datetime-format %b %d ## configuration option: display-article-progress ## description: If set to yes, then a read progress (in percent) is displayed in the article view. Otherwise, no read progress is displayed. ## parameter syntax: [yes/no] # display-article-progress yes ## configuration option: download-retries ## description: How many times newsbeuter shall try to successfully download a feed before giving up. This is an option to improve the success of downloads on slow and shaky connections such as via a TOR proxy. ## parameter syntax: # download-retries 1 ## configuration option: download-timeout ## description: The number of seconds newsbeuter shall wait when downloading a feed before giving up. This is an option to improve the success of downloads on slow and shaky connections such as via a TOR proxy. ## parameter syntax: # download-timeout 30 ## configuration option: error-log ## description: If set, then user errors (e.g. errors regarding defunct RSS feeds) will be logged to this file. ## parameter syntax: # error-log "" ## configuration option: feed-sort-order ## description: If set to "firsttag", the feeds in the feed list will be sorted by their first tag in the urls file. ## parameter syntax: # feed-sort-order none ## configuration option: feedlist-format ## description: This variable defines the format of entries in the feed list. See the respective section in the documentation for more information on format strings. ## parameter syntax: # feedlist-format "%4i %n %11u %t" ## configuration option: googlereader-flag-share ## description: If this is set and Google Reader support is used, then all articles that are flagged with the specified flag are being "shared" in Google Reader so that people that follow you can see it. ## parameter syntax: # googlereader-flag-share "" ## configuration option: googlereader-flag-star ## description: If this is set and Google Reader support is used, then all articles that are flagged with the specified flag are being "starred" in Google Reader and appear in the list of "Starred items". ## parameter syntax: # googlereader-flag-star "" ## configuration option: googlereader-login ## description: This variable sets your Google Reader login for the Google Reader support. ## parameter syntax: # googlereader-login "" ## configuration option: googlereader-min-items ## description: This variable sets the number of articles that are loaded from Google Reader per feed. ## parameter syntax: # googlereader-min-items 20 ## configuration option: googlereader-password ## description: This variable sets your Google Reader password for the Google Reader support. ## parameter syntax: # googlereader-password "" ## configuration option: googlereader-show-special-feeds ## description: If this is set, then "special feeds" like "People you follow" (articles shared by people you follow), "Starred items" (your starred articles), "Shared items" (your shared articles) and "Popular items" (articles considered to be popular by Google's magic algorithms) appear in your subscription list. ## parameter syntax: [yes/no] # googlereader-show-special-feeds yes ## configuration option: goto-first-unread ## description: If set to yes (the default), then the first unread article will be selected whenever a feed is entered. ## parameter syntax: [yes/no] # goto-first-unread yes ## configuration option: goto-next-feed ## description: If set to yes, then the next-unread and prev-unread keys will search in other feeds for unread articles if all articles in the current feed are read. If set to no, then the next-unread and prev-unread keys will stop in the current feed. ## parameter syntax: [yes/no] # goto-next-feed yes ## configuration option: history-limit ## description: Defines the maximum number of entries of commandline resp. search history to be saved. To disable history saving, set history-limit to 0. ## parameter syntax: # history-limit 100 ## configuration option: html-renderer ## description: If set to "internal", then the internal HTML renderer will be used. Otherwise, the specified command will be executed, the HTML to be rendered will be written to the command's stdin, and the program's output will be displayed. This makes it possible to use other, external programs, such as w3m, links or lynx, to render HTML. ## parameter syntax: # html-renderer internal ## configuration option: ignore-mode ## description: This configuration option defines in what way an article is ignored (see ignore-article). If set to "download", then it is ignored in the download/parsing phase (which is the default) and thus never written to the cache, if it set to "display", it is ignored when displaying articles but is kept in the cache. ## parameter syntax: [download/display] # ignore-mode download ## configuration option: keep-articles-days ## description: If set the a number greater than 0, only articles that are were published within the last days are kept, and older articles are deleted. If set to 0 (default value), this option is not active. ## parameter syntax: # keep-articles-days 0 ## configuration option: mark-as-read-on-hover ## description: If set to yes, then all articles that get selected in the article list are marked as read. ## parameter syntax: [yes/no] # mark-as-read-on-hover no ## configuration option: max-items ## description: Set the number of articles to maximally keep per feed. If the number is set to 0, then all articles are kept. ## parameter syntax: # max-items 0 ## configuration option: notify-format ## description: Format string that is used for formatting notifications. See the chapter on format strings for more information. ## parameter syntax: # notify-format "newsbeuter: finished reload, %f unread feeds (%n unread articles total)" ## configuration option: notify-program ## description: If set, then the configured program will be executed if new articles arrived (through a reload) or if notify-always is true. The first parameter of the called program contains the notification message. ## parameter syntax: # notify-program "" ## configuration option: notify-always ## description: If no, notifications will only be made when there are new feeds or articles. If yes, notifications will be made regardless. ## parameter syntax: [yes/no] # notify-always no ## configuration option: notify-screen ## description: If yes, then a "privacy message" will be sent to the terminal, containing a notification message about new articles. This is especially useful if you use terminal emulations such as GNU screen which implement privacy messages. ## parameter syntax: [yes/no] # notify-screen no ## configuration option: notify-xterm ## description: If yes, then the xterm window title will be set to a notification message about new articles. ## parameter syntax: [yes/no] # notify-xterm no ## configuration option: notify-beep ## description: If yes, then the speaker beep on new articles. ## parameter syntax: [yes/no] # notify-beep no ## configuration option: opml-url ## description: If the OPML online subscription mode is enabled, then the list of feeds will be taken from the OPML file found on this location. Optionally, you can specify more than one URL. All the listed OPML URLs will then be taken into account when loading the feed list. ## parameter syntax: ... # opml-url "" ## configuration option: pager ## description: If set to "internal", then the internal pager will be used. Otherwise, the article to be displayed will be rendered to be a temporary file and then displayed with the configured pager. If the pager path is set to an empty string, the content of the "PAGER" environment variable will be used. If the pager path contains a placeholder "%f", it will be replaced with the temporary filename. ## parameter syntax: [/internal] # pager internal ## configuration option: podcast-auto-enqueue ## description: If yes, then all podcast URLs that are found in articles are added to the podcast download queue. See the respective section in the documentation for more information on podcast support in newsbeuter. ## parameter syntax: [yes/no] # podcast-auto-enqueue no ## configuration option: prepopulate-query-feeds ## description: If yes, then all query feeds are prepopulated with articles on startup. ## parameter syntax: [yes/no] # prepopulate-query-feeds no ## configuration option: proxy-auth-method ## description: Set proxy authentication method. Allowed values: any, basic, digest, digest_ie (only available with libcurl 7.19.3 and newer), gssnegotiate, ntlm, anysafe. ## parameter syntax: # proxy-auth-method any ## configuration option: proxy-type ## description: Set proxy type. Allowed values: http, socks4, socks4a, socks5. ## parameter syntax: # proxy-type http ## configuration option: refresh-on-startup ## description: If yes, then all feeds will be reloaded when newsbeuter starts up. This is equivalent to the -r commandline option. ## parameter syntax: [yes/no] # refresh-on-startup no ## configuration option: reload-only-visible-feeds ## description: If yes, then manually reloading all feeds will only reload the currently visible feeds, e.g. if a filter or a tag is set. ## parameter syntax: [yes/no] # reload-only-visible-feeds no ## configuration option: reload-time ## description: The number of minutes between automatic reloads. ## parameter syntax: # reload-time 60 ## configuration option: reload-threads ## description: The number of parallel reload threads that shall be started when all feeds are reloaded. ## parameter syntax: # reload-threads 1 ## configuration option: save-path ## description: The default path where articles shall be saved to. If an invalid path is specified, the current directory is used. ## parameter syntax: # save-path ~/ ## configuration option: search-highlight-colors ## description: This configuration command specifies the highlighting colors when searching for text from the article view. ## parameter syntax: [ ...] # search-highlight-colors black yellow bold ## configuration option: show-keymap-hint ## description: If no, then the keymap hints on the bottom of screen will not be displayed. ## parameter syntax: [yes/no] # show-keymap-hint yes ## configuration option: show-read-feeds ## description: If yes, then all feeds, including those without unread articles, are listed. If no, then only feeds with one or more unread articles are list. ## parameter syntax: [yes/no] # show-read-feeds yes ## configuration option: show-read-articles ## description: If yes, then all articles of a feed are listed in the article list. If no, then only unread articles are listed. ## parameter syntax: [yes/no] # show-read-articles yes ## configuration option: suppress-first-reload ## description: If yes, then the first automatic reload will be suppressed if auto-reload is set to yes. ## parameter syntax: [yes/no] # suppress-first-reload no ## configuration option: text-width ## description: If set to a number greater than 0, then all HTML will be rendered to this maximum line length. If set to 0, the terminal width will be used. ## parameter syntax: # text-width 0 ## configuration option: urls-source ## description: This configuration command sets the source where URLs shall be retrieved from. By default, this is ~/.newsbeuter/urls. Alternatively, you can set it to "opml", which enables newsbeuter's OPML online subscription mode, or to "googlereader", which enables newsbeuter's Google Reader support. In order to make Google Reader support work correctly, you also need to set googlereader-login and googlereader-password. ## parameter syntax: # urls-source "local" ## configuration option: use-proxy ## description: If yes, then the configured proxy will be used for downloading the RSS feeds. ## parameter syntax: [yes/no] # use-proxy no ## configuration option: user-agent ## description: If set to a non-zero-length string, this value will be used as HTTP User-Agent header for all HTTP requests. ## parameter syntax: # user-agent "" # EOF # a simple newsbeuter color scheme. color listnormal white black color listfocus yellow red bold color info cyan blue color background white black color article white black newsbeuter-2.7/test/config-filter000066400000000000000000000000701220711462700171760ustar00rootroot00000000000000define-filter "unread articles only" "unread = \"yes\"" newsbeuter-2.7/test/config-reloadthread000066400000000000000000000000201220711462700203420ustar00rootroot00000000000000auto-reload yes newsbeuter-2.7/test/config-reset000066400000000000000000000002251220711462700170350ustar00rootroot00000000000000reset-unread-on-update http://testbed.newsbeuter.org/rss20-html.xml http://testbed.newsbeuter.org/tables.xml http://testbed.newsbeuter.org/rss20.xml newsbeuter-2.7/test/config-retry000066400000000000000000000000501220711462700170540ustar00rootroot00000000000000download-retries 10 download-timeout 60 newsbeuter-2.7/test/config-tuitest2000066400000000000000000000001071220711462700174750ustar00rootroot00000000000000urls-source opml opml-url "http://testbed.newsbeuter.org/testbed.opml" newsbeuter-2.7/test/config-tuitest2-offline000066400000000000000000000000721220711462700211160ustar00rootroot00000000000000urls-source opml opml-url "file://./testbed/testbed.opml" newsbeuter-2.7/test/data/000077500000000000000000000000001220711462700154375ustar00rootroot00000000000000newsbeuter-2.7/test/data/atom10_1.xml000066400000000000000000000034151220711462700175050ustar00rootroot00000000000000 test atom atom description! tag:example.com 2008-12-30T18:26:15Z A Person http://example.com/ <![CDATA[A gentle introduction to Atom testing]]> tag:example.com,2008-12-30:/atom_testing 2008-12-30T20:04:15Z 2008-12-30T20:04:15Z some content A Person http://example.com/ <![CDATA[A missing rel attribute]]> tag:example.com,2008-12-30:/atom_testing1 2008-12-30T20:14:15Z 2008-12-30T20:14:15Z some content A Person http://example.com/ <![CDATA[alternate link isn't first]]> tag:example.com,2008-12-30:/atom_testing2 2008-12-30T20:24:15Z 2008-12-30T20:24:15Z some content newsbeuter-2.7/test/data/rss091_1.xml000066400000000000000000000013411220711462700174410ustar00rootroot00000000000000 Example Channel http://example.com/ an example feed en (PICS-1.1 "http://www.classify.org/safesurf/" l r (SS~~000 1)) Search this site: Find: q http://example.com/search 0 1 < 2 http://example.com/1_less_than_2.html 1 < 2, 3 < 4. In HTML, <b> starts a bold phrase and you start a link with <a href= newsbeuter-2.7/test/data/rss092_1.xml000066400000000000000000000010331220711462700174400ustar00rootroot00000000000000 Example Channel http://example.com/ an example feed en <![CDATA[1 < 2]]> http://example.com/1_less_than_2.html starts a bold phrase and you start a link with A second item http://example.com/a_second_item.html no description newsbeuter-2.7/test/data/rss10_1.xml000066400000000000000000000015501220711462700173520ustar00rootroot00000000000000 Example Dot Org http://www.example.org the Example Organization web site Example http://www.example.org/images/logo.gif http://www.example.org New Status Updates http://www.example.org/status/foo News about the Example project 2008-12-30T08:20:00+01:00 newsbeuter-2.7/test/data/rss20_1.xml000066400000000000000000000013221220711462700173500ustar00rootroot00000000000000 my weblog http://example.com/blog/ my description this is an item http://example.com/blog/this_is_an_item.html http://example.com/blog/this_is_an_item.html#comments blog@synflood.at (Andreas Krennmair) oh well, this is the content. Fri, 12 Dec 2008 02:36:10 +0100 http://example.com/blog/this_is_an_item.html newsbeuter-2.7/test/lcov-run-all.sh000077500000000000000000000010471220711462700174020ustar00rootroot00000000000000#!/bin/sh APPBASE_INFO=appbase.info APPTEST_INFO=apptest.info APPTOTAL_INFO=apptotal.info make distclean rm -rf $APPBASE_INFO $APPTEST_INFO html make -j 5 -f Makefile.prof all test test-rss lcov -c -i -b . -d . -o $APPBASE_INFO export OFFLINE=1 ( cd test && ./test ) lcov -c -b . -d . -o $APPTEST_INFO ( cd test && ./test-rss ) lcov -c -b . -d . -o $APPTEST_INFO ( cd test && ./run-uitests-headless.sh ) lcov -c -b . -d . -o $APPTEST_INFO lcov -b . -d . -a $APPBASE_INFO -a $APPTEST_INFO -o $APPTOTAL_INFO rm -rf html genhtml -o html $APPTOTAL_INFO newsbeuter-2.7/test/lemon.h000066400000000000000000000323661220711462700160230ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// // lemon.h - A minimal unit-testing framework based on Test::More // // Description: // lemon is a minimal unit-testing framework designed to be simple to drop // in and use without require external dependencies or linking. In this way // lemon hopes to promote testing on projects of all sizes by reducing the // barrier of setup that comes with most unit-testing frameworks. To find // the latest version visit http://github.com/etscrivner/lemon. // // Copyright (c) 2010 lemon team // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. /////////////////////////////////////////////////////////////////////////////// #ifndef LEMON_H_ #define LEMON_H_ // C++ includes #include #include /////////////////////////////////////////////////////////////////////////////// // Macro: LEMON_SKIP // // Begins a block of tests that will be skipped, creating a more convenient // syntax for test skipping. For example: // // // lemon::test<> lemon(..); // // ... // LEMON_SKIP(lemon, "These tests are currently broken") { // lemon.is(foo(), true, "foo true"); // lemon.is(bar(), false, "bar false"); // } // #define LEMON_SKIP(lemon_inst, reason) \ for (bool __skip_enabled__ = (lemon_inst).enable_skip(); \ __skip_enabled__; __skip_enabled__ = (lemon_inst).disable_skip()) /////////////////////////////////////////////////////////////////////////////// // Macro: LEMON_TODO // // Begins a block of tests for features which have yet to be completed. For // example: // // // lemon::test<> lemon(..); // // ... // LEMON_TODO(lemon) { // lemon.is(tumtum(), fizbaz(), "tumtum is fizbaz"); // lemon.not_ok(cannibalism(), "cannibalism is not ok"); // } // #define LEMON_TODO(lemon_inst) \ for (bool __todo_enabled__ = (lemon_inst).enable_todo(); \ __todo_enabled__; __todo_enabled__ = (lemon_inst).disable_todo()) namespace lemon { namespace output { /////////////////////////////////////////////////////////////////////////// // Class: cout // // Implements output to standard out struct cout { template lemon::output::cout& operator << (const T& val) { std::cout << val; return *this; } }; /////////////////////////////////////////////////////////////////////////// // Class: cerr // // Implements output to standard error struct cerr { template lemon::output::cerr& operator << (const T& val) { std::cerr << val; return *this; } }; /////////////////////////////////////////////////////////////////////////// // Class: clog // // Implements output to standard logging struct clog { template lemon::output::clog& operator << (const T& val) { std::clog << val; return *this; } }; /////////////////////////////////////////////////////////////////////////// // Class: nothing // // Implements a null output policy struct nothing { template lemon::output::nothing& operator << (const T& val) { return *this; } }; } ///////////////////////////////////////////////////////////////////////////// // Class: test // // Policy-based class for doing testing. For example a simple test might be: // // // bool always_true() { return true; } // //... // lemon::test<> lemon(2); // lemon.is(always_true(), true, "always_true is true"); // lemon.isnt(always_true(), false, "always_true isn't false"); // lemon.done(); // template class test { public: ///////////////////////////////////////////////////////////////////////////// // Function: test // // Parameters: // num_planned_tests - The total number of tests you plan to execute // // This simply lets lemon know how many tests you're planning to run so that // it can properly output the diagnostic information and doesn't have to // count by hand (which can be tricky as one test can have many assertions). test (unsigned int num_planned_tests = 0) : num_tests_(0), test_number_(0), num_skipped_(0), num_failed_(0), num_planned_(num_planned_tests), skip_enabled_(false), todo_enabled_(false) { if (num_planned_tests > 0) { output_ << "1.." << num_planned_tests << "\n"; } } ///////////////////////////////////////////////////////////////////////////// // Function: done // // Returns true if all unskipped tests passed, false if there were failures. bool done () { // If there was no test plan specified if (num_planned_ == 0) { output_ << "1.." << num_tests_ << "\n"; } // Compute the total number of tests without skipped tests counted unsigned int total_tests = num_tests_ - num_skipped_; // If any tests were skipped if (num_planned_ > 0 && num_skipped_ > 0) { // Display information about the skipped tests output_ << "# Looks like you planned " << num_planned_; output_ << " but only ran " << total_tests << "\n"; } // If any tests were failed if (num_failed_ > 0) { // Display test failure statistics output_ << "# Looks like you failed " << num_failed_; output_ << " of " << total_tests << "\n"; return false; } else if(num_planned_ > 0 && total_tests > num_planned_) { output_ << "# Looks like you ran " << total_tests << " tests, "; output_ << "but only planned " << num_planned_ << "\n"; return false; } else { // Otherwise display success message output_ << "# Looks like you passed all " << total_tests << " tests.\n"; return true; } } ///////////////////////////////////////////////////////////////////////////// // Function: diag // // Parameters: // message - A string to be written out to the display // // Used to display diagnostic information which is not a unit test. void diag (const std::string& message) { output_ << "# " << message << "\n"; } ///////////////////////////////////////////////////////////////////////////// // Function: ok // // Parameters: // passed - True indicates a passing condition, false indicates failure // test_name - A short, descriptive name for this test // // Marks this test as passed if pass is true. The test is marked as // failing otherwise. bool ok (bool passed, const std::string& test_name) { // Increment the number of tests run num_tests_++; // If this is a skip or todo message std::string test_name_out = test_name; if (test_name[0] != '#') { // Not the safest thing, but append a dash to the front test_name_out = "- " + test_name_out; } // If we're currently skipping tests if (skip_enabled_) { num_skipped_++; output_ << "skipping " << num_tests_ << " " << test_name_out << "\n"; return false; } else if (todo_enabled_) { num_skipped_++; output_ << "todo " << num_tests_ << " " << test_name_out << "\n"; return false; } else if (passed) { // Inform you that the test passed output_ << "ok " << num_tests_ << " " << test_name_out << "\n"; } else { // Otherwise increment the number of failed tests. num_failed_++; // Inform you that the test failed output_ << "not ok " << num_tests_ << " " << test_name_out << "\n"; diag(" Failed test '" + test_name + "'"); } return passed; } ///////////////////////////////////////////////////////////////////////////// // Function: not_ok // // Parameters: // failed - False indicates a passing condition, true indicates failure // test_name - A short, descriptive name for this test // // Marks this test as passed if the boolean parameter is false. The test is // marked as failing otherwise. bool not_ok (bool failed, const std::string& test_name) { return ok(!failed, test_name); } ///////////////////////////////////////////////////////////////////////////// // Function: is // // Parameters: // this_one - The left hand of the equality operator // that_one - The right hand of the equality operator // test_name - A short, descriptive name for this test // // Checks whether the two values are equal using the == operator. If // they are equal the test passes, otherwise it fails. template bool is (const T1& this_one, const T2& that_one, const std::string& test_name) { bool passed = (this_one == that_one); ok(passed, test_name); if (!passed && !skip_enabled_ && !todo_enabled_) { output_ << "# got: '" << this_one << "'\n"; output_ << "# expected: '" << that_one << "'\n"; } return passed; } ///////////////////////////////////////////////////////////////////////////// // Function: isnt // // Parameters: // this_one - The left hand of the inequality operator // that_one - The right hand of the inequality operator // test_name - A short, descriptive name for this test // // Checks whether the two values are equal using the != operator. If // they are not equal the test passes, otherwise the test fails. template bool isnt (const T1& this_one, const T2& that_one, const std::string& test_name) { bool passed = (this_one != that_one); ok (passed, test_name); if (!passed && !skip_enabled_ && !todo_enabled_) { output_ << "# '" << this_one << "'\n"; output_ << "# !=\n"; output_ << "# '" << that_one << "'\n"; } return passed; } ///////////////////////////////////////////////////////////////////////////// // Function: pass // // Parameters: // test_name - A short, descriptive name for this test // // Marks the given test as trivially passing. bool pass (const std::string& test_name) { return ok(true, test_name); } ///////////////////////////////////////////////////////////////////////////// // Function: fail // // Parameters: // test_name - A short, descriptive name for this test // // Marks the given test as trivially failing. bool fail (const std::string& test_name) { return ok(false, test_name); } ///////////////////////////////////////////////////////////////////////////// // Function: enable_todo // // Enables todo mode causing no tests to be run until todo is disabled. // Always returns true. bool enable_todo () { todo_enabled_ = true; return true; } ///////////////////////////////////////////////////////////////////////////// // Function: disable_todo // // Disables todo mode causing any further tests to be run. Always returns // false. bool disable_todo () { todo_enabled_ = false; return false; } ///////////////////////////////////////////////////////////////////////////// // Function: enable_skip // // Parameters: // reason - The reason printed for skipping tests // // Enables skipping causing no tests to be run until skipping is disabled. // Always returns true. bool enable_skip () { skip_enabled_ = true; return true; } ///////////////////////////////////////////////////////////////////////////// // Function: disable_skip // // Disables skipping allowing tests to be run again. Always returns false. bool disable_skip () { skip_enabled_ = false; return false; } ///////////////////////////////////////////////////////////////////////////// // Function: num_failed // // Returns the number of failed tests unsigned int num_failed () const { return num_failed_; } ///////////////////////////////////////////////////////////////////////////// // Function: num_skipped // // Returns the number of skipped tests unsigned int num_skipped() const { return num_skipped_; } private: unsigned int num_tests_; // The total number of tests to be executed unsigned int test_number_; // The number of the current test unsigned int num_skipped_; // The number of tests marked as skipped unsigned int num_failed_; // The number of tests marked as failing unsigned int num_planned_; // The number of tests planned to be run bool skip_enabled_; // Are tests being skipped bool todo_enabled_; // Are these tests incomplete output_policy_t output_; // The place where output will be sent }; } #endif // LEMON_H_ newsbeuter-2.7/test/queue000066400000000000000000000000751220711462700155770ustar00rootroot00000000000000http://testbed.newsbeuter.org/rss20.xml "/home/ak/rss20.xml" newsbeuter-2.7/test/run-all-uitests.sh000077500000000000000000000001651220711462700201370ustar00rootroot00000000000000#!/bin/sh for f in *.rb ; do ruby "$f" if [ $? != 0 ] ; then echo "Running test $f failed." #exit 1 fi done newsbeuter-2.7/test/run-uitests-headless.sh000077500000000000000000000002461220711462700211570ustar00rootroot00000000000000#!/bin/sh rm -f *.rb.log for f in *.rb ; do echo "Running $f..." ruby "$f" > /dev/null if [ $? != 0 ] ; then echo "Running test $f failed." #exit 1 fi done newsbeuter-2.7/test/test-basic-ops.rb000066400000000000000000000123251220711462700177130ustar00rootroot00000000000000# basic operations test: # - reload # - mark feed read # - mark articles read/unread # - some HTML rendering verifications # - delete article # - search prompt # - bookmarking (unconfigured), i.e. prompts and error messages # - select filter with no filter defined, i.e error message require 'tuitest' Tuitest.init verifier = Tuitest::Verifier.new("test-basic-ops.rb.log", "RESULT-test-basic-ops.rb.xml") Kernel.system("rm -f cache cache.lock") if ENV["OFFLINE"] then Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1-offline") else Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1") end Tuitest.wait_until_idle Tuitest.keypress("r"[0]) Tuitest.keypress(10) Tuitest.keypress("A"[0]) Tuitest.wait_until_expected_text(0, 58, "0", 5000) verifier.expect(0, 58, "0") verifier.expect(1, 5, " ") verifier.expect(2, 5, " ") verifier.expect(3, 5, " ") Tuitest.keypress("q"[0]) Tuitest.keypress(10) Tuitest.keypress("N"[0]) Tuitest.keypress("N"[0]) Tuitest.keypress("N"[0]) Tuitest.wait_until_expected_text(0, 58, "3", 5000) verifier.expect(0, 58, "3") verifier.expect(1, 5, "N") verifier.expect(2, 5, "N") verifier.expect(3, 5, "N") Tuitest.keypress(259) Tuitest.keypress(259) Tuitest.keypress(10) Tuitest.keypress(12) Tuitest.keypress("n"[0]) Tuitest.wait_until_idle Tuitest.wait_until_expected_text(0, 39, "2", 5000) verifier.expect(0, 39, "2") verifier.expect(2, 20, "2") verifier.expect(4, 40, "2") verifier.expect(5, 6, "Fri, 29 Aug 2008 08:41:3") verifier.expect(7, 9, "econd item, this time only with a tag.") verifier.expect(8, 0, "~") verifier.expect(9, 0, "~ ") verifier.expect(10, 0, "~ ") verifier.expect(11, 0, "~") verifier.expect(12, 0, "~ ") verifier.expect(13, 0, "~ ") verifier.expect(14, 0, "~ ") verifier.expect(15, 0, "~") Tuitest.keypress("n"[0]) Tuitest.wait_until_expected_text(0, 39, "3", 5000) verifier.expect(0, 39, "3") verifier.expect(2, 20, "3") verifier.expect(4, 40, "3") verifier.expect(5, 6, "Thu, 28 Aug 2008 18:27:5") verifier.expect(7, 0, "And finally a third item, also description, but with some HTML...") verifier.expect(8, 0, "Yes, there was a line break. And here is a link to slashdot[1]") verifier.expect(9, 0, " ") verifier.expect(10, 0, "Links:") verifier.expect(11, 0, "[1]: http://slashdot.org/ (link)") Tuitest.keypress("n"[0]) Tuitest.wait_until_expected_text(0, 24, "s in feed 'RSS 2.0 testbed feed' (0 unread, 3 total)") verifier.expect(0, 24, "s in feed 'RSS 2.0 testbed feed' (0 unread, 3 total)") verifier.expect(1, 0, " 1 Aug 30 212 RSS 2.0 Item 1") verifier.expect(2, 0, " 2 Aug 29 67 RSS 2.0 Item 2") verifier.expect(3, 0, " 3 Aug 28 170 RSS 2.0 Item 3 ") verifier.expect(4, 0, " ") verifier.expect(5, 0, " ") verifier.expect(7, 0, " ") verifier.expect(8, 0, " ") verifier.expect(10, 0, " ") verifier.expect(11, 0, " ") verifier.expect(12, 0, " ") verifier.expect(13, 0, " ") verifier.expect(14, 0, " ") verifier.expect(15, 0, " ") verifier.expect(16, 0, " ") verifier.expect(17, 0, " ") verifier.expect(18, 0, " ") verifier.expect(19, 0, " ") verifier.expect(20, 0, " ") verifier.expect(21, 0, " ") verifier.expect(22, 0, " ") verifier.expect(23, 25, "r:Reload n:Next Unread A:Mark All Read /:Search ?:Help") verifier.expect(24, 0, "No unread items.") Tuitest.keypress("q"[0]) Tuitest.keypress(10) Tuitest.keypress(258) Tuitest.keypress(258) Tuitest.keypress("d"[0]) Tuitest.keypress("D"[0]) Tuitest.keypress("$"[0]) Tuitest.wait_until_expected_text(0, 68, "2", 5000) verifier.expect(0, 68, "2") verifier.expect(3, 3, " ") Tuitest.keypress("/"[0]) Tuitest.wait_until_expected_text(24, 0, "Search for:", 5000) verifier.expect(24, 0, "Search for:") Tuitest.keypress(10) Tuitest.wait_until_expected_text(24, 0, " ", 5000) verifier.expect(24, 0, " ") Tuitest.keypress("f"[0]) Tuitest.wait_until_expected_text(24, 0, "No filters defined.", 5000) verifier.expect(24, 0, "No filters defined.") Tuitest.keypress(2) Tuitest.wait_until_expected_text(24, 0, "URL: http://testbed.newsbeuter.org/item2.html", 5000) verifier.expect(24, 0, "URL: http://testbed.newsbeuter.org/item2.html") Tuitest.keypress(10) Tuitest.wait_until_expected_text(24, 0, "Title: RSS 2.0 Item 2", 5000) verifier.expect(24, 0, "Title: RSS 2.0 Item 2 ") Tuitest.keypress(10) Tuitest.wait_until_expected_text(24, 0, "Description:", 5000) verifier.expect(24, 0, "Description: ") Tuitest.keypress(10) Tuitest.wait_until_expected_text(24, 0, "Error while saving bookmark: bookmarking support is not configured. Please set t", 5000) verifier.expect(24, 0, "Error while saving bookmark: bookmarking support is not configured. Please set t") Tuitest.keypress(259) Tuitest.keypress(10) Tuitest.keypress("u"[0]) Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-cache.rb000066400000000000000000000022471220711462700171000ustar00rootroot00000000000000#!/usr/bin/env ruby # auto-generated tuitest script require 'tuitest' Tuitest.init verifier = Tuitest::Verifier.new("test-cache.rb.log", "RESULT-test-cache.rb.xml") Tuitest.run("../newsbeuter -c cache -C config-reset -u urls-feedlist") Tuitest.wait_until_idle Tuitest.keypress("R"[0]) Tuitest.wait_until_idle # begin auto-generated verification #1 verifier.expect(0, 29, "3") verifier.expect(1, 5, "N (3/3) HTML rendering testbed feed ") verifier.expect(2, 5, "N (1/1) html table rendering testbed feed ") verifier.expect(3, 5, "N (3/3) RSS 2.0 testbed feed ") # end auto-generated verification #1 Tuitest.keypress("C"[0]) Tuitest.wait_until_idle # begin auto-generated verification #2 verifier.expect(0, 29, "0") verifier.expect(1, 5, " (0") verifier.expect(2, 5, " (0") verifier.expect(3, 5, " (0") # end auto-generated verification #2 Tuitest.keypress("R"[0]) Tuitest.wait_until_idle # begin auto-generated verification #3 # end auto-generated verification #3 Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-config.txt000066400000000000000000000004631220711462700175140ustar00rootroot00000000000000# a comment show-read-feeds no browser "firefox" max-items 100 # another comment cache-file "~/foo" # yet another comment macro k open ; reload ; reload-all ; mark-feed-read ; save ; next-unread macro j open "foo" "bar" baz ; "save" blafasel macro l ; ; ; macro m quit ; # and here's one more comment newsbeuter-2.7/test/test-dialogs.rb000066400000000000000000000042571220711462700174620ustar00rootroot00000000000000#!/usr/bin/env ruby # auto-generated tuitest script require 'tuitest' Tuitest.init verifier = Tuitest::Verifier.new("test-dialogs.rb.log", "RESULT-test-dialogs.rb.xml") Kernel.system("rm -f cache cache.lock") if ENV["OFFLINE"] then Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1-offline") else Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1") end Tuitest.wait_until_idle Tuitest.keypress("r"[0]) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.keypress("v"[0]) Tuitest.wait_until_idle # begin auto-generated verification #1 verifier.expect(0, 17, "Dialogs ") verifier.expect(1, 0, " 1 Feed List - 1 unread, 1 total") verifier.expect(2, 0, " 2 Article List - RSS 2.0 testbed feed") verifier.expect(3, 0, " 3 * Article - RSS 2.0 Item 1 ") verifier.expect(4, 0, " ") # end auto-generated verification #1 Tuitest.keypress(258) Tuitest.keypress(10) Tuitest.keypress(258) Tuitest.keypress(10) Tuitest.keypress("v"[0]) Tuitest.wait_until_idle # begin auto-generated verification #2 verifier.expect(3, 5, " ") verifier.expect(4, 3, "4 * Article - RSS 2.0 Item 2") # end auto-generated verification #2 Tuitest.keypress(258) Tuitest.keypress(258) Tuitest.keypress(258) Tuitest.keypress(24) Tuitest.wait_until_idle # begin auto-generated verification #3 verifier.expect(1, 5, "*") verifier.expect(4, 3, " ") # end auto-generated verification #3 Tuitest.keypress(24) Tuitest.wait_until_idle # begin auto-generated verification #4 verifier.expect(3, 3, " ") # end auto-generated verification #4 Tuitest.keypress(24) Tuitest.wait_until_idle # begin auto-generated verification #5 verifier.expect(2, 3, " ") # end auto-generated verification #5 Tuitest.keypress(24) Tuitest.wait_until_idle # begin auto-generated verification #6 verifier.expect(24, 0, "Error: you can't remove the feed list!") # end auto-generated verification #6 Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-dumpconfig.rb000066400000000000000000000014621220711462700201660ustar00rootroot00000000000000#!/usr/bin/env ruby # auto-generated tuitest script require 'tuitest' Tuitest.init verifier = Tuitest::Verifier.new("test-dumpconfig.rb.log", "RESULT-test-dumpconfig.rb.xml") Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1") Tuitest.wait_until_idle Tuitest.keypress(":"[0]) Tuitest.keypress("d"[0]) Tuitest.keypress("u"[0]) Tuitest.keypress(9) Tuitest.keypress(" "[0]) Tuitest.keypress("c"[0]) Tuitest.keypress("o"[0]) Tuitest.keypress("n"[0]) Tuitest.keypress("f"[0]) Tuitest.keypress("i"[0]) Tuitest.keypress("g"[0]) Tuitest.keypress("."[0]) Tuitest.keypress("d"[0]) Tuitest.keypress("u"[0]) Tuitest.keypress("m"[0]) Tuitest.keypress("p"[0]) Tuitest.keypress(10) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f config.dump cache") # EOF newsbeuter-2.7/test/test-feedlist.rb000066400000000000000000000062201220711462700176270ustar00rootroot00000000000000#!/usr/bin/env ruby # test misc. functionality of the feedlist dialog require 'tuitest' Kernel.system("rm -f cache cache.lock") Tuitest.init verifier = Tuitest::Verifier.new("test-feedlist.rb.log", "RESULT-test-feedlist.rb.xml") if ENV["OFFLINE"] then Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1-offline") else Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1") end Tuitest.wait_until_expected_text(0, 0, "newsbeuter") Tuitest.keypress(18) Tuitest.keypress("r"[0]) Tuitest.keypress("R"[0]) Tuitest.wait_until_idle Tuitest.keypress("A"[0]) Tuitest.keypress("l"[0]) Tuitest.wait_until_expected_text(0, 39, "0", 5000) # begin auto-generated verification #1 verifier.expect(0, 39, "0"); verifier.expect(1, 3, " ") # end auto-generated verification #1 Tuitest.keypress("l"[0]) Tuitest.wait_until_expected_text(0, 39, "1", 5000) # begin auto-generated verification #3 verifier.expect(0, 39, "1") verifier.expect(1, 3, "1 (0/3) RSS 2.0 testbed feed") # end auto-generated verification #3 Tuitest.keypress("n"[0]) Tuitest.keypress("p"[0]) Tuitest.keypress("C"[0]) Tuitest.keypress(20) Tuitest.keypress("t"[0]) Tuitest.keypress(10) Tuitest.keypress(20) Tuitest.keypress(10) Tuitest.keypress("q"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress(10) Tuitest.wait_until_expected_text(0, 48, "- tag ", 5000) # begin auto-generated verification #4 verifier.expect(0, 48, "- tag `mytag'") # end auto-generated verification #4 Tuitest.keypress(20) Tuitest.wait_until_expected_text(0, 48, " ", 5000) # begin auto-generated verification #5 verifier.expect(0, 48, " ") # end auto-generated verification #5 Tuitest.keypress("/"[0]) Tuitest.keypress("d"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("c"[0]) Tuitest.wait(1000) Tuitest.keypress(10) Tuitest.wait(1000) Tuitest.keypress(10) Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.keypress("/"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress(8) Tuitest.keypress(8) Tuitest.keypress(10) Tuitest.keypress(259) Tuitest.keypress(12) Tuitest.keypress("/"[0]) Tuitest.wait_until_expected_text(24, 0, "Search for:", 5000) # begin auto-generated verification #6 verifier.expect(24, 0, "Search for:") # end auto-generated verification #6 Tuitest.keypress("d"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("c"[0]) Tuitest.wait(2000) Tuitest.keypress(10) Tuitest.wait(2000) Tuitest.wait_until_expected_text(0, 17, "Search result (0 unread, 2 total)", 5000) # begin auto-generated verification #7 verifier.expect(0, 17, "Search result (0 unread, 2 total)") verifier.expect(1, 3, "1 Aug 29 67 |RSS 2.0 testbed f| RSS 2.0 Item 2") verifier.expect(2, 3, "2 Aug 28 170 |RSS 2.0 testbed f| RSS 2.0 Item 3") # end auto-generated verification #7 Tuitest.keypress(10) Tuitest.keypress("q"[0]) Tuitest.keypress(258) Tuitest.keypress(10) Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-feedlist2.rb000066400000000000000000000137141220711462700177170ustar00rootroot00000000000000#!/usr/bin/env ruby # auto-generated tuitest script require 'tuitest' Tuitest.init verifier = Tuitest::Verifier.new("test-feedlist2.rb.log", "RESULT-test-feedlist2.rb.xml") Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-feedlist") Tuitest.wait_until_idle Tuitest.keypress("n"[0]) Tuitest.wait_until_idle verifier.expect(24, 0, "No feeds with unread items.") Tuitest.keypress("r"[0]) Tuitest.wait_until_idle verifier.expect(1, 5, "N (3/3) HTML rendering testbed feed ") Tuitest.keypress(258) Tuitest.keypress("r"[0]) Tuitest.wait_until_idle verifier.expect(2, 5, "N (1/1) html table rendering testbed feed ") Tuitest.keypress(258) Tuitest.keypress("r"[0]) Tuitest.wait_until_idle verifier.expect(3, 5, "N (3/3) RSS 2.0 testbed feed ") Tuitest.keypress("p"[0]) Tuitest.keypress("p"[0]) Tuitest.keypress(10) Tuitest.wait_until_idle verifier.expect(0, 17, "Articles in feed 'HTML rendering testbed feed' (3 unread, 3 tot") verifier.expect(1, 8, "Aug 30 405 HTML Item 1 ") verifier.expect(2, 8, "Aug 29 394 HTML Item 2 ") verifier.expect(3, 8, "Aug 28 187 HTML Item 3 ") Tuitest.keypress("q"[0]) Tuitest.keypress("n"[0]) Tuitest.keypress(10) Tuitest.wait_until_idle verifier.expect(0, 35, "html table rendering testbed feed' (1 unread,") verifier.expect(1, 17, "291 table item 1") verifier.expect(2, 3, " ") verifier.expect(3, 3, " ") Tuitest.keypress("q"[0]) Tuitest.keypress("n"[0]) Tuitest.keypress(10) Tuitest.wait_until_idle verifier.expect(0, 35, "RSS 2.0 testbed feed' (3 unread, 3 total) - h") verifier.expect(1, 18, "12 RSS 2.0 Item 1") verifier.expect(2, 3, "2 N Aug 29 67 RSS 2.0 Item 2") verifier.expect(3, 3, "3 N Aug 28 170 RSS 2.0 Item 3") Tuitest.keypress("q"[0]) Tuitest.keypress("g"[0]) Tuitest.keypress("t"[0]) Tuitest.wait_until_idle verifier.expect(0, 17, "Your feeds (3 unread, 3 total) ") verifier.expect(1, 8, " (3/3) HTML rendering testbed feed") verifier.expect(2, 8, " (1/1) html table rendering testbed feed") verifier.expect(3, 8, " (3/3) RSS 2.0 testbed feed") verifier.expect(23, 18, "n:Next Unread r:Reload R:Reload All A:Mark Read C:Catchup All") Tuitest.keypress("g"[0]) Tuitest.keypress("a"[0]) Tuitest.wait_until_idle verifier.expect(1, 14, "1/1) html table rendering testbed feed") verifier.expect(2, 14, "3/3) HTML rendering testbed feed ") Tuitest.keypress("g"[0]) Tuitest.keypress("n"[0]) Tuitest.wait_until_idle verifier.expect(1, 14, "3/3) HTML rendering testbed feed ") verifier.expect(2, 14, "1/1) html table rendering testbed feed") Tuitest.keypress("g"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("G"[0]) Tuitest.keypress("t"[0]) Tuitest.wait_until_idle verifier.expect(1, 19, "RSS 2.0 testbed feed ") verifier.expect(3, 19, "HTML rendering testbed feed") Tuitest.keypress("G"[0]) Tuitest.keypress("a"[0]) Tuitest.wait_until_idle verifier.expect(1, 19, "HTML rendering testbed feed") verifier.expect(2, 14, "3/3) RSS 2.0 testbed feed ") verifier.expect(3, 14, "1/1) html table rendering testbed feed") Tuitest.keypress("F"[0]) Tuitest.keypress("f"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("d"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("i"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("l"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress(" "[0]) Tuitest.keypress("="[0]) Tuitest.keypress("~"[0]) Tuitest.keypress(" "[0]) Tuitest.keypress("\""[0]) Tuitest.keypress("h"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("m"[0]) Tuitest.keypress("l"[0]) Tuitest.keypress("\""[0]) Tuitest.keypress(10) Tuitest.wait_until_idle verifier.expect(0, 29, "2 unread, 2") verifier.expect(2, 3, "3 N (1/1) html table rendering testbed feed") verifier.expect(3, 3, " ") Tuitest.keypress(6) Tuitest.wait_until_idle verifier.expect(0, 29, "3 unread, 3") verifier.expect(2, 3, "2 N (3/3) RSS 2.0 testbed feed ") verifier.expect(3, 3, "3 N (1/1) html table rendering testbed feed") Tuitest.keypress("F"[0]) Tuitest.keypress(259) Tuitest.keypress(260) Tuitest.keypress(260) Tuitest.keypress(260) Tuitest.keypress(260) Tuitest.keypress(260) Tuitest.keypress(260) Tuitest.keypress(260) Tuitest.keypress(260) Tuitest.keypress(263) Tuitest.keypress(260) Tuitest.keypress(330) Tuitest.keypress("!"[0]) Tuitest.keypress(10) Tuitest.wait_until_idle verifier.expect(0, 29, "1 unread, 1") verifier.expect(1, 3, "2 N (3/3) RSS 2.0 testbed feed ") verifier.expect(2, 3, " ") verifier.expect(3, 3, " ") Tuitest.keypress(6) Tuitest.wait_until_idle verifier.expect(0, 29, "3 unread, 3") verifier.expect(1, 3, "1 N (3/3) HTML rendering testbed feed") verifier.expect(2, 3, "2 N (3/3) RSS 2.0 testbed feed") verifier.expect(3, 3, "3 N (1/1) html table rendering testbed feed") Tuitest.keypress("?"[0]) Tuitest.wait_until_idle verifier.expect(0, 17, "Help ") Tuitest.keypress("q"[0]) Tuitest.wait_until_idle verifier.expect(0, 17, "Your feeds (3 unread, 3 total)") verifier.expect(1, 0, " 1 N (3/3) HTML rendering testbed feed ") verifier.expect(2, 0, " 2 N (3/3) RSS 2.0 testbed feed ") verifier.expect(3, 0, " 3 N (1/1) html table rendering testbed feed ") verifier.expect(4, 0, " ") Tuitest.keypress(":"[0]) Tuitest.keypress("1"[0]) Tuitest.keypress(10) Tuitest.keypress("p"[0]) Tuitest.keypress(10) Tuitest.wait_until_idle verifier.expect(0, 17, "Articles in feed 'html table rendering testbed feed' (1 unread,") Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-feedlist3.rb000066400000000000000000000045051220711462700177160ustar00rootroot00000000000000#!/usr/bin/env ruby # auto-generated tuitest script require 'tuitest' Tuitest.init verifier = Tuitest::Verifier.new("test-feedlist3.rb.log", "RESULT-test-feedlist3.rb.xml") Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-feedlist") Tuitest.wait_until_idle Tuitest.keypress("r"[0]) Tuitest.keypress(258) Tuitest.keypress("r"[0]) Tuitest.keypress(258) Tuitest.keypress("r"[0]) Tuitest.wait_until_idle verifier.expect(1, 3, "1 N (3/3) HTML rendering testbed feed") verifier.expect(2, 3, "2 N (1/1) html table rendering testbed feed") verifier.expect(3, 3, "3 N (3/3) RSS 2.0 testbed feed") verifier.expect(23, 0, "q:Quit ENTER:Open n:Next Unread r:Reload R:Reload All A:Mark Read C:Catchup All") Tuitest.keypress(":"[0]) Tuitest.keypress("g"[0]) Tuitest.keypress("o"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("o"[0]) Tuitest.keypress(" "[0]) Tuitest.keypress("h"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("m"[0]) Tuitest.keypress("l"[0]) Tuitest.keypress(" "[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("n"[0]) Tuitest.keypress("d"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("i"[0]) Tuitest.keypress("n"[0]) Tuitest.keypress("g"[0]) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.wait_until_idle verifier.expect(0, 17, "Articles in feed 'HTML rendering testbed feed' (3 unread, 3 tot") Tuitest.keypress("q"[0]) Tuitest.keypress(":"[0]) Tuitest.keypress("g"[0]) Tuitest.keypress("o"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("o"[0]) Tuitest.keypress(" "[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.wait_until_idle verifier.expect(0, 35, "RSS 2.0 testbed feed' (3 unread, 3 total) - h") Tuitest.keypress("q"[0]) Tuitest.keypress(":"[0]) Tuitest.keypress("g"[0]) Tuitest.keypress("o"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("o"[0]) Tuitest.keypress(" "[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("b"[0]) Tuitest.keypress("l"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.wait_until_idle verifier.expect(0, 35, "html table rendering testbed feed' (1 unread,") Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-filters.rb000066400000000000000000000030421220711462700174770ustar00rootroot00000000000000#!/usr/bin/env ruby # script to test pre-defined filters require 'tuitest' Kernel.system("rm -f cache cache.lock") Tuitest.init verifier = Tuitest::Verifier.new("test-filters.rb.log", "RESULT-test-filters.rb.xml") if ENV["OFFLINE"] then Tuitest.run("../newsbeuter -c cache -C config-filter -u urls-tuitest1-offline") else Tuitest.run("../newsbeuter -c cache -C config-filter -u urls-tuitest1") end Tuitest.wait_until_expected_text(0, 0, "newsbeuter ", 5000) Tuitest.keypress("r"[0]) Tuitest.keypress("f"[0]) Tuitest.keypress(10) Tuitest.wait_until_expected_text(24, 0, "Error: applying the filter failed: attribute `unread' is not available.", 5000) # begin auto-generated verification #1 verifier.expect(24, 0, "Error: applying the filter failed: attribute `unread' is not available.") # end auto-generated verification #1 Tuitest.keypress(10) Tuitest.keypress(258) Tuitest.keypress(258) Tuitest.keypress("f"[0]) Tuitest.keypress(10) Tuitest.keypress("N"[0]) Tuitest.wait_until_expected_text(0, 58, "2", 5000) # begin auto-generated verification #3 verifier.expect(0, 58, "2") verifier.expect(3, 5, " ") # end auto-generated verification #3 Tuitest.keypress("f"[0]) Tuitest.keypress(10) Tuitest.wait_until_expected_text(3, 3, " ", 5000) # begin auto-generated verification #4 verifier.expect(3, 3, " ") # end auto-generated verification #4 Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-formaction.rb000066400000000000000000000035241220711462700201750ustar00rootroot00000000000000#!/usr/bin/env ruby # auto-generated tuitest script require 'tuitest' Tuitest.init verifier = Tuitest::Verifier.new("test-formaction.rb.log", "RESULT-test-formaction.rb.xml") Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1") Tuitest.wait_until_idle Tuitest.keypress(":"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress(9) Tuitest.wait_until_idle # begin auto-generated verification #1 verifier.expect(0, 14, " - Your feeds (0 unread, 1 total)") verifier.expect(1, 3, "1 (0/0) http://testbed.newsbeuter.org/rss20.xml") verifier.expect(23, 0, "q:Quit ENTER:Open n:Next Unread r:Reload R:Reload All A:Mark Read C:Catchup All") verifier.expect(24, 0, ":set") # end auto-generated verification #1 Tuitest.keypress(9) Tuitest.wait_until_idle # begin auto-generated verification #2 verifier.expect(24, 2, "ource") # end auto-generated verification #2 Tuitest.keypress(9) Tuitest.wait_until_idle # begin auto-generated verification #3 verifier.expect(24, 2, "et ") # end auto-generated verification #3 Tuitest.keypress(" "[0]) Tuitest.keypress(9) Tuitest.wait_until_idle # begin auto-generated verification #4 verifier.expect(24, 5, "always-display-description") # end auto-generated verification #4 Tuitest.keypress(9) Tuitest.wait_until_idle # begin auto-generated verification #5 verifier.expect(24, 6, "rticle-sort-order ") # end auto-generated verification #5 Tuitest.keypress(9) Tuitest.wait_until_idle # begin auto-generated verification #6 verifier.expect(24, 12, "list-format") # end auto-generated verification #6 Tuitest.keypress(7) Tuitest.wait_until_idle # begin auto-generated verification #7 verifier.expect(24, 0, " ") # end auto-generated verification #7 Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache") # EOF newsbeuter-2.7/test/test-html.rb000066400000000000000000000110251220711462700167730ustar00rootroot00000000000000#!/usr/bin/env ruby # script to test HTML rendering. require 'tuitest' Kernel.system("rm -f cache cache.lock") Tuitest.init verifier = Tuitest::Verifier.new("test-html.rb.log", "RESULT-test-html.rb.xml") if ENV["OFFLINE"] then Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-html-offline") else Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-html") end Tuitest.wait_until_expected_text(0, 0, "newsbeuter ", 5000) Tuitest.keypress("r"[0]) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.wait_until_expected_text(0, 24, " 'HTML Item 1' ", 5000) # begin auto-generated verification #1 verifier.expect(0, 24, " 'HTML Item 1' ") verifier.expect(1, 0, "Feed: HTML rendering testbed feed") verifier.expect(2, 0, "Title: HTML Item 1 ") verifier.expect(3, 0, "Author: Andreas Krennmair") verifier.expect(4, 0, "Link: http://testbed.newsbeuter.org/htmlitem1.html") verifier.expect(5, 0, "Date: Sat, 30 Aug 2008 09:40:10") verifier.expect(7, 0, "normal link[1]") verifier.expect(8, 0, "invalid link without href.") verifier.expect(9, 0, "[embedded flash: 2]") verifier.expect(10, 0, "hello world") verifier.expect(11, 0, "hello world") verifier.expect(12, 0, "hello world") verifier.expect(13, 1, "-------------------------------------------------------------------------") verifier.expect(14, 0, "[image 3]") verifier.expect(15, 1, "-------------------------------------------------------------------------") verifier.expect(17, 2, "To be or not to be, that is the question.") verifier.expect(20, 0, "Links:") verifier.expect(21, 0, "[1]: http://www.newsbeuter.org/ (link)") verifier.expect(22, 0, "[2]: http://www.youtube.com/v/BLjDXxjkrWc (embedded flash)") verifier.expect(23, 14, "n:Next Unread o:Open in Browser e:Enqueue ?:Help ") # end auto-generated verification #1 Tuitest.keypress("n"[0]) Tuitest.wait_until_expected_text(0, 36, "2", 5000) # begin auto-generated verification #2 verifier.expect(0, 36, "2") verifier.expect(2, 17, "2") verifier.expect(4, 44, "2") verifier.expect(5, 6, "Fri, 29") verifier.expect(7, 0, "Lorem ipsum dolor sit amet, consectetuer sadipscing elitr, sed diam nonumy") verifier.expect(8, 0, "eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam") verifier.expect(9, 0, "voluptua. ") verifier.expect(10, 0, " ") verifier.expect(11, 0, "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd") verifier.expect(12, 0, "gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem") verifier.expect(13, 0, "ipsum dolor sit amet, consetetur sadipscing elitr, ... ") verifier.expect(14, 0, "~ ") verifier.expect(15, 0, "~ ") verifier.expect(16, 0, "~") verifier.expect(17, 0, "~ ") verifier.expect(18, 0, "~") verifier.expect(19, 0, "~") verifier.expect(20, 0, "~ ") verifier.expect(21, 0, "~ ") verifier.expect(22, 0, "~ ") # end auto-generated verification #2 Tuitest.keypress("n"[0]) Tuitest.wait_until_expected_text(0, 36, "3", 5000) # begin auto-generated verification #3 verifier.expect(0, 36, "3") verifier.expect(2, 17, "3") verifier.expect(4, 44, "4") verifier.expect(5, 6, "Thu, 28") verifier.expect(7, 0, " ") verifier.expect(8, 0, " 1.one ") verifier.expect(9, 0, " 2.two ") verifier.expect(10, 1, "3.three") verifier.expect(11, 0, " ") verifier.expect(12, 0, " -------------------------------------------------------------------------") verifier.expect(13, 0, " ") verifier.expect(14, 0, " * hello") verifier.expect(15, 0, " * world") verifier.expect(16, 0, " ") verifier.expect(17, 0, " -------------------------------------------------------------------------") verifier.expect(18, 0, "a[0] = 23") verifier.expect(19, 0, "a[1] = 42") verifier.expect(20, 0, "E = mc^2") verifier.expect(21, 0, " -------------------------------------------------------------------------") # end auto-generated verification #3 Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-htmltables.rb000066400000000000000000000021701220711462700201670ustar00rootroot00000000000000#!/usr/bin/env ruby # auto-generated tuitest script require 'tuitest' Tuitest.init verifier = Tuitest::Verifier.new("test-htmltables.rb.log", "RESULT-test-htmltables.rb.xml") Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tables") Tuitest.wait_until_idle Tuitest.keypress("r"[0]) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.wait_until_idle verifier.expect(6, 0, "+--------+--------+--------+") verifier.expect(7, 0, "|Column 1|Column 2|Column 3|") verifier.expect(8, 0, "+--------+--------+--------+") verifier.expect(9, 0, "|data 1 |data 2 |data 3 |") verifier.expect(10, 0, "+--------+--------+--------+") verifier.expect(11, 0, "|data 1-2 |data 3 |") verifier.expect(12, 0, "+--------+--------+--------+") verifier.expect(13, 0, "|data 1 |data 2-3 |") verifier.expect(14, 0, "+--------+--------+--------+") verifier.expect(15, 0, "|data 1-3 |") verifier.expect(16, 0, "+--------+--------+--------+") Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-itemlist.rb000066400000000000000000000113741220711462700176700ustar00rootroot00000000000000#!/usr/bin/env ruby # auto-generated tuitest script require 'tuitest' Tuitest.init verifier = Tuitest::Verifier.new("test-itemlist.rb.log", "RESULT-test-itemlist.rb.xml") Kernel.system("rm -f cache cache.lock") if ENV["OFFLINE"] then Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1-offline") else Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1") end Tuitest.wait_until_idle Tuitest.keypress("r"[0]) Tuitest.keypress(10) Tuitest.keypress(":"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress(" "[0]) Tuitest.keypress("b"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("o"[0]) Tuitest.keypress("w"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("="[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("u"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress(10) Tuitest.keypress("o"[0]) Tuitest.keypress("u"[0]) Tuitest.wait_until_idle # begin auto-generated verification #1 verifier.expect(24, 0, "URL list empty.") # end auto-generated verification #1 Tuitest.keypress(258) Tuitest.keypress("u"[0]) Tuitest.keypress(258) Tuitest.keypress("u"[0]) Tuitest.wait_until_idle # begin auto-generated verification #2 verifier.expect(0, 17, "URLs") verifier.expect(1, 1, "1 http://slashdot.org/ ") verifier.expect(2, 3, " ") # end auto-generated verification #2 Tuitest.keypress("q"[0]) Tuitest.keypress(2) Tuitest.wait_until_idle # begin auto-generated verification #3 verifier.expect(0, 17, "Articles in feed 'RSS 2.0 testbed feed' (3 unread, 3 total)") verifier.expect(1, 1, " 1 N Aug 30 212 RSS 2.0 Item 1") verifier.expect(2, 3, "2 N Aug 29 67 RSS 2.0 Item 2") verifier.expect(3, 3, "3 N Aug 28 170 RSS 2.0 Item 3") verifier.expect(24, 0, "URL: http://testbed.newsbeuter.org/item3.html") # end auto-generated verification #3 Tuitest.keypress(10) Tuitest.wait_until_idle # begin auto-generated verification #4 verifier.expect(24, 0, "Title: RSS 2.0 Item 3") # end auto-generated verification #4 Tuitest.keypress(10) Tuitest.keypress("t"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("t"[0]) Tuitest.wait_until_idle # begin auto-generated verification #5 verifier.expect(24, 0, "Description: test ") # end auto-generated verification #5 Tuitest.keypress(10) Tuitest.wait_until_idle # begin auto-generated verification #6 verifier.expect(24, 0, "Error while saving bookmark: bookmarking support is not configured. Please set t") # end auto-generated verification #6 Tuitest.keypress(5) Tuitest.keypress("a"[0]) Tuitest.keypress("b"[0]) Tuitest.keypress("c"[0]) Tuitest.wait_until_idle # begin auto-generated verification #7 verifier.expect(24, 0, "Flags: abc ") # end auto-generated verification #7 Tuitest.keypress(10) Tuitest.wait_until_idle # begin auto-generated verification #8 verifier.expect(3, 6, "!") verifier.expect(24, 5, " updated.") # end auto-generated verification #8 Tuitest.keypress("s"[0]) Tuitest.wait(1000) Tuitest.wait_until_idle # begin auto-generated verification #9 verifier.expect(0, 17, "Save File - ") verifier.expect(23, 2, "Cancel ENTER:Save ") verifier.expect(24, 0, " ") # end auto-generated verification #9 Tuitest.keypress(259) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle # begin auto-generated verification #10 verifier.expect(0, 17, "Articles in feed 'RSS 2.0 testbed feed' (3 unread, 3 total)") verifier.expect(1, 0, " 1 N Aug 30 212 RSS 2.0 Item 1 ") verifier.expect(2, 0, " 2 N Aug 29 67 RSS 2.0 Item 2 ") verifier.expect(3, 0, " 3 N! Aug 28 170 RSS 2.0 Item 3 ") verifier.expect(4, 0, " ") verifier.expect(24, 0, "Aborted saving.") # end auto-generated verification #10 Tuitest.keypress("?"[0]) Tuitest.wait_until_idle # begin auto-generated verification #11 verifier.expect(0, 17, "Help") # end auto-generated verification #11 Tuitest.keypress("q"[0]) Tuitest.keypress("n"[0]) Tuitest.keypress("n"[0]) Tuitest.keypress("n"[0]) Tuitest.keypress("p"[0]) Tuitest.keypress("p"[0]) Tuitest.keypress("p"[0]) Tuitest.keypress(16) Tuitest.keypress("A"[0]) Tuitest.keypress(16) Tuitest.wait_until_idle # begin auto-generated verification #12 verifier.expect(0, 58, "0") verifier.expect(1, 5, " ") verifier.expect(2, 5, " ") verifier.expect(3, 5, " ") verifier.expect(24, 0, "No unread feeds.") # end auto-generated verification #12 Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-itemlist2.rb000066400000000000000000000103511220711462700177440ustar00rootroot00000000000000#!/usr/bin/env ruby # auto-generated tuitest script require 'tuitest' Tuitest.init verifier = Tuitest::Verifier.new("test-itemlist2.rb.log", "RESULT-test-itemlist2.rb.xml") Kernel.system("rm -f cache cache.lock") if ENV["OFFLINE"] then Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1-offline") else Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1") end Tuitest.wait_until_idle Tuitest.keypress("r"[0]) Tuitest.keypress(10) Tuitest.keypress(":"[0]) Tuitest.keypress("3"[0]) Tuitest.keypress(10) Tuitest.keypress("N"[0]) Tuitest.keypress(12) Tuitest.keypress(10) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle # begin auto-generated verification #1 verifier.expect(0, 58, "2") verifier.expect(3, 5, " ") # end auto-generated verification #1 Tuitest.keypress(":"[0]) Tuitest.keypress("1"[0]) Tuitest.keypress(10) Tuitest.keypress("N"[0]) Tuitest.wait_until_idle # begin auto-generated verification #2 verifier.expect(0, 58, "1") verifier.expect(1, 5, " ") # end auto-generated verification #2 Tuitest.keypress(259) Tuitest.keypress("N"[0]) Tuitest.keypress(258) Tuitest.keypress("N"[0]) Tuitest.keypress(":"[0]) Tuitest.keypress("1"[0]) Tuitest.keypress(10) Tuitest.keypress(":"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress(" "[0]) Tuitest.keypress("m"[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("k"[0]) Tuitest.keypress("-"[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("-"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("d"[0]) Tuitest.keypress("-"[0]) Tuitest.keypress("o"[0]) Tuitest.keypress("n"[0]) Tuitest.keypress("-"[0]) Tuitest.keypress("h"[0]) Tuitest.keypress("o"[0]) Tuitest.keypress("v"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("="[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("u"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress(10) Tuitest.keypress(258) Tuitest.wait_until_idle # begin auto-generated verification #3 verifier.expect(0, 58, "1") verifier.expect(2, 5, " ") # end auto-generated verification #3 Tuitest.keypress(258) Tuitest.wait_until_idle # begin auto-generated verification #4 verifier.expect(0, 58, "0") verifier.expect(3, 5, " ") # end auto-generated verification #4 Tuitest.keypress(":"[0]) Tuitest.keypress("1"[0]) Tuitest.keypress(10) Tuitest.keypress("N"[0]) Tuitest.keypress("N"[0]) Tuitest.keypress("N"[0]) Tuitest.wait_until_idle # begin auto-generated verification #5 verifier.expect(0, 58, "2") verifier.expect(1, 5, "N") verifier.expect(2, 5, "N") # end auto-generated verification #5 Tuitest.keypress(":"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress(" "[0]) Tuitest.keypress("m"[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("k"[0]) Tuitest.keypress("-"[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("-"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("d"[0]) Tuitest.keypress("-"[0]) Tuitest.keypress("o"[0]) Tuitest.keypress("n"[0]) Tuitest.keypress("-"[0]) Tuitest.keypress("h"[0]) Tuitest.keypress("o"[0]) Tuitest.keypress("v"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("="[0]) Tuitest.keypress("f"[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("l"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress(10) Tuitest.keypress("N"[0]) Tuitest.keypress(":"[0]) Tuitest.keypress("1"[0]) Tuitest.keypress(10) Tuitest.keypress("N"[0]) Tuitest.wait_until_idle # begin auto-generated verification #6 verifier.expect(0, 58, "2") verifier.expect(1, 5, " ") # end auto-generated verification #6 Tuitest.keypress("N"[0]) Tuitest.wait_until_idle # begin auto-generated verification #7 verifier.expect(0, 58, "1") verifier.expect(2, 5, " ") # end auto-generated verification #7 Tuitest.keypress("N"[0]) Tuitest.wait_until_idle # begin auto-generated verification #8 verifier.expect(0, 58, "0") verifier.expect(3, 5, " ") # end auto-generated verification #8 Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-itemview.rb000066400000000000000000000061001220711462700176560ustar00rootroot00000000000000#!/usr/bin/env ruby # test misc. functions of itemview. require 'tuitest' Kernel.system("rm -f cache cache.lock") Tuitest.init verifier = Tuitest::Verifier.new("test-itemview.rb.log", "RESULT-test-itemview.rb.xml") if ENV["OFFLINE"] then Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1-offline") else Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1") end Tuitest.wait_until_expected_text(0, 0, "newsbeuter ") Tuitest.keypress("r"[0]) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.keypress(" "[0]) Tuitest.keypress("b"[0]) Tuitest.keypress(21) Tuitest.wait_until_idle Tuitest.wait_until_expected_text(7, 0, " ", 5000) # begin auto-generated verification #1 verifier.expect(7, 0, " ") verifier.expect(8, 0, "

    This is some example content.

    ") verifier.expect(9, 0, "

    Here's a line break.
    ") verifier.expect(10, 0, " Second line. And now we try an unordered list.

    ") verifier.expect(11, 0, "
      ") verifier.expect(12, 0, "
    • first entry
    • ") verifier.expect(13, 0, "
    • second entry
    • ") verifier.expect(14, 0, "
    • third entry
    • ") verifier.expect(15, 0, "
    ") verifier.expect(16, 0, " ") # end auto-generated verification #1 Tuitest.keypress(21) Tuitest.wait_until_expected_text(7, 0, "This is some example content.", 5000) # begin auto-generated verification #2 verifier.expect(7, 0, "This is some example content.") verifier.expect(8, 0, " ") verifier.expect(9, 0, "Here's a line break. ") verifier.expect(10, 0, "Second line. And now we try an unordered list.") verifier.expect(11, 0, " ") verifier.expect(12, 0, " * first entry ") verifier.expect(13, 0, " * second entry ") verifier.expect(14, 0, " * third entry ") verifier.expect(15, 0, " ") verifier.expect(16, 0, "~") # end auto-generated verification #2 Tuitest.keypress("s"[0]) Tuitest.keypress(259) Tuitest.keypress("q"[0]) Tuitest.keypress(2) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.wait_until_expected_text(24, 0, "Error while saving bookmark: bookmarking support is not configured. Please set t", 5000) # begin auto-generated verification #3 verifier.expect(24, 0, "Error while saving bookmark: bookmarking support is not configured. Please set t") # end auto-generated verification #3 Tuitest.keypress("p"[0]) Tuitest.keypress(":"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("v"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress(" "[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("i"[0]) Tuitest.keypress("c"[0]) Tuitest.keypress("l"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("."[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("x"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress(10) Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache article.txt cache.lock") # EOF newsbeuter-2.7/test/test-loadconfig.rb000066400000000000000000000020241220711462700201330ustar00rootroot00000000000000#!/usr/bin/env ruby # auto-generated tuitest script require 'tuitest' Kernel.system("rm -f cache cache.lock") Tuitest.init verifier = Tuitest::Verifier.new("test-loadconfig.rb.log", "RESULT-test-loadconfig.rb.xml") if ENV["OFFLINE"] then Tuitest.run("../newsbeuter -c cache -C config-example -u urls-tuitest1-offline") else Tuitest.run("../newsbeuter -c cache -C config-example -u urls-tuitest1") end Tuitest.wait_until_expected_text(0, 17, "Your feeds (0 unread, 1 total)", 5000) # begin auto-generated verification #1 verifier.expect(0, 17, "Your feeds (0 unread, 1 total)") if ENV["OFFLINE"] then verifier.expect(1, 3, "1 (0/0) file://./testbed/rss20.xml") else verifier.expect(1, 3, "1 (0/0) http://testbed.newsbeuter.org/rss20.xml") end verifier.expect(23, 0, "q:Quit ENTER:Open n:Next Unread r:Reload R:Reload All A:Mark Read C:Catchup All") # end auto-generated verification #1 Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-misc.rb000066400000000000000000000201701220711462700167630ustar00rootroot00000000000000#!/usr/bin/env ruby # auto-generated tuitest script require 'tuitest' Tuitest.init verifier = Tuitest::Verifier.new("test-misc.rb.log", "RESULT-test-misc.rb.xml") Kernel.system("rm -f cache cache.lock") if ENV["OFFLINE"] then Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1-offline") else Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1") end Tuitest.wait_until_idle Tuitest.keypress("r"[0]) Tuitest.keypress(18) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.keypress(":"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress(" "[0]) Tuitest.keypress("d"[0]) Tuitest.keypress("i"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("p"[0]) Tuitest.keypress("l"[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("y"[0]) Tuitest.keypress("-"[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("i"[0]) Tuitest.keypress("c"[0]) Tuitest.keypress("l"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("-"[0]) Tuitest.keypress("p"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("o"[0]) Tuitest.keypress("g"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("="[0]) Tuitest.keypress("f"[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("l"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress(10) Tuitest.wait(100) Tuitest.keypress("q"[0]) Tuitest.keypress(10) Tuitest.keypress(":"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress(" "[0]) Tuitest.keypress("d"[0]) Tuitest.keypress("i"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("p"[0]) Tuitest.keypress("l"[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("y"[0]) Tuitest.keypress("-"[0]) Tuitest.keypress("p"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("o"[0]) Tuitest.keypress("g"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("-"[0]) Tuitest.keypress(8) Tuitest.keypress(260) Tuitest.keypress(260) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(10) Tuitest.wait(100) Tuitest.keypress(":"[0]) Tuitest.keypress(259) Tuitest.keypress(259) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(261) Tuitest.keypress(8) Tuitest.keypress(8) Tuitest.keypress(8) Tuitest.keypress(8) Tuitest.wait(100) Tuitest.keypress(260) Tuitest.keypress(260) Tuitest.keypress(260) Tuitest.keypress(260) Tuitest.keypress(260) Tuitest.keypress(330) Tuitest.keypress(330) Tuitest.keypress(330) Tuitest.keypress(330) Tuitest.keypress(330) Tuitest.keypress("t"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("u"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress(10) Tuitest.wait(100) Tuitest.keypress("q"[0]) Tuitest.keypress(5) Tuitest.keypress("a"[0]) Tuitest.keypress("b"[0]) Tuitest.keypress("c"[0]) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.keypress("q"[0]) Tuitest.keypress(5) Tuitest.keypress(330) Tuitest.keypress(330) Tuitest.keypress(330) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.keypress(21) Tuitest.wait(1000) Tuitest.wait_until_idle # begin auto-generated verification #1 verifier.expect(8, 0, " ") verifier.expect(9, 0, "

    This is some example content.

    ") verifier.expect(10, 0, "

    Here's a line break.
    ") verifier.expect(11, 0, " Second line. And now we try an unordered list.

    ") verifier.expect(12, 0, "
      ") verifier.expect(13, 0, "
    • first entry
    • ") verifier.expect(14, 0, "
    • second entry
    • ") verifier.expect(15, 0, "
    • third entry
    • ") verifier.expect(16, 0, "
    ") verifier.expect(17, 0, " ") # end auto-generated verification #1 Tuitest.keypress(21) Tuitest.keypress("q"[0]) Tuitest.keypress(":"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress(" "[0]) Tuitest.keypress("h"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("m"[0]) Tuitest.keypress("l"[0]) Tuitest.keypress("-"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("n"[0]) Tuitest.keypress("d"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("="[0]) Tuitest.keypress("c"[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.wait_until_idle # begin auto-generated verification #2 #verifier.expect(0, 24, " 'RSS 2.0 Item 1' ") verifier.expect(1, 0, "Feed: RSS 2.0 testbed feed ") verifier.expect(2, 0, "Title: RSS 2.0 Item 1 ") verifier.expect(3, 0, "Author: Andreas Krennmair") verifier.expect(4, 0, "Link: http://testbed.newsbeuter.org/item1.html") verifier.expect(5, 0, "Date: Sat, 30 Aug 2008 09:40:10 +0200") verifier.expect(9, 0, "

    This is some example content.

    ") verifier.expect(10, 0, "

    Here's a line break.
    ") verifier.expect(11, 0, " Second line. And now we try an unordered list.

    ") verifier.expect(12, 0, "
      ") verifier.expect(13, 0, "
    • first entry
    • ") verifier.expect(14, 0, "
    • second entry
    • ") verifier.expect(15, 0, "
    • third entry
    • ") verifier.expect(16, 0, "
    ") verifier.expect(17, 0, " ") verifier.expect(18, 0, "~") verifier.expect(19, 0, "~") verifier.expect(20, 0, "~") verifier.expect(21, 0, "~") verifier.expect(22, 0, "~") verifier.expect(23, 14, "n:Next Unread o:Open in Browser e:Enqueue ?:Help ") # end auto-generated verification #2 Tuitest.keypress("q"[0]) Tuitest.keypress(":"[0]) Tuitest.keypress("s"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress(" "[0]) Tuitest.keypress("h"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("m"[0]) Tuitest.keypress("l"[0]) Tuitest.keypress("-"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("n"[0]) Tuitest.keypress("d"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("="[0]) Tuitest.keypress("i"[0]) Tuitest.keypress("n"[0]) Tuitest.keypress("t"[0]) Tuitest.keypress("e"[0]) Tuitest.keypress("r"[0]) Tuitest.keypress("n"[0]) Tuitest.keypress("a"[0]) Tuitest.keypress("l"[0]) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.wait_until_idle # begin auto-generated verification #3 verifier.expect(8, 0, "This is some example content.") verifier.expect(9, 0, " ") verifier.expect(10, 0, "Here's a line break. ") verifier.expect(11, 0, "Second line. And now we try an unordered list.") verifier.expect(12, 0, " ") verifier.expect(13, 0, " * first entry ") verifier.expect(14, 0, " * second entry ") verifier.expect(15, 0, " * third entry ") verifier.expect(16, 0, " ") # end auto-generated verification #3 Tuitest.keypress("q"[0]) Tuitest.keypress(258) Tuitest.keypress(258) Tuitest.keypress(10) Tuitest.keypress("u"[0]) Tuitest.keypress(2) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.keypress(10) Tuitest.wait_until_idle # begin auto-generated verification #4 verifier.expect(24, 0, "Error while saving bookmark: bookmarking support is not configured. Please set t") # end auto-generated verification #4 Tuitest.keypress(":"[0]) Tuitest.keypress("1"[0]) Tuitest.keypress(10) Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-openalldialog.rb000066400000000000000000000034651220711462700206520ustar00rootroot00000000000000#!/usr/bin/env ruby # auto-generated tuitest script require 'tuitest' Kernel.system("rm -f cache cache.lock") Tuitest.init verifier = Tuitest::Verifier.new("test-openalldialog.rb.log", "RESULT-test-openalldialog.rb.xml") if ENV["OFFLINE"] then Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1-offline") else Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1") end Tuitest.wait_until_expected_text(0, 17, "Your feeds (0 unread, 1 total)", 5000) verifier.expect(0, 17, "Your feeds (0 unread, 1 total)") Tuitest.keypress("r"[0]) Tuitest.keypress(10) Tuitest.wait_until_expected_text(0, 17, "Articles in feed 'RSS 2.0 testbed feed' (3 unread, 3 total)", 5000) verifier.expect(0, 17, "Articles in feed 'RSS 2.0 testbed feed' (3 unread, 3 total)") Tuitest.keypress(258) Tuitest.keypress(258) Tuitest.keypress(10) Tuitest.wait_until_expected_text(0, 17, "Article ", 5000) verifier.expect(0, 17, "Article ") Tuitest.keypress("?"[0]) Tuitest.wait_until_expected_text(0, 17, "Help ", 5000) verifier.expect(0, 17, "Help ") Tuitest.keypress("q"[0]) Tuitest.keypress("u"[0]) Tuitest.wait_until_expected_text(0, 17, "URLs") verifier.expect(0, 17, "URLs") Tuitest.keypress("q"[0]) Tuitest.keypress("u"[0]) Tuitest.keypress("q"[0]) Tuitest.keypress("s"[0]) # begin auto-generated verification #6 Tuitest.wait_until_expected_text(0, 17, "Save File - ", 5000) verifier.expect(0, 17, "Save File - ") Tuitest.keypress(259) Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.keypress("t"[0]) Tuitest.wait_until_expected_text(0, 17, "Select Tag", 5000) verifier.expect(0, 17, "Select Tag") Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-opmlsrc.rb000066400000000000000000000021201220711462700175020ustar00rootroot00000000000000#!/usr/bin/env ruby # tests the urls-source "opml" configuration option require 'tuitest' Kernel.system("rm -f cache cache.lock") if not ENV["OFFLINE"] then # this test doesn't work in offline mode. Tuitest.init verifier = Tuitest::Verifier.new("test-opmlsrc.rb.log", "RESULT-test-opmlsrc.rb.xml") Tuitest.run("../newsbeuter -c cache -C config-tuitest2 -u /dev/null") Tuitest.wait_until_expected_text(1, 3, "1 (0/0) http://testbed.newsbeuter.org/rss20.xml", 5000) verifier.expect(1, 3, "1 (0/0) http://testbed.newsbeuter.org/rss20.xml") Tuitest.keypress("r"[0]) Tuitest.wait_until_expected_text(0, 29, "1", 5000) verifier.expect(0, 29, "1") verifier.expect(1, 5, "N (3/3) RSS 2.0 testbed feed ") Tuitest.keypress(":"[0]) Tuitest.keypress("3"[0]) Tuitest.keypress(10) Tuitest.keypress("r"[0]) Tuitest.wait_until_expected_text(3, 5, "N ", 5000) verifier.expect(3, 5, "N (2/2) newsbeuter testbed") Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") end # not ENV["OFFLINE"] # EOF newsbeuter-2.7/test/test-podbeuter-basic.rb000066400000000000000000000040451220711462700211030ustar00rootroot00000000000000#!/usr/bin/env ruby # auto-generated tuitest script require 'tuitest' Tuitest.init verifier = Tuitest::Verifier.new("test-podbeuter-basic.rb.log", "RESULT-test-podbeuter-basic.rb.xml") Tuitest.run("../podbeuter -C config-tuitest2 -q queue") Tuitest.wait_until_idle Tuitest.wait_until_idle # begin auto-generated verification #1 verifier.expect(0, 0, "Queue (0 downloads in progress, 1 total) - 0.00 kb/s total") verifier.expect(1, 4, "1 [ 0.0MB/ 0.0MB] [ 0.0 %] [ 0.00 kb/s] queued") verifier.expect(23, 0, "q:Quit d:Download c:Cancel D:Delete P:Purge Finished a:Toggle Automatic Download") # end auto-generated verification #1 Tuitest.keypress("?"[0]) Tuitest.wait_until_idle # begin auto-generated verification #2 verifier.expect(0, 0, "Help ") verifier.expect(1, 0, "ENTER open Open feed/article ") verifier.expect(2, 0, "q quit Return to previous dialog/Quit") verifier.expect(3, 0, "Q hard-quit Quit program, no confirmation") verifier.expect(4, 0, "? help Open help dialog") verifier.expect(5, 0, "d pb-download Download file") verifier.expect(6, 0, "c pb-cancel Cancel download") verifier.expect(7, 0, "D pb-delete Mark download as deleted") verifier.expect(8, 0, "P pb-purge Purge finished and deleted downloads from queue") verifier.expect(9, 0, "a pb-toggle-download-all Toggle automatic download on/off") verifier.expect(10, 0, "p pb-play Start player with currently selected download") verifier.expect(11, 0, "+ pb-increase-max-dls Increase the number of concurrent downloads") verifier.expect(12, 0, "- pb-decreate-max-dls Decrease the number of concurrent downloads") verifier.expect(13, 0, "~") # end auto-generated verification #2 Tuitest.keypress("q"[0]) Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish # EOF newsbeuter-2.7/test/test-podbeuter-basic2.rb000066400000000000000000000011631220711462700211630ustar00rootroot00000000000000#!/usr/bin/env ruby # auto-generated tuitest script require 'tuitest' Tuitest.init verifier = Tuitest::Verifier.new("test-podbeuter-basic2.rb.log", "RESULT-test-podbeuter-basic2.rb.xml") Tuitest.run("../podbeuter -C config-example -q queue") Tuitest.wait_until_idle Tuitest.wait_until_idle # begin auto-generated verification #1 verifier.expect(0, 0, "Queue (0 downloads in progress, 1 total) - 0.00 kb/s total") verifier.expect(1, 4, "1 [ 0.0MB/ 0.0MB] [ 0.0 %] [ 0.00 kb/s] queued") # end auto-generated verification #1 Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish # EOF newsbeuter-2.7/test/test-reloadall-retry.rb000066400000000000000000000014751220711462700211410ustar00rootroot00000000000000#!/usr/bin/env ruby # test "reload all" (which starts a background thread) require 'tuitest' Kernel.system("rm -f cache cache.lock") Tuitest.init verifier = Tuitest::Verifier.new("test-reloadall-retry.rb.log", "RESULT-test-reloadall-retry.rb.xml") if ENV["OFFLINE"] then Tuitest.run("../newsbeuter -c cache -C config-retry -u urls-tuitest1-offline") else Tuitest.run("../newsbeuter -c cache -C config-retry -u urls-tuitest1") end Tuitest.wait_until_expected_text(0, 0, "newsbeuter ", 5000) Tuitest.keypress("R"[0]) Tuitest.wait_until_expected_text(0, 29, "1", 5000) verifier.expect(0, 29, "1") verifier.expect(1, 5, "N (3/3) RSS 2.0 testbed feed ") Tuitest.keypress("q"[0]) Tuitest.wait(1000) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-reloadall.rb000066400000000000000000000014541220711462700177730ustar00rootroot00000000000000#!/usr/bin/env ruby # test "reload all" (which starts a background thread) require 'tuitest' Kernel.system("rm -f cache cache.lock") Tuitest.init verifier = Tuitest::Verifier.new("test-reloadall.rb.log", "RESULT-test-reloadall.rb.xml") if ENV["OFFLINE"] then Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1-offline") else Tuitest.run("../newsbeuter -c cache -C /dev/null -u urls-tuitest1") end Tuitest.wait_until_expected_text(0, 0, "newsbeuter ", 5000) Tuitest.keypress("R"[0]) Tuitest.wait_until_expected_text(0, 29, "1", 5000) verifier.expect(0, 29, "1") verifier.expect(1, 5, "N (3/3) RSS 2.0 testbed feed ") Tuitest.keypress("q"[0]) Tuitest.wait(1000) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-reloadthread.rb000066400000000000000000000014611220711462700204700ustar00rootroot00000000000000#!/usr/bin/env ruby # auto-generated tuitest script require 'tuitest' Kernel.system("rm -f cache cache.lock") Tuitest.init verifier = Tuitest::Verifier.new("test-reloadthread.rb.log", "RESULT-test-reloadthread.rb.xml") if ENV["OFFLINE"] then Tuitest.run("../newsbeuter -c cache -C config-reloadthread -u urls-tuitest1-offline") else Tuitest.run("../newsbeuter -c cache -C config-reloadthread -u urls-tuitest1") end Tuitest.wait_until_expected_text(0, 0, "newsbeuter ", 5000) Tuitest.keypress(271) Tuitest.wait_until_expected_text(1, 5, "N (3/3) RSS 2.0 testbed feed ", 5000) verifier.expect(1, 5, "N (3/3) RSS 2.0 testbed feed ") Tuitest.keypress("q"[0]) Tuitest.wait_until_idle Tuitest.close verifier.finish Kernel.system("rm -f cache cache.lock") # EOF newsbeuter-2.7/test/test-rss.cpp000066400000000000000000000147031220711462700170230ustar00rootroot00000000000000/* test driver for rsspp */ #include "lemon.h" #include #include int main(void) { lemon::test<> lemon(74); rsspp::parser p; // test of RSS 0.91 rsspp::feed f = p.parse_file("data/rss091_1.xml"); lemon.is(f.rss_version, rsspp::RSS_0_91, "RSS type is RSS 0.91"); lemon.is(f.title, "Example Channel", "RSS feed title is Example Channel"); lemon.is(f.description, "an example feed", "RSS feed description is 'an example feed'"); lemon.is(f.link, "http://example.com/", "RSS feed link is http://example.com/"); lemon.is(f.language, "en", "RSS feed language is en"); lemon.is(f.items.size(), 1u, "RSS feed contains 1 item"); lemon.is(f.items[0].title, "1 < 2", "item title with < entity"); lemon.is(f.items[0].link, "http://example.com/1_less_than_2.html", "item link"); lemon.is(f.items[0].description, "1 < 2, 3 < 4.\nIn HTML, starts a bold phrase\nand you start a link with
    #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace newsbeuter; namespace test { lemon::test<> lemon(0); void TestNewsbeuterReload() { configcontainer * cfg = new configcontainer(); cache * rsscache = new cache("test-cache.db", cfg); rss_parser parser("http://testbed.newsbeuter.org/unit-test/rss.xml", rsscache, cfg, NULL); std::tr1::shared_ptr feed = parser.parse(); lemon.is(feed->items().size(), 8u, "rss.xml contains 8 items"); rsscache->externalize_rssfeed(feed, false); rsscache->internalize_rssfeed(feed, NULL); lemon.is(feed->items().size(), 8u, "feed contains 8 items after externalization/internalization"); lemon.is(feed->items()[0]->title(), "Teh Saxxi", "first item title"); lemon.is(feed->items()[7]->title(), "Handy als IR-Detektor", "last item title"); feed->items()[0]->set_title("Another Title"); feed->items()[0]->set_pubDate(time(NULL)); lemon.is(feed->items()[0]->title(), "Another Title", "first item title after set_title"); rsscache->externalize_rssfeed(feed, false); std::tr1::shared_ptr feed2(new rss_feed(rsscache)); feed2->set_rssurl("http://testbed.newsbeuter.org/unit-test/rss.xml"); rsscache->internalize_rssfeed(feed2, NULL); lemon.is(feed2->items().size(), 8u, "feed2 contains 8 items after internalizaton"); lemon.is(feed2->items()[0]->title(), "Another Title", "feed2 first item title"); lemon.is(feed2->items()[7]->title(), "Handy als IR-Detektor", "feed2 last item title"); std::vector feedurls = rsscache->get_feed_urls(); lemon.is(feedurls.size(), 1u, "1 feed url"); lemon.is(feedurls[0], "http://testbed.newsbeuter.org/unit-test/rss.xml", "first feed url"); std::vector > feedv; feedv.push_back(feed); cfg->set_configvalue("cleanup-on-quit", "true"); rsscache->cleanup_cache(feedv); delete rsscache; delete cfg; ::unlink("test-cache.db"); } void TestConfigParserContainerAndKeymap() { configcontainer * cfg = new configcontainer(); configparser cfgparser; cfg->register_commands(cfgparser); keymap k(KM_NEWSBEUTER); cfgparser.register_handler("macro", &k); try { cfgparser.parse("test-config.txt"); } catch (const configexception& ex) { LOG(LOG_ERROR,"an exception occured while parsing the configuration file: %s", ex.what()); lemon.fail("TODO: description"); } catch (...) { lemon.fail("TODO: description"); } // test boolean config values lemon.is(cfg->get_configvalue("show-read-feeds"), "no", "show-read-feeds is no"); lemon.is(cfg->get_configvalue_as_bool("show-read-feeds"), false, "show-read-feeds as boolean is false"); // test string config values lemon.is(cfg->get_configvalue("browser"), "firefox", "browser is firefox"); // test integer config values lemon.is(cfg->get_configvalue("max-items"), "100", "max-items is 100"); lemon.is(cfg->get_configvalue_as_int("max-items"), 100, "max-items as integer is 100"); // test ~/ expansion for path config values std::string cachefilecomp = ::getenv("HOME"); cachefilecomp.append("/foo"); lemon.ok(cfg->get_configvalue("cache-file") == cachefilecomp, "cache-file is ~/foo (~ substitution test)"); delete cfg; lemon.is(k.get_operation("ENTER", "feedlist"), OP_OPEN, "ENTER in feedlist -> OP_OPEN"); lemon.is(k.get_operation("u", "article"), OP_SHOWURLS, "u in article -> OP_SHOWURLS"); lemon.is(k.get_operation("X", "feedlist"), OP_NIL, "X in feedlist -> OP_NIL"); lemon.is(k.get_operation("", "feedlist"), OP_NIL, "no key in feedlist -> OP_NIL"); k.unset_key("ENTER", "all"); lemon.is(k.get_operation("ENTER", "all"), OP_NIL, "ENTER in all -> OP_NIL after unset_key"); k.set_key(OP_OPEN, "ENTER", "all"); lemon.is(k.get_operation("ENTER", "all"), OP_OPEN, "ENTER in all -> OP_OPEN after set_key"); lemon.is(k.get_opcode("open"), OP_OPEN, "open -> OP_OPEN"); lemon.is(k.get_opcode("some-noexistent-operation"), OP_NIL, "some-noexistent-operation -> OP_NIL"); lemon.is(k.getkey(OP_OPEN, "all"), "ENTER", "OP_OPEN in all -> ENTER"); lemon.is(k.getkey(OP_TOGGLEITEMREAD, "all"), "N", "OP_TOGGLEITEMREAD in all -> N"); lemon.is(k.getkey(static_cast(30000), "all"), "", "operation 30000 in all -> "); lemon.is(k.get_key(" "), ' ', "space -> space (character)"); lemon.is(k.get_key("U"), 'U', "U -> U (character)"); lemon.is(k.get_key("~"), '~', "~ -> ~ (character)"); lemon.is(k.get_key("INVALID"), 0, "INVALID -> 0"); lemon.is(k.get_key("ENTER"), '\n', "ENTER -> \\n"); lemon.is(k.get_key("ESC"), '\033', "ESC -> \\033"); lemon.is(k.get_key("^A"), '\001', "^A -> \\001"); std::vector params; try { k.handle_action("bind-key", params); lemon.fail("bind-key with no parameters threw no exception"); } catch (const confighandlerexception& e) { lemon.ok(std::string(e.what()).length() > 0, "bind-key with no parameters"); } try { k.handle_action("unbind-key", params); lemon.fail("unbind-key with no parameters threw no exception"); } catch (const confighandlerexception& e) { lemon.ok(std::string(e.what()).length() > 0, "unbind-key with no parameters"); } try { k.handle_action("macro", params); lemon.fail("macro with no parameters threw no exception"); } catch (const confighandlerexception& e) { lemon.ok(std::string(e.what()).length() > 0, "macro with no parameters"); } params.push_back("r"); try { k.handle_action("bind-key", params); lemon.fail("bind-key with only one parameter threw no exception"); } catch (const confighandlerexception& e) { lemon.ok(std::string(e.what()).length() > 0, "bind-key with one parameter"); } try { k.handle_action("unbind-key", params); lemon.pass("unbind-key with one parameter threw no exception"); } catch (const confighandlerexception& e) { lemon.fail("unbind-key with one parameter threw exception"); } params.push_back("open"); try { k.handle_action("bind-key", params); lemon.pass("bind-key with two parameters threw no exception"); } catch (const confighandlerexception& e) { lemon.fail("bind-key with two parameters threw exception"); } try { k.handle_action("an-invalid-action", params); lemon.fail("an-invalid-action threw no exception"); } catch (const confighandlerexception& e) { lemon.pass("an-invalid-action threw exception"); } } void TestTagSoupPullParser() { std::istringstream is("textmore text"!@"); tagsouppullparser xpp; tagsouppullparser::event e; xpp.setInput(is); e = xpp.getEventType(); lemon.is(e, tagsouppullparser::START_DOCUMENT, "document start"); e = xpp.next(); lemon.is(e, tagsouppullparser::START_TAG, "type is start tag"); lemon.is(xpp.getText(), "test", "tag is test"); e = xpp.next(); lemon.is(e, tagsouppullparser::START_TAG, "type is start tag"); lemon.is(xpp.getText(), "foo", "tag is foo"); lemon.is(xpp.getAttributeValue("quux"), "asdf", "attribute quux is asdf"); lemon.is(xpp.getAttributeValue("bar"), "qqq", "attribute bar is qqq"); e = xpp.next(); lemon.is(e, tagsouppullparser::TEXT, "type is text"); lemon.is(xpp.getText(), "text", "text is text"); e = xpp.next(); lemon.is(e, tagsouppullparser::END_TAG, "type is end tag"); lemon.is(xpp.getText(), "foo", "tag is foo"); e = xpp.next(); lemon.is(e, tagsouppullparser::TEXT, "type is text"); lemon.is(xpp.getText(), "more text", "text is more text"); e = xpp.next(); lemon.is(e, tagsouppullparser::START_TAG, "type is start tag"); lemon.is(xpp.getText(), "more", "tag is more"); e = xpp.next(); lemon.is(e, tagsouppullparser::TEXT, "type is text"); lemon.is(xpp.getText(), "\"!@", "text is \"!@"); e = xpp.next(); lemon.is(e, tagsouppullparser::END_TAG, "type is end tag"); lemon.is(xpp.getText(), "more", "tag is more"); e = xpp.next(); lemon.is(e, tagsouppullparser::START_TAG, "type is start tag"); lemon.is(xpp.getText(), "xxx", "tag is xxx"); lemon.is(xpp.getAttributeValue("foo"), "bar", "attribute foo is bar"); lemon.is(xpp.getAttributeValue("baz"), "qu ux", "attribute baz is qu ux"); lemon.is(xpp.getAttributeValue("hi"), "ho ho ho", "attribute hi is ho ho ho"); e = xpp.next(); lemon.is(e, tagsouppullparser::END_TAG, "type is end tag"); lemon.is(xpp.getText(), "xxx", "tag is xxx"); e = xpp.next(); lemon.is(e, tagsouppullparser::END_TAG, "type is end tag"); lemon.is(xpp.getText(), "test", "tag is test"); e = xpp.next(); lemon.is(e, tagsouppullparser::END_DOCUMENT, "type is end document"); e = xpp.next(); lemon.is(e, tagsouppullparser::END_DOCUMENT, "type is end document (2nd try)"); } void TestUrlReader() { file_urlreader u; u.load_config("test-urls.txt"); lemon.is(u.get_urls().size(), 3u, "test-urls.txt contains 3 URL"); lemon.is(u.get_urls()[0], "http://test1.url.cc/feed.xml", "test-urls.txt URL 1"); lemon.is(u.get_urls()[1], "http://anotherfeed.com/", "test-urls.txt URL 2"); lemon.is(u.get_urls()[2], "http://onemorefeed.at/feed/", "test-urls.txt URL 3"); lemon.is(u.get_tags("http://test1.url.cc/feed.xml").size(), 2u, "feed 1 has 2 tags"); lemon.is(u.get_tags("http://test1.url.cc/feed.xml")[0], "tag1", "feed 1 tag 1 is tag1"); lemon.is(u.get_tags("http://test1.url.cc/feed.xml")[1], "tag2", "feed 1 tag 2 is tag2"); lemon.is(u.get_tags("http://anotherfeed.com/").size(), 0u, "feed 2 has no tags"); lemon.is(u.get_tags("http://onemorefeed.at/feed/").size(), 2u, "feed 3 has two tags"); lemon.is(u.get_alltags().size(), 3u, "3 tags in total"); } void TestTokenizers() { std::vector tokens; tokens = utils::tokenize("as df qqq"); lemon.is(tokens.size(), 3u, "tokenize results in 3 tokens"); lemon.ok(tokens[0] == "as" && tokens[1] == "df" && tokens[2] == "qqq", "tokenize of as df qqq"); tokens = utils::tokenize(" aa "); lemon.is(tokens.size(), 1u, "tokenize of ' aa ' resulted in one token"); lemon.is(tokens[0], "aa", "first token is aa"); tokens = utils::tokenize(" "); lemon.is(tokens.size(), 0u, "tokenize of tab resulted in 0 tokens"); tokens = utils::tokenize(""); lemon.is(tokens.size(), 0u, "tokenize of empty string resulted in 0 tokens"); tokens = utils::tokenize_spaced("a b"); lemon.is(tokens.size(), 3u, "tokenize_spaced of a b resulted in 3 tokens"); lemon.is(tokens[1], " ", "middle token is space"); tokens = utils::tokenize_spaced(" a\t b "); lemon.is(tokens.size(), 5u, "tokenize_spaced resulted in 5 tokens"); lemon.is(tokens[0], " ", "first token is space"); lemon.is(tokens[1], "a", "second token is a"); lemon.is(tokens[2], " ", "third token is space"); tokens = utils::tokenize_quoted("asdf \"foobar bla\" \"foo\\r\\n\\tbar\""); lemon.is(tokens.size(), 3u, "tokenize_quoted resulted in 3 tokens"); lemon.is(tokens[0], "asdf", "first token is asdf"); lemon.is(tokens[1], "foobar bla", "second token is foobar bla"); lemon.is(tokens[2], "foo\r\n\tbar", "third token contains \\r\\n\\t"); tokens = utils::tokenize_quoted(" \"foo \\\\xxx\"\t\r \" \""); lemon.is(tokens.size(), 2u, "tokenize_quoted resulted in 2 tokens"); lemon.is(tokens[0], "foo \\xxx", "first token contains \\"); lemon.is(tokens[1], " ", "second token is space"); tokens = utils::tokenize_quoted("\"\\\\"); lemon.is(tokens.size(), 1u, "tokenize_quoted with unbalanced quotes resulted in 1 token"); lemon.is(tokens[0], "\\", "first token is \\"); // the following test cases specifically demonstrate a problem of the tokenize_quoted with several \\ sequences directly appended tokens = utils::tokenize_quoted("\"\\\\\\\\"); lemon.is(tokens.size(), 1u, "tokenize_quoted escape test 1 resulted in 1 token"); lemon.is(tokens[0], "\\\\", "tokenize_quoted escape test 1 token is \\\\"); tokens = utils::tokenize_quoted("\"\\\\\\\\\\\\"); lemon.is(tokens.size(), 1u, "tokenize_quoted escape test 2 resulted in 1 token"); lemon.is(tokens[0], "\\\\\\", "tokenize_quoted escape test 2 token is \\\\\\"); tokens = utils::tokenize_quoted("\"\\\\\\\\\""); lemon.is(tokens.size(), 1u, "tokenize_quoted escape test 3 resulted in 1 token"); lemon.is(tokens[0], "\\\\", "tokenize_quoted escape test 3 token is \\\\"); tokens = utils::tokenize_quoted("\"\\\\\\\\\\\\\""); lemon.is(tokens.size(), 1u, "tokenize_quoted escape test 4 resulted in 1 token"); lemon.is(tokens[0], "\\\\\\", "tokenize_quoted escape test 4 token is \\\\\\"); } struct testmatchable : public matchable { virtual bool has_attribute(const std::string& attribname) { if (attribname == "abcd" || attribname == "AAAA" || attribname == "tags") return true; return false; } virtual std::string get_attribute(const std::string& attribname) { if (attribname == "abcd") return "xyz"; if (attribname == "AAAA") return "12345"; if (attribname == "tags") return "foo bar baz quux"; return ""; } }; void TestFilterLanguage() { FilterParser fp; // test parser lemon.ok(fp.parse_string("a = \"b\""), utils::wstr2str(fp.get_error()).c_str()); lemon.ok(!fp.parse_string("a = \"b"), utils::wstr2str(fp.get_error()).c_str()); lemon.ok(!fp.parse_string("a = b"), utils::wstr2str(fp.get_error()).c_str()); lemon.ok(fp.parse_string("(a=\"b\")"), utils::wstr2str(fp.get_error()).c_str()); lemon.ok(fp.parse_string("((a=\"b\"))"), utils::wstr2str(fp.get_error()).c_str()); lemon.ok(!fp.parse_string("((a=\"b\")))"), utils::wstr2str(fp.get_error()).c_str()); // test operators lemon.ok(fp.parse_string("a != \"b\""), utils::wstr2str(fp.get_error()).c_str()); lemon.ok(fp.parse_string("a =~ \"b\""), utils::wstr2str(fp.get_error()).c_str()); lemon.ok(fp.parse_string("a !~ \"b\""), utils::wstr2str(fp.get_error()).c_str()); lemon.ok(!fp.parse_string("a !! \"b\""), utils::wstr2str(fp.get_error()).c_str()); // complex query lemon.is(fp.parse_string("( a = \"b\") and ( b = \"c\" ) or ( ( c != \"d\" ) and ( c !~ \"asdf\" )) or c != \"xx\""), true, "parse string of complex query"); testmatchable tm; matcher m; m.parse("abcd = \"xyz\""); lemon.ok(m.matches(&tm), "abcd = xyz matches"); m.parse("abcd = \"uiop\""); lemon.not_ok(m.matches(&tm), "abcd = uiop doesn't match"); m.parse("abcd != \"uiop\""); lemon.ok(m.matches(&tm), "abcd != uiop matches"); m.parse("abcd != \"xyz\""); lemon.not_ok(m.matches(&tm), "abcd != xyz doesn't match"); // testing regex matching m.parse("AAAA =~ \".\""); lemon.ok(m.matches(&tm), "AAAA =~ . matches"); m.parse("AAAA =~ \"123\""); lemon.ok(m.matches(&tm), "AAAA =~ 123 matches"); m.parse("AAAA =~ \"234\""); lemon.ok(m.matches(&tm), "AAAA =~ 234 matches"); m.parse("AAAA =~ \"45\""); lemon.ok(m.matches(&tm), "AAAA =~ 45 matches"); m.parse("AAAA =~ \"^12345$\""); lemon.ok(m.matches(&tm), "AAAA =~ ^12345$ matches"); m.parse("AAAA =~ \"^123456$\""); lemon.not_ok(m.matches(&tm), "AAAA =~ ^123456$ doesn't match"); m.parse("AAAA !~ \".\""); lemon.not_ok(m.matches(&tm), "AAAA !~ . doesn't match"); m.parse("AAAA !~ \"123\""); lemon.is(m.matches(&tm), false, "AAAA !~ 123 doesn't match"); m.parse("AAAA !~ \"234\""); lemon.is(m.matches(&tm), false, "AAAA !~ 234 doesn't match"); m.parse("AAAA !~ \"45\""); lemon.is(m.matches(&tm), false, "AAAA !~ 45 doesn't match"); m.parse("AAAA !~ \"^12345$\""); lemon.is(m.matches(&tm), false, "AAAA !~ ^12345$ doesn't match"); // testing the "contains" operator m.parse("tags # \"foo\""); lemon.is(m.matches(&tm), true, "tags # foo matches"); m.parse("tags # \"baz\""); lemon.is(m.matches(&tm), true, "tags # baz matches"); m.parse("tags # \"quux\""); lemon.is(m.matches(&tm), true, "tags # quux matches"); m.parse("tags # \"xyz\""); lemon.is(m.matches(&tm), false, "tags # xyz doesn't match"); m.parse("tags # \"foo bar\""); lemon.is(m.matches(&tm), false, "tags # foo bar doesn't match"); m.parse("tags # \"foo\" and tags # \"bar\""); lemon.is(m.matches(&tm), true, "tags # foo and tags # bar matches"); m.parse("tags # \"foo\" and tags # \"xyz\""); lemon.is(m.matches(&tm), false, "tags # foo and tags # xyz doesn't match"); m.parse("tags # \"foo\" or tags # \"xyz\""); lemon.is(m.matches(&tm), true, "tags # foo or tags # xyz matches"); m.parse("tags !# \"nein\""); lemon.is(m.matches(&tm), true, "tags !# nein matches"); m.parse("tags !# \"foo\""); lemon.is(m.matches(&tm), false, "tags !# foo doesn't match"); m.parse("AAAA > 12344"); lemon.is(m.matches(&tm), true, "AAAA > 12344 matches"); m.parse("AAAA > 12345"); lemon.is(m.matches(&tm), false, "AAAA > 12345 doesn't match"); m.parse("AAAA >= 12345"); lemon.is(m.matches(&tm), true, "AAAA >= 12345 matches"); m.parse("AAAA < 12345"); lemon.is(m.matches(&tm), false, "AAAA < 12345 doesn't match"); m.parse("AAAA <= 12345"); lemon.is(m.matches(&tm), true, "AAAA <= 12345 matches"); m.parse("AAAA between 0:12345"); lemon.is(m.matches(&tm), true, "AAAA between 0:12345 matches"); m.parse("AAAA between 12345:12345"); lemon.is(m.matches(&tm), true, "AAAA between 12345:12345 matches"); m.parse("AAAA between 23:12344"); lemon.is(m.matches(&tm), false, "AAAA between 23:12344 doesn't match"); m.parse("AAAA between 0"); lemon.is(m.matches(&tm), false, "invalid between expression (1)"); lemon.is(m.parse("AAAA between 0:15:30"), false, "invalid between expression won't be parsed"); lemon.ok(m.get_parse_error() != "", "invalid between expression leads to parse error"); m.parse("AAAA between 1:23"); lemon.ok(m.get_parse_error() == "", "valid between expression returns no parse error"); m.parse("AAAA between 12346:12344"); lemon.is(m.matches(&tm), true, "reverse ranges will match, too"); try { m.parse("BBBB < 0"); m.matches(&tm); lemon.fail("attribute BBBB shouldn't have been found"); } catch (const matcherexception& e) { lemon.ok(true, "attribute BBBB was detected as non-existent"); } try { m.parse("BBBB > 0"); m.matches(&tm); lemon.fail("attribute BBBB shouldn't have been found"); } catch (const matcherexception& e) { lemon.ok(true, "attribute BBBB was detected as non-existent"); } try { m.parse("BBBB =~ \"foo\""); m.matches(&tm); lemon.fail("attribute BBBB shouldn't have been found"); } catch (const matcherexception& e) { lemon.ok(true, "attribute BBBB was detected as non-existent"); } try { m.parse("BBBB between 1:23"); m.matches(&tm); lemon.fail("attribute BBBB shouldn't have been found"); } catch (const matcherexception& e) { lemon.ok(true, "attribute BBBB was detected as non-existent"); } try { m.parse("AAAA =~ \"[[\""); m.matches(&tm); lemon.fail("invalid regex should have been found"); } catch (const matcherexception& e) { lemon.ok(true, "invalid regex was found"); } try { m.parse("BBBB # \"foo\""); m.matches(&tm); lemon.fail("attribute BBBB shouldn't have been found"); } catch (const matcherexception& e) { lemon.ok(true, "attribute BBBB was detected as non-existent"); } matcher m2("AAAA between 1:30000"); lemon.is(m2.get_expression(), "AAAA between 1:30000", "get_expression returns previously parsed expression"); } void TestHistory() { history h; lemon.is(h.prev(), "", "previous is empty"); lemon.is(h.prev(), "", "previous is empty"); lemon.is(h.next(), "", "previous is empty"); lemon.is(h.next(), "", "previous is empty"); h.add_line("testline"); lemon.is(h.prev(), "testline", "previous is testline"); lemon.is(h.prev(), "testline", "previous is testline"); lemon.is(h.next(), "testline", "previous is testline"); lemon.is(h.next(), "", "next is empty"); h.add_line("foobar"); lemon.is(h.prev(), "foobar","previous is foobar"); lemon.is(h.prev(), "testline", "previous is testline"); lemon.is(h.next(), "testline", "previous is testline"); lemon.is(h.prev(), "testline", "previous is testline"); lemon.is(h.next(), "testline", "previous is testline"); lemon.is(h.next(), "foobar", "next is foobar"); lemon.is(h.next(), "", "next is empty"); lemon.is(h.next(), "", "next is empty"); } void TestStringConversion() { std::string s1 = utils::wstr2str(L"This is a simple string. Let's have a look at the outcome..."); lemon.is(s1, "This is a simple string. Let's have a look at the outcome...", "conversion from wstring to string"); std::wstring w1 = utils::str2wstr("And that's another simple string."); lemon.is(w1 == L"And that's another simple string.", true, "conversion from string to wstring"); std::wstring w2 = utils::str2wstr(""); lemon.is(w2 == L"", true, "conversion from empty string to wstring"); std::string s2 = utils::wstr2str(L""); lemon.is(s2, "", "conversion from empty wstring to string"); } void TestFmtStrFormatter() { fmtstr_formatter fmt; fmt.register_fmt('a', "AAA"); fmt.register_fmt('b', "BBB"); fmt.register_fmt('c', "CCC"); lemon.is(fmt.do_format(""), "", "empty format string"); lemon.is(fmt.do_format("%"), "", "format string with illegal single %"); lemon.is(fmt.do_format("%%"), "%", "format string with %%"); lemon.is(fmt.do_format("%a%b%c"), "AAABBBCCC", "format string substitution of %a%b%c"); lemon.is(fmt.do_format("%%%a%%%b%%%c%%"), "%AAA%BBB%CCC%", "format string substitution of %a, %b, %c intermixed with %%"); lemon.is(fmt.do_format("%4a")," AAA", "format string align right"); lemon.is(fmt.do_format("%-4a"), "AAA ", "format string align left"); lemon.is(fmt.do_format("%2a"), "AA", "format string limit size (align right)"); lemon.is(fmt.do_format("%-2a"), "AA", "format string limit size (align left"); lemon.is(fmt.do_format("<%a> <%5b> | %-5c%%"), " < BBB> | CCC %", "complex format string"); fmtstr_formatter fmt2; fmt2.register_fmt('a',"AAA"); lemon.is(fmt2.do_format("%?a?%a&no?"), "AAA", "conditional format string (1)"); lemon.is(fmt2.do_format("%?b?%b&no?"), "no", "conditional format string (2)"); lemon.is(fmt2.do_format("%?a?[%-4a]&no?"), "[AAA ]", "complex format string with conditional"); fmt2.register_fmt('b',"BBB"); lemon.is(fmt2.do_format("asdf | %a | %?c?%a%b&%b%a? | qwert"), "asdf | AAA | BBBAAA | qwert", "complex format string (2)"); lemon.is(fmt2.do_format("%?c?asdf?"), "", "conditional format string (3)"); fmt2.register_fmt('c',"CCC"); lemon.is(fmt2.do_format("asdf | %a | %?c?%a%b&%b%a? | qwert"), "asdf | AAA | AAABBB | qwert", "complex format string (3)"); lemon.is(fmt2.do_format("%?c?asdf?"), "asdf", "conditional format string (4)"); lemon.is(fmt.do_format("%>X", 3), "XXX", "format string filler"); lemon.is(fmt.do_format("%a%> %b", 10), "AAA BBB", "format string filler (2)"); lemon.is(fmt.do_format("%a%> %b", 0), "AAA BBB", "format string filler (3) with with 0"); } void TestMiscUtilsFunctions() { /* this test assumes some command line utilities to be installed */ lemon.is(utils::get_command_output("ls /dev/null"), "/dev/null\n", "ls /dev/null"); char * argv[4]; argv[0] = "cat"; argv[1] = NULL; lemon.is(utils::run_program(argv, "this is a multine-line\ntest string"), "this is a multine-line\ntest string", "run_program(cat)"); argv[0] = "echo"; argv[1] = "-n"; argv[2] = "hello world"; argv[3] = NULL; lemon.is(utils::run_program(argv, ""), "hello world", "echo -n 'hello world'"); lemon.is(utils::replace_all("aaa", "a", "b"), "bbb", "replace all a by b"); lemon.is(utils::replace_all("aaa", "aa", "ba"), "baa", "replace all aa by ba"); lemon.is(utils::replace_all("aaaaaa", "aa", "ba"), "bababa", "replace all aa by ba (2)"); lemon.is(utils::replace_all("", "a", "b"), "", "replace a by b on empty string"); lemon.is(utils::replace_all("aaaa", "b", "c"), "aaaa", "replace b by c in string only consisting of a"); lemon.is(utils::replace_all("this is a normal test text", " t", " T"), "this is a normal Test Text", "replace t by T"); lemon.is(utils::replace_all("o o o", "o", ""), " ", "replace o by "); lemon.is(utils::to_string(0), "0", "convert 0 to string"); lemon.is(utils::to_string(100), "100", "convert 100 to string"); lemon.is(utils::to_string(65536), "65536", "convert 65536 to string"); lemon.is(utils::to_string(65537), "65537", "convert 65537 to string"); } void TestUtilsStrPrintf() { lemon.is(utils::strprintf(NULL), "", "strprintf with NULL format string"); lemon.is(utils::strprintf("%s", ""), "", "strprintf(%s) with empty string"); lemon.is(utils::strprintf("%u", 0), "0", "strprintf(%u) with 0"); lemon.is(utils::strprintf("%s", NULL), "(null)", "strprintf(%s) with NULL"); lemon.is(utils::strprintf("%u-%s-%c", 23, "hello world", 'X'), "23-hello world-X", "strprintf(%u-%s-%c)"); } void TestRegexManager() { regexmanager rxman; std::vector params; try { rxman.handle_action("highlight", params); lemon.fail("highlight with no parameters threw no exception"); } catch (const confighandlerexception& e) { lemon.pass("highlight with no parameters threw an exception"); } params.push_back("articlelist"); params.push_back("foo"); params.push_back("blue"); params.push_back("red"); try { rxman.handle_action("highlight", params); lemon.pass("highlight with correct parameters threw no exception"); } catch (const confighandlerexception& e) { lemon.fail("highlight with correct parameters threw an exception"); } std::string str = "xfoox"; rxman.quote_and_highlight(str, "articlelist"); lemon.is(str, "x<0>foox", "highlight of foo in articlelist"); str = "xfoox"; rxman.quote_and_highlight(str, "feedlist"); lemon.is(str, "xfoox", "highlight of foo in feedlist"); params[0] = "feedlist"; try { rxman.handle_action("highlight", params); lemon.pass("highlight with correct parameters threw no exception"); } catch (const confighandlerexception& e) { lemon.fail("highlight with correct parameters threw an exception"); } str = "yfooy"; rxman.quote_and_highlight(str, "feedlist"); lemon.is(str, "y<0>fooy", "highlight of foo in feedlist"); params[0] = "invalidloc"; try { rxman.handle_action("highlight", params); lemon.fail("highlight with invalid location threw no exception"); } catch (const confighandlerexception& e) { lemon.pass("highlight with invalid location threw an exception"); } params[0] = "feedlist"; params[1] = "*"; try { rxman.handle_action("highlight", params); lemon.fail("highlight with invalid expression threw no exception"); } catch (const confighandlerexception& e) { lemon.pass("highlight with invalid expression threw an exception"); } params[1] = "foo"; params.push_back("bold"); params.push_back("underline"); try { rxman.handle_action("highlight", params); lemon.pass("highlight with correct parameters threw no exception"); } catch (const confighandlerexception& e) { lemon.fail("highlight with correct parameters threw an exception"); } params[0] = "all"; try { rxman.handle_action("highlight", params); lemon.pass("highlight with correct parameters threw no exception"); } catch (const confighandlerexception& e) { lemon.fail("highlight with correct parameters threw an exception"); } try { rxman.handle_action("an-invalid-command", params); lemon.fail("an-invalid-command threw no exception"); } catch (const confighandlerexception& e) { lemon.pass("an-invalid-command threw an exception"); } str = "<"; rxman.quote_and_highlight(str, "feedlist"); lemon.is(str, "<", "quote_and_highlight <"); str = "a"; rxman.quote_and_highlight(str, "feedlist"); lemon.is(str, "a", "quote_and_highlight a"); } void TestHtmlRenderer() { htmlrenderer rnd(100); std::vector lines; std::vector links; rnd.render("slashdot", lines, links, ""); lemon.ok(lines.size() >= 1u, "rendering produced one line"); lemon.is(lines[0], "slashdot[1]", "first line contains underlined link"); lemon.is(links[0].first, "http://slashdot.org/", "first link"); lemon.is(links[0].second, LINK_HREF, "first link type"); lines.erase(lines.begin(), lines.end()); links.erase(links.begin(), links.end()); rnd.render("hello
    world!", lines, links, ""); lemon.is(lines.size(), 2u, "text with
    produces two lines"); lemon.is(lines[0], "hello", "first line hello"); lemon.is(lines[1], "world!", "second line is world!"); lines.erase(lines.begin(), lines.end()); links.erase(links.begin(), links.end()); rnd.render("310", lines, links, ""); lemon.is(lines.size(), 1u, "superscription produced 1 line"); lemon.is(lines[0], "3^10", "superscription of 3^10"); lines.erase(lines.begin(), lines.end()); links.erase(links.begin(), links.end()); rnd.render("Ai", lines, links, ""); lemon.is(lines.size(), 1u, "subscription produced 1 line"); lemon.is(lines[0], "A[i]", "subscription of A[i]"); lines.erase(lines.begin(), lines.end()); links.erase(links.begin(), links.end()); rnd.render("abc", lines, links, ""); lemon.is(lines.size(), 1u, "rendering produced one line"); lemon.is(lines.at(0),"abc", "rendering of abc produced one empty line"); } void TestIndexPartitioning() { std::vector > partitions = utils::partition_indexes(0, 9, 2); lemon.is(partitions.size(), 2u, "partitioning of [0,9] in 2 parts produced 2 parts"); lemon.is(partitions[0].first, 0u, "first partition start is 0"); lemon.is(partitions[0].second, 4u, "first partition end is 4"); lemon.is(partitions[1].first, 5u, "second partition start is 5"); lemon.is(partitions[1].second, 9u, "second partition end is 9"); partitions = utils::partition_indexes(0, 10, 3); lemon.is(partitions.size(), 3u, "partitioning of [0,10] in 3 parts produced 3 parts"); lemon.is(partitions[0].first, 0u, "first partition start is 0"); lemon.is(partitions[0].second, 2u, "first partition end is 2"); lemon.is(partitions[1].first, 3u, "second partition start is 3"); lemon.is(partitions[1].second, 5u, "second partition end is 5"); lemon.is(partitions[2].first, 6u, "third partition start is 6"); lemon.is(partitions[2].second, 10u, "third partition end is 10"); partitions = utils::partition_indexes(0, 11, 3); lemon.is(partitions.size(), 3u, "partitioning of [0,11] in 3 parts produced 3 parts"); lemon.is(partitions[0].first, 0u, "first partition start is 0"); lemon.is(partitions[0].second, 3u, "first partition end is 3"); lemon.is(partitions[1].first, 4u, "second partition start is 4"); lemon.is(partitions[1].second, 7u, "second partition end is 7"); lemon.is(partitions[2].first, 8u, "third partition start is 8"); lemon.is(partitions[2].second, 11u, "third partition end is 11"); partitions = utils::partition_indexes(0, 199, 200); lemon.is(partitions.size(), 200u, "partitioning of [0,199] in 200 parts produced 200 parts"); partitions = utils::partition_indexes(0, 103, 1); lemon.is(partitions.size(), 1u, "partitioning of [0,103] in 1 partition produced 1 partition"); lemon.is(partitions[0].first, 0u, "first partition start is 0"); lemon.is(partitions[0].second, 103u, "first partition end is 103"); } void TestCensorUrl() { lemon.is(utils::censor_url(""), "", "censor empty string"); lemon.is(utils::censor_url("foobar"), "foobar", "censor foobar"); lemon.is(utils::censor_url("foobar://xyz/"), "foobar://xyz/", "censor foobar: url with no authinfo"); lemon.is(utils::censor_url("http://newsbeuter.org/"), "http://newsbeuter.org/", "censor http url with no authinfo"); lemon.is(utils::censor_url("https://newsbeuter.org/"), "https://newsbeuter.org/", "censor https url with no authinfo"); lemon.is(utils::censor_url("http://@newsbeuter.org/"), "http://*:*@newsbeuter.org/", "censor http url with empty authinfo"); lemon.is(utils::censor_url("https://@newsbeuter.org/"), "https://*:*@newsbeuter.org/", "censor https url with empty authinfo"); lemon.is(utils::censor_url("http://foo:bar@newsbeuter.org/"), "http://*:*@newsbeuter.org/", "censor http url with authinfo"); lemon.is(utils::censor_url("https://foo:bar@newsbeuter.org/"), "https://*:*@newsbeuter.org/", "censor https url with authinfo"); lemon.is(utils::censor_url("http://aschas@newsbeuter.org/"), "http://*:*@newsbeuter.org/", "censor http url with username-only authinfo"); lemon.is(utils::censor_url("https://aschas@newsbeuter.org/"), "https://*:*@newsbeuter.org/", "censor https url with username-only authinfo"); lemon.is(utils::censor_url("xxx://aschas@newsbeuter.org/"), "xxx://*:*@newsbeuter.org/", "censor xxx url with username-only authinfo"); lemon.is(utils::censor_url("http://foobar"), "http://foobar", "censor http url with no authinfo and no trailing slash"); lemon.is(utils::censor_url("https://foobar"), "https://foobar", "censor https url with no authinfo and no trailing slash"); lemon.is(utils::censor_url("http://aschas@host"), "http://*:*@host", "censor http url with username-only authinfo and no trailing slash"); lemon.is(utils::censor_url("https://aschas@host"), "https://*:*@host", "censor http url with username-only authinfo and no trailing slash"); lemon.is(utils::censor_url("query:name:age between 1:10"), "query:name:age between 1:10", "censor query feed"); } void TestMakeAbsoluteUrl() { lemon.is(utils::absolute_url("http://foobar/hello/crook/", "bar.html"), "http://foobar/hello/crook/bar.html", "relative url"); lemon.is(utils::absolute_url("https://foobar/foo/", "/bar.html"), "https://foobar/bar.html", "path-absolute url"); lemon.is(utils::absolute_url("https://foobar/foo/", "http://quux/bar.html"), "http://quux/bar.html", "absolute url"); lemon.is(utils::absolute_url("http://foobar", "bla.html"), "http://foobar/bla.html", "relative url with absolute url with no trailing slash"); lemon.is(utils::absolute_url("http://test:test@foobar:33", "bla2.html"), "http://test:test@foobar:33/bla2.html", "relative url with absolute url with authinfo and port"); } void TestBacktickEvaluation() { lemon.is(configparser::evaluate_backticks(""), "", "backtick evaluation of empty string"); lemon.is(configparser::evaluate_backticks("hello world"), "hello world", "backtick evaluation of string with no backticks"); lemon.is(configparser::evaluate_backticks("foo`true`baz"), "foobaz", "backtick evaluation with true (empty string)"); lemon.is(configparser::evaluate_backticks("foo`barbaz"), "foo`barbaz", "backtick evaluation with missing second backtick"); lemon.is(configparser::evaluate_backticks("foo `true` baz"), "foo baz", "backtick evaluation with true (2)"); lemon.is(configparser::evaluate_backticks("foo `true` baz `xxx"), "foo baz `xxx", "backtick evaluation with missing third backtick"); lemon.is(configparser::evaluate_backticks("`echo hello world`"), "hello world", "backtick evaluation of an echo command"); lemon.is(configparser::evaluate_backticks("xxx`echo yyy`zzz"), "xxxyyyzzz", "backtick evaluation of an echo command embedded in regular text"); lemon.is(configparser::evaluate_backticks("`echo 3 \\* 4 | bc`"), "12", "backtick evaluation of an expression piped into bc"); } void TestUtilsQuote() { lemon.is(utils::quote(""), "\"\"", "quote empty string"); lemon.is(utils::quote("hello world"), "\"hello world\"", "quote regular string"); lemon.is(utils::quote("\"hello world\""), "\"\\\"hello world\\\"\"", "quote string that contains quotes"); } void TestUtilsFunctions_to_u() { lemon.is(utils::to_u("0"), 0u, "conversion to unsigned 0 -> 0"); lemon.is(utils::to_u("23"), 23u, "convertion to unsigned 23 -> 23"); lemon.is(utils::to_u(""), 0u, "conversion to unsigned empty string -> 0"); } void TestUtilsFunctions_strwidth() { lemon.is(utils::strwidth(""), 0u, "empty string is 0 colums wide"); lemon.is(utils::strwidth("xx"), 2u, "xx is 2 columns wide"); lemon.is(utils::strwidth(utils::wstr2str(L"\uF91F")), 2u, "character U+F91F is 2 columns wide"); } void TestUtilsFunction_join() { std::vector str; lemon.is(utils::join(str, ""), "", "join of no elements with empty string"); lemon.is(utils::join(str, "-"), "", "join of no elements with -"); str.push_back("foobar"); lemon.is(utils::join(str, ""), "foobar", "join of single element with empty string"); lemon.is(utils::join(str, "-"), "foobar", "join of single element with -"); str.push_back("quux"); lemon.is(utils::join(str, ""), "foobarquux", "join of two elements two empty string"); lemon.is(utils::join(str, "-"), "foobar-quux", "join of two elements with -"); } void TestUtilsFunction_trim() { std::string str = " xxx\r\n"; utils::trim(str); lemon.is(str, "xxx", "trim string starting with spaces and ending with CRLF"); str = "\n\n abc foobar\n"; utils::trim(str); lemon.is(str, "abc foobar", "trim string starting with newlines and space and ending with newline"); str = ""; utils::trim(str); lemon.is(str, "", "trim empty string"); str = " \n"; utils::trim(str); lemon.is(str, "", "trim string only consisting of spaces and newline"); str = "quux\n"; utils::trim_end(str); lemon.is(str, "quux", "trim end of string that ends with newline"); } void TestOlFormatting() { htmlrenderer r; lemon.is(r.format_ol_count(1, '1'), " 1", "1 in digit formats to \"1\""); lemon.is(r.format_ol_count(3, '1'), " 3", "3 in digit formats to \"3\""); lemon.is(r.format_ol_count(3, 'a'), "c", "3 in alphabetic formats to \"c\""); lemon.is(r.format_ol_count(26 + 3, 'a'), "ac", "26+3 in alphabetic formats to \"ac\""); lemon.is(r.format_ol_count(3*26*26 + 5*26 + 2, 'a'), "ceb", "3*26*26 + 5*26 + 2 in alphabetic formats to \"ceb\""); lemon.is(r.format_ol_count(3, 'A'), "C", "3 in alphabetic uppercase formats to \"C\""); lemon.is(r.format_ol_count(26 + 5, 'A'), "AE", "26+5 in alphabetic uppercase formats to \"AE\""); lemon.is(r.format_ol_count(27, 'A'), "AA", "27 in alphabetic uppercase formats to \"AA\""); lemon.is(r.format_ol_count(26, 'A'), "Z", "26 in alphabetic uppercase formats to \"Z\""); lemon.is(r.format_ol_count(26*26+26, 'A'), "ZZ", "26*26+26 in alphabetic uppercase formats to \"ZZ\""); lemon.is(r.format_ol_count(25*26*26 + 26*26+26, 'A'), "YZZ", "26*26*26+26*26+26 in alphabetic uppercase formats to \"YZZ\""); lemon.is(r.format_ol_count(1, 'i'), "i", "1 in roman numerals is i"); lemon.is(r.format_ol_count(2, 'i'), "ii", "2 in roman numerals is ii"); lemon.is(r.format_ol_count(5, 'i'), "v", "5 in roman numerals is v"); lemon.is(r.format_ol_count(4, 'i'), "iv", "4 in roman numerals is iv"); lemon.is(r.format_ol_count(6, 'i'), "vi", "6 in roman numerals is vi"); lemon.is(r.format_ol_count(7, 'i'), "vii", "6 in roman numerals is vii"); lemon.is(r.format_ol_count(10, 'i'), "x", "10 in roman numerals is x"); lemon.is(r.format_ol_count(32, 'i'), "xxxii", "32 in roman numerals is xxxii"); lemon.is(r.format_ol_count(1972, 'i'), "mcmlxxii", "1972 in roman numerals is mcmlxxii"); lemon.is(r.format_ol_count(2011, 'I'), "MMXI", "201 in roman numerals uppercase is MMXI"); } } // namespace test int main(void) { setlocale(LC_CTYPE, ""); logger::getInstance().set_logfile("testlog.txt"); logger::getInstance().set_loglevel(LOG_DEBUG); test::TestNewsbeuterReload(); test::TestConfigParserContainerAndKeymap(); test::TestTagSoupPullParser(); test::TestUrlReader(); test::TestTokenizers(); test::TestFilterLanguage(); test::TestHistory(); test::TestStringConversion(); test::TestFmtStrFormatter(); test::TestMiscUtilsFunctions(); test::TestUtilsStrPrintf(); test::TestRegexManager(); test::TestHtmlRenderer(); test::TestIndexPartitioning(); test::TestCensorUrl(); test::TestMakeAbsoluteUrl(); test::TestBacktickEvaluation(); test::TestUtilsQuote(); test::TestUtilsFunctions_to_u(); test::TestUtilsFunctions_strwidth(); test::TestUtilsFunction_join(); test::TestUtilsFunction_trim(); test::TestOlFormatting(); return test::lemon.done() ? 0 : 1; } newsbeuter-2.7/test/testbed/000077500000000000000000000000001220711462700161605ustar00rootroot00000000000000newsbeuter-2.7/test/testbed/atom10.xml000066400000000000000000000025761220711462700200150ustar00rootroot00000000000000 http://testbed.newsbeuter.org/ <div xmlns='http://www.w3.org/1999/xhtml'>newsbeuter testbed</div> this is the subtitle. 2008-08-27T16:20:46-04:00 Andreas Krennmair http://www.newsbeuter.org/ ak@newsbeuter.org http://testbed.newsbeuter.org/atom-item1.html Atom Entry 1
    this is HTML content.
    yes, really.
    2008-08-27T16:20:46-04:00
    http://testbed.newsbeuter.org/atom-item2.html <div xmlns='http://www.w3.org/1999/xhtml'><strong>Atom Entry 2</strong></div>
    Not really the intention of the Atom designers, but seen quite often. ]]>
    2008-08-26T16:20:46-04:00
    newsbeuter-2.7/test/testbed/enclosure.xml000066400000000000000000000004671220711462700207100ustar00rootroot00000000000000 Podcast Test Podcast Foo http://localhost/ Test Description newsbeuter-2.7/test/testbed/hierarchy.opml000066400000000000000000000132531220711462700210330ustar00rootroot00000000000000 Generated by SharpReader - http://www.sharpreader.net newsbeuter-2.7/test/testbed/pre.xml000066400000000000000000000016561220711462700175000ustar00rootroot00000000000000 pre html rendering testbed feed http://testbed.newsbeuter.org/ testbed RSS feed for newsbeuter pre html Item 1 http://testbed.newsbeuter.org/preitem1.html ak@newsbeuter.org (Andreas Krennmair) <blockquote><pre>foo bar baz quux foobar</pre></blockquote> Sat, 30 Aug 2008 09:40:10 +0200 newsbeuter-testbed-rss20:item1 newsbeuter-2.7/test/testbed/rss20-html.xml000066400000000000000000000047531220711462700206260ustar00rootroot00000000000000 HTML rendering testbed feed http://testbed.newsbeuter.org/ HTML-rendering-related testbed RSS feed for newsbeuter HTML Item 1 http://testbed.newsbeuter.org/htmlitem1.html ak@newsbeuter.org (Andreas Krennmair) normal link
    invalid link without href.
    hello world
    hello world
    hello world


    To be or not to be, that is the question.
    ]]>
    Sat, 30 Aug 2008 09:40:10 +0200 newsbeuter-testbed-html:item1
    HTML Item 2 http://testbed.newsbeuter.org/htmlitem2.html ak@newsbeuter.org (Andreas Krennmair) Lorem ipsum dolor sit amet, consectetuer sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.

    At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, ...

    ]]>
    Fri, 29 Aug 2008 09:40:10 +0200 newsbeuter-testbed-html:item2
    HTML Item 3 http://testbed.newsbeuter.org/htmlitem4.html ak@newsbeuter.org (Andreas Krennmair)
  1. one
  2. two
  3. three

    • hello
    • world

    a0 = 23
    a1 = 42
    E = mc2

    ]]>
    Thu, 28 Aug 2008 09:40:10 +0200 newsbeuter-testbed-html:item3
    newsbeuter-2.7/test/testbed/rss20.xml000066400000000000000000000036521220711462700176610ustar00rootroot00000000000000 RSS 2.0 testbed feed http://testbed.newsbeuter.org/ testbed RSS feed for newsbeuter RSS 2.0 Item 1 http://testbed.newsbeuter.org/item1.html ak@newsbeuter.org (Andreas Krennmair) This is some example content.

    Here's a line break.
    Second line. And now we try an unordered list.

    • first entry
    • second entry
    • third entry
    ]]>
    Sat, 30 Aug 2008 09:40:10 +0200 newsbeuter-testbed-rss20:item1
    RSS 2.0 Item 2 http://testbed.newsbeuter.org/item2.html ak@newsbeuter.org (Andreas Krennmair) This is second item, this time only with a &lt;description&gt; tag. Fri, 29 Aug 2008 08:41:30 +0200 newsbeuter-testbed-rss20:item2 RSS 2.0 Item 3 http://testbed.newsbeuter.org/item3.html ak@newsbeuter.org (Andreas Krennmair) And finally a third item, also description, but with some HTML...<br /> Yes, there was a line break. And here is a <a href="http://slashdot.org/">link to slashdot</a>. Thu, 28 Aug 2008 18:27:50 +0200 newsbeuter-testbed-rss20:item3
    newsbeuter-2.7/test/testbed/tables.xml000066400000000000000000000021051220711462700201520ustar00rootroot00000000000000 html table rendering testbed feed http://testbed.newsbeuter.org/ testbed RSS feed for newsbeuter table item 1 http://testbed.newsbeuter.org/table1.html
    Column 1Column 2Column 3
    data 1data 2data 3
    data 1-2data 3
    data 1data 2-3
    data 1-3
    ]]> Sat, 30 Aug 2008 09:40:10 +0200 newsbeuter-testbed-tables:item1 newsbeuter-2.7/test/testbed/testbed.opml000066400000000000000000000007011220711462700205010ustar00rootroot00000000000000 newsbeuter - testbed feeds newsbeuter-2.7/test/urls-feedlist000066400000000000000000000002041220711462700172270ustar00rootroot00000000000000http://testbed.newsbeuter.org/rss20-html.xml http://testbed.newsbeuter.org/tables.xml http://testbed.newsbeuter.org/rss20.xml mytag newsbeuter-2.7/test/urls-html000066400000000000000000000000551220711462700164000ustar00rootroot00000000000000http://testbed.newsbeuter.org/rss20-html.xml newsbeuter-2.7/test/urls-html-offline000066400000000000000000000000401220711462700200120ustar00rootroot00000000000000file://./testbed/rss20-html.xml newsbeuter-2.7/test/urls-tables000066400000000000000000000000511220711462700167020ustar00rootroot00000000000000http://testbed.newsbeuter.org/tables.xml newsbeuter-2.7/test/urls-tuitest1000066400000000000000000000000561220711462700172170ustar00rootroot00000000000000http://testbed.newsbeuter.org/rss20.xml mytag newsbeuter-2.7/test/urls-tuitest1-offline000066400000000000000000000000411220711462700206310ustar00rootroot00000000000000file://./testbed/rss20.xml mytag newsbeuter-2.7/txt2h.pl000077500000000000000000000010771220711462700151650ustar00rootroot00000000000000#!/usr/bin/perl -w use strict; use File::Basename; if (length(@ARGV) < 1) { print STDOUT "usage: $0 []\n"; exit(1); } my ($filename, $extension) = @ARGV; my $id = basename($filename, $extension); chomp($id); open(my $fh, '<', $filename) or die "couldn't open $filename: $!\n"; print "#ifndef ${id}__h_included\n"; print "#define ${id}__h_included\n"; print "\n"; print "static char ${id}_str[] = \"\" "; while (my $line = <$fh>) { $line =~ s/"/\\"/g; chomp($line); print "\"$line\\n\"\n"; } close($fh); print ";\n"; print "#endif\n";