// This file is part of Snownews - A lightweight console RSS newsreader
//
// Copyright (c) 2003-2004 Oliver Feiler <kiza@kcore.de>
// Copyright (c) 2021 Mike Sharov <msharov@users.sourceforge.net>
//
// Snownews is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 3
// as published by the Free Software Foundation.
//
// Snownews 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 Snownews. If not, see http://www.gnu.org/licenses/.

#include "dialog.h"
#include "main.h"
#include "cat.h"
#include "conv.h"
#include "filters.h"
#include "feedio.h"
#include "uiutil.h"
#include "parse.h"
#include "setup.h"
#include <ncurses.h>

char* UIOneLineEntryField (int x, int y)
{
    // UIStatus switches off attron!
    attron (WA_REVERSE);
    echo();
    curs_set (1);

    move (y, x);
    // Beware of hardcoded textlength size!
    // getnstr size does NOT include \0. This is really stupid and causes
    // 1-byte overflows. Always size=len-1!
    char text [512] = {0};
    getnstr (text, sizeof(text)-1);

    noecho();
    if (!_settings.cursor_always_visible)
	curs_set (0);
    attroff (WA_REVERSE);

    // This memory needs to be freed in the calling function!
    return strdup (text);
}

void UIChangeBrowser (void)
{
    // malloc = 17 (strlen("Current setting: ") + browser
    // We will malloc a bigger junk, because other languages
    // might need longer strings and crash!
    size_t cbrsl = strlen (_("Current setting: %s")) + strlen (_settings.browser) + 1;
    char curbrowserstr[cbrsl];
    snprintf (curbrowserstr, cbrsl, _("Current setting: %s"), _settings.browser);

  repeat:
    // Clear screen area we want to "draw" to.
    attron (WA_REVERSE);
    UISupportDrawBox (3, 5, COLS - 4, 7);
    UIStatus (curbrowserstr, 0, 0);

    char* browserstring = UIOneLineEntryField (5, 6);

    if (strlen (browserstring) == 0) {
	free (browserstring);
	UIStatus (_("Aborted."), 1, 0);
	return;
    }

    const char* fmtstr = strstr (browserstring, "%");
    if (fmtstr && fmtstr[1] != 's') {
	free (browserstring);
	UIStatus (_("Only %s format strings allowed for default browser!"), 3, 1);
	goto repeat;
    }

    if (strstr (browserstring, "'") != NULL)
	UIStatus (_("Unsafe browser string (contains quotes)! See snownews.kcore.de/faq#toc2.4"), 3, 1);

    free (_settings.browser);
    _settings.browser = browserstring;
}

// Dialog to change feedname.
// Return: 0    on success
//         1    on user abort
//         2    original title restored
void UIChangeFeedName (struct feed* cur_ptr)
{
    // Clear screen area we want to "draw" to.
    attron (WA_REVERSE);
    UISupportDrawBox (3, 5, COLS - 4, 7);
    UIStatus (_("Enter new name. Blank line to abort. '-' to reset."), 0, 0);

    char* newname = UIOneLineEntryField (5, 6);

    // If strlen is zero, return 1.
    if (strlen (newname) == 0) {
	free (newname);
	return;
    }
    // If newname contains "|", abort since this is used as a delimiter for the config file.
    if (strstr (newname, "|") != NULL) {
	free (newname);
	UIStatus (_("The new title must not contain a \"|\" character!"), 2, 0);
	return;
    }
    // Restore original title.
    if (newname && cur_ptr->custom_title) {
	if (strcmp (newname, "-") == 0) {
	    if (cur_ptr->title != NULL)
		free (cur_ptr->title);
	    cur_ptr->title = cur_ptr->original;
	    // Set back original to NULL pointer.
	    cur_ptr->original = NULL;
	    free (cur_ptr->custom_title);
	    cur_ptr->custom_title = NULL;
	    free (newname);
	    return;
	}
    }
    // Copy new name into ->custom_title.
    free (cur_ptr->custom_title);
    cur_ptr->custom_title = strdup (newname);

    // Save original.
    free (cur_ptr->original);
    cur_ptr->original = cur_ptr->title;

    // Set new title.
    cur_ptr->title = newname;
    return;
}

// Popup window to add new RSS feed. Passing an URL will
// automatically add it, no questions asked.
int UIAddFeed (char* newurl)
{
    char* url;
    if (newurl == NULL) {
	// Clear screen area we want to "draw" to.
	attron (WA_REVERSE);
	UISupportDrawBox (3, 5, COLS - 4, 7);

	UIStatus (_("Enter URL of the feed you want to add. Blank line to abort."), 0, 0);

	url = UIOneLineEntryField (5, 6);

	// If read stringlength is ZARO (abort of action requested) return 1
	// and confuse the calling function.
	if (strlen (url) == 0) {
	    free (url);
	    return 1;
	}

	CleanupString (url, false);

	if (url[0] == '/') {
	    // Prefix file paths with file://
	    char* fileurl = malloc (strlen ("file://") + strlen (url) + 1);
	    sprintf (fileurl, "file://%s", url);
	    free (url);
	    url = fileurl;
	} else if (strncasecmp (url, "feed://", 7) == 0)
	    memcpy (url, "http", 4); // feed:// is http
	else if (strncasecmp (url, "http://", 7) != 0
		&& strncasecmp (url, "https://", 8) != 0
		&& strncasecmp (url, "file://", 7) != 0
		&& strncasecmp (url, "exec:", 5) != 0) {
	    // If URL does not start with the procotol specification, assume http://
	    char* httpurl = malloc (strlen ("http://") + strlen (url) + 1);
	    sprintf (httpurl, "http://%s", url);
	    free (url);
	    url = httpurl;
	}
    } else
	url = strdup (newurl);

    struct feed* new_ptr = newFeedStruct();

    // getnstr does not return newline... says the docs.
    new_ptr->feedurl = malloc (strlen (url) + 1);
    strncpy (new_ptr->feedurl, url, strlen (url) + 1);

    // Attach to feed pointer chain.
    AddFeedToList (new_ptr);

    // Tag execurl.
    if (strncasecmp (url, "exec:", 5) == 0)
	new_ptr->execurl = 1;

    if (strncasecmp (url, "smartfeed:", 10) == 0)
	new_ptr->smartfeed = 1;

    // Don't need url text anymore.
    free (url);

    // Download new feed and DeXMLize it. */
    if (UpdateFeed (new_ptr) != 0) {
	UIStatus (_("The feed could not be parsed. Do you need a filter script for this feed? (y/n)"), 0, 0);
	if (getch() == 'n')
	    return -1;
	else {
	    UIPerFeedFilter (new_ptr);
	    FilterPipeNG (new_ptr);
	    if (DeXML (new_ptr) != 0)
		return -1;
	    else
		new_ptr->problem = false;
	}
    }
    new_ptr->mtime = time (NULL);
    return 0;
}

void FeedInfo (const struct feed* current_feed)
{
    char* url = strdup (current_feed->feedurl);	// feedurl - authinfo.

    // Remove authinfo from URL.
    const char* pauthinfo = strstr (url, "@");
    if (pauthinfo)
	memmove (strstr (url, "://") + 3, pauthinfo + 1, strlen (pauthinfo));

    unsigned boxw = COLS - 6, centerx = COLS / 2u, leftx = centerx - boxw/2 + 4;

    UISupportDrawBox (5, 4, boxw, 13);

    attron (WA_REVERSE);
    mvaddn_utf8 (5, centerx - utf8_length(current_feed->title), current_feed->title, boxw-8);
    mvaddn_utf8 (7, leftx, url, boxw-8);
    move (8, leftx);
    if (current_feed->lastmodified) {
	char timebuf [32] = "";
	ctime_r (&current_feed->lastmodified, timebuf);
	for (unsigned i = 0; i < sizeof(timebuf); ++i)
	    if (timebuf[i] == '\n')
		timebuf[i] = 0;
	timebuf[sizeof(timebuf)-1] = 0;
	add_utf8 (_("Last updated: "));
	addstr (timebuf);
    } else
	add_utf8 (_("No modification date."));
    free (url);
    url = NULL;

    char* hashme = Hashify (current_feed->feedurl);
    char cachefile [PATH_MAX];
    CacheFilePath (hashme, cachefile, sizeof(cachefile));
    free (hashme);

    struct stat cachestat;
    move (9, leftx);
    if (stat (cachefile, &cachestat) < 0)
	add_utf8 (_("Not in disk cache."));
    else {
	char cacheszbuf [64];
	snprintf (cacheszbuf, sizeof(cacheszbuf), _("In disk cache: %jd bytes"), cachestat.st_size);
	add_utf8 (cacheszbuf);
    }

    // Print category info
    mvadd_utf8 (10, leftx, _("Categories:"));
    addstr (" ");
    if (current_feed->feedcategories == NULL)
	addstr (_("none"));
    else {
	char* categories = GetCategoryList (current_feed);
	printw (categories);
	free (categories);
    }

    // Tell user if feed uses auth, but don't display the string.
    move (11, leftx);
    if (current_feed->lasterror) {
	add_utf8 (_("Download failed: "));
	add_utf8 (current_feed->lasterror);
    } else if (pauthinfo)
	add_utf8 (_("Feed uses authentication."));
    else
	add_utf8 (_("Feed does not use authentication."));

    // Display filter script if any.
    if (current_feed->perfeedfilter != NULL) {
	UISupportDrawBox (5, 13, boxw, 14);
	attron (WA_REVERSE);
	const char* filteredmsg = _("Filtered through:");
	mvadd_utf8 (13, leftx, filteredmsg);
	addstr (" ");
	addn_utf8 (current_feed->perfeedfilter, boxw-8-utf8_length(filteredmsg));
    }

    UIStatus (_("Displaying feed information."), 0, 0);

    // Wait for the any key.
    getch();
}

bool UIDeleteFeed (const char* feedname)
{
    UISupportDrawBox (3, 5, COLS - 3, 8);

    attron (WA_REVERSE);
    mvadd_utf8 (6, COLS / 2 - 21, _("Are you sure you want to delete this feed?"));
    mvprintw (7, 5, "%s", feedname);

    UIStatus (_("Type 'y' to delete, any other key to abort."), 0, 0);

    return getch() == 'y';
}

void UIHelpScreen (void)
{
    unsigned centerx = COLS / 2u, centery = LINES / 2u;

    UISupportDrawBox (centerx - 20, centery - 10, centerx + 24, centery + 9);

    attron (WA_REVERSE);
    // Keys
    const int offset = 18, offsetstr = 12;
    mvprintw (centery - 9, centerx - offset, "%c:", _settings.keybindings.addfeed);
    mvprintw (centery - 8, centerx - offset, "%c:", _settings.keybindings.deletefeed);
    mvprintw (centery - 7, centerx - offset, "%c:", _settings.keybindings.changefeedname);
    mvprintw (centery - 6, centerx - offset, "%c:", _settings.keybindings.reloadall);
    mvprintw (centery - 5, centerx - offset, "%c:", _settings.keybindings.reload);
    mvprintw (centery - 4, centerx - offset, "%c:", _settings.keybindings.markallread);
    mvprintw (centery - 3, centerx - offset, "%c:", _settings.keybindings.dfltbrowser);
    mvprintw (centery - 2, centerx - offset, "%c, %c:", _settings.keybindings.moveup, _settings.keybindings.movedown);
    mvprintw (centery - 1, centerx - offset, "%c:", _settings.keybindings.sortfeeds);
    mvprintw (centery, centerx - offset, "%c:", _settings.keybindings.categorize);
    mvprintw (centery + 1, centerx - offset, "%c:", _settings.keybindings.filter);
    mvprintw (centery + 2, centerx - offset, "%c:", _settings.keybindings.filtercurrent);
    mvprintw (centery + 3, centerx - offset, "%c:", _settings.keybindings.nofilter);
    mvprintw (centery + 4, centerx - offset, "%c:", _settings.keybindings.newheadlines);
    mvprintw (centery + 5, centerx - offset, "%c:", _settings.keybindings.perfeedfilter);
    mvadd_utf8 (centery + 6, centerx - offset, _("tab:"));
    mvprintw (centery + 7, centerx - offset, "%c:", _settings.keybindings.about);
    mvprintw (centery + 8, centerx - offset, "%c:", _settings.keybindings.quit);
    // Descriptions
    mvadd_utf8 (centery - 9, centerx - offsetstr, _("Add RSS feed..."));
    mvadd_utf8 (centery - 8, centerx - offsetstr, _("Delete highlighted RSS feed..."));
    mvadd_utf8 (centery - 7, centerx - offsetstr, _("Rename feed..."));
    mvadd_utf8 (centery - 6, centerx - offsetstr, _("Reload all feeds"));
    mvadd_utf8 (centery - 5, centerx - offsetstr, _("Reload this feed"));
    mvadd_utf8 (centery - 4, centerx - offsetstr, _("Mark all read"));
    mvadd_utf8 (centery - 3, centerx - offsetstr, _("Change default browser..."));
    mvadd_utf8 (centery - 2, centerx - offsetstr, _("Move item up, down"));
    mvadd_utf8 (centery - 1, centerx - offsetstr, _("Sort feed list alphabetically"));
    mvadd_utf8 (centery, centerx - offsetstr, _("Categorize feed..."));
    mvadd_utf8 (centery + 1, centerx - offsetstr, _("Apply filter..."));
    mvadd_utf8 (centery + 2, centerx - offsetstr, _("Only current category"));
    mvadd_utf8 (centery + 3, centerx - offsetstr, _("Remove filter"));
    mvadd_utf8 (centery + 4, centerx - offsetstr, _("Show new headlines"));
    mvadd_utf8 (centery + 5, centerx - offsetstr, _("Add conversion filter..."));
    mvadd_utf8 (centery + 6, centerx - offsetstr, _("Type Ahead Find"));
    mvadd_utf8 (centery + 7, centerx - offsetstr, _("About"));
    mvadd_utf8 (centery + 8, centerx - offsetstr, _("Quit program"));
    attroff (WA_REVERSE);

    UIStatus (_("Press the any(tm) key to exit help screen."), 0, 0);
    getch();
}

void UIDisplayFeedHelp (void)
{
    unsigned centerx = COLS / 2u, centery = LINES / 2u;
    UISupportDrawBox (centerx - 20, centery - 6, centerx + 24, centery + 7);

    attron (WA_REVERSE);
    // Keys
    const int offset = 18, offsetstr = 7;
    mvprintw (centery - 5, centerx - offset, "%c", _settings.keybindings.prev);
    add_utf8 (_(", up:"));
    mvprintw (centery - 4, centerx - offset, "%c", _settings.keybindings.next);
    add_utf8 (_(", down:"));
    mvadd_utf8 (centery - 3, centerx - offset, _("enter:"));
    mvprintw (centery - 2, centerx - offset, "%c:", _settings.keybindings.reload);
    mvprintw (centery - 1, centerx - offset, "%c:", _settings.keybindings.forcereload);
    mvprintw (centery, centerx - offset, "%c:", _settings.keybindings.urljump);
    mvprintw (centery + 1, centerx - offset, "%c:", _settings.keybindings.urljump2);
    mvprintw (centery + 2, centerx - offset, "%c:", _settings.keybindings.markread);
    mvprintw (centery + 3, centerx - offset, "%c:", _settings.keybindings.markunread);
    mvprintw (centery + 4, centerx - offset, "%c:", _settings.keybindings.feedinfo);
    mvadd_utf8 (centery + 5, centerx - offset, _("tab:"));
    mvprintw (centery + 6, centerx - offset, "%c:", _settings.keybindings.prevmenu);
    // Descriptions
    mvadd_utf8 (centery - 5, centerx - offsetstr, _("Previous item"));
    mvadd_utf8 (centery - 4, centerx - offsetstr, _("Next item"));
    mvadd_utf8 (centery - 3, centerx - offsetstr, _("View item"));
    mvadd_utf8 (centery - 2, centerx - offsetstr, _("Reload this feed"));
    mvadd_utf8 (centery - 1, centerx - offsetstr, _("Force reload this feed"));
    mvadd_utf8 (centery, centerx - offsetstr, _("Open homepage"));
    mvadd_utf8 (centery + 1, centerx - offsetstr, _("Open link"));
    mvadd_utf8 (centery + 2, centerx - offsetstr, _("Mark all read"));
    mvadd_utf8 (centery + 3, centerx - offsetstr, _("Toggle item read status"));
    mvadd_utf8 (centery + 4, centerx - offsetstr, _("Show feed info..."));
    mvadd_utf8 (centery + 5, centerx - offsetstr, _("Type Ahead Find"));
    mvadd_utf8 (centery + 6, centerx - offsetstr, _("Return to main menu"));
    attroff (WA_REVERSE);

    UIStatus (_("Press the any(tm) key to exit help screen."), 0, 0);
    getch();
}

void UIDisplayItemHelp (void)
{
    unsigned centerx = COLS / 2u, centery = LINES / 2u;
    UISupportDrawBox (centerx - 18, centery - 2, centerx + 18, centery + 3);

    attron (WA_REVERSE);
    // Keys
    const int offset = 16, offsetstr = 6;
    mvprintw (centery - 1, centerx - offset, "%c, <-:", _settings.keybindings.prev);
    mvprintw (centery, centerx - offset, "%c, ->:", _settings.keybindings.next);
    mvprintw (centery + 1, centerx - offset, "%c:", _settings.keybindings.urljump);
    mvprintw (centery + 2, centerx - offset, "%c", _settings.keybindings.prevmenu);
    add_utf8 (_(", enter:"));
    // Descriptions
    mvadd_utf8 (centery - 1, centerx - offsetstr, _("Previous item"));
    mvadd_utf8 (centery, centerx - offsetstr, _("Next item"));
    mvadd_utf8 (centery + 1, centerx - offsetstr, _("Open link"));
    mvadd_utf8 (centery + 2, centerx - offsetstr, _("Return to overview"));
    attroff (WA_REVERSE);

    UIStatus (_("Press the any(tm) key to exit help screen."), 0, 0);
    getch();
}

// Add/remove categories for given feed. This takes over the main interface while running.
void CategorizeFeed (struct feed* current_feed)
{
    // Return if we got passed a NULL pointer (no feeds added to main program).
    if (current_feed == NULL)
	return;

    // Determine number of global categories.
    unsigned nglobalcat = 0;
    for (const struct categories * c = _settings.global_categories; c; c = c->next)
	++nglobalcat;

    // We're taking over the program!
    while (1) {
	// Determine number of categories for current_feed.
	unsigned nfeedcat = 0;
	for (const struct feedcategories * c = current_feed->feedcategories; c; c = c->next)
	    ++nfeedcat;

	UISupportDrawBox ((COLS / 2) - 37, 2, (COLS / 2) + 37, 1 + 4 + nfeedcat + 1);

	attron (WA_REVERSE);
	char titlebuf [256];
	snprintf (titlebuf, sizeof(titlebuf), _("Category configuration for %s"), current_feed->title);
	mvadd_utf8 (3, (COLS - utf8_length(titlebuf))/2u, titlebuf);

	char catletter = '1';
	// No category defined yet
	if (current_feed->feedcategories == NULL) {
	    unsigned y = 5;
	    mvadd_utf8 (y, (COLS / 2) - 33, _("No category defined. Select one or add a new category:"));
	    for (const struct categories * c = _settings.global_categories; c; ++y, c = c->next) {
		mvprintw (y + 1, COLS / 2 - 33, "%c. %s", catletter, c->name);
		if (++catletter == '9' + 1)
		    catletter = 'a';	// Fast forward to 'a' after the digits
	    }
	    char tmp[128];
	    snprintf (tmp, sizeof (tmp), _("Select category number to add, press 'A' to add a new category or '%c' to quit."), _settings.keybindings.quit);
	    UIStatus (tmp, 0, 0);
	} else {
	    unsigned y = 5;
	    mvadd_utf8 (y, (COLS / 2) - 33, _("Categories defined for this feed:"));
	    for (const struct feedcategories * c = current_feed->feedcategories; c; ++y, c = c->next) {
		mvprintw (y + 1, COLS / 2 - 33, "%c. %s", catletter, c->name);
		if (++catletter == '9' + 1)
		    catletter = 'a';	// Fast forward to 'a' after the digits
	    }
	    char tmp[128];
	    snprintf (tmp, sizeof (tmp), _("Select a category number to delete, press 'A' to add a new one or '%c' to quit."), _settings.keybindings.quit);
	    UIStatus (tmp, 0, 0);
	}
	refresh();

	int uiinput = getch();
	if (uiinput == _settings.keybindings.quit)
	    return;
	if (uiinput == 'A') {
	    if (nfeedcat && nglobalcat) {
		// Clear screen area we want to "draw" to.
		UISupportDrawBox ((COLS / 2) - 37, 5, (COLS / 2) + 37, 2 + 3 + nglobalcat + 1);

		attron (WA_REVERSE);
		catletter = '1';
		unsigned y = 5;
		mvadd_utf8 (y, (COLS / 2) - 33, _("Select a new category or add a new one:"));
		for (const struct categories * c = _settings.global_categories; c; ++y, c = c->next) {
		    mvprintw (y + 1, COLS / 2 - 33, "%c. %s", catletter, c->name);
		    if (++catletter == '9' + 1)
			catletter = 'a';	// Fast forward to 'a' after the digits
		}
		char tmp[128];
		snprintf (tmp, sizeof (tmp), _("Select category number to add, press 'A' to add a new category or '%c' to quit."), _settings.keybindings.quit);
		UIStatus (tmp, 0, 0);

		uiinput = getch();
	    }
	    if (uiinput == 'A') {
		// Clear screen area we want to "draw" to.
		UISupportDrawBox ((COLS / 2) - 37, 5, (COLS / 2) + 37, 1 + 5 + nglobalcat + 1);

		attron (WA_REVERSE);
		UIStatus (_("Enter new category name."), 0, 0);
		char* newcategory = UIOneLineEntryField (COLS / 2 - 33, 6);
		if (strlen (newcategory) == 0)
		    UIStatus (_("Aborted."), 1, 0);
		else if (!FeedCategoryExists (current_feed, newcategory))
		    FeedCategoryAdd (current_feed, newcategory);
		else
		    UIStatus (_("Category already defined for this feed!"), 1, 0);
		free (newcategory);
	    } else	       // To add category below.
		nfeedcat = 0;
	}
	// If uiinput < i (ASCII of max selectable element) ignore event.
	if (((uiinput >= '1' && uiinput <= '9') || (uiinput >= 'a' && uiinput <= 'z')) && uiinput < catletter) {
	    unsigned selcat;
	    if (uiinput <= '9')
		selcat = uiinput - '0';
	    else
		selcat = uiinput - ('a' - 10);
	    if (nfeedcat) {    // feed categories are only deleted in this dialog
		const struct feedcategories* c = current_feed->feedcategories;
		for (; c && selcat > 1; --selcat, c = c->next) {
		}
		FeedCategoryDelete (current_feed, c->name);
	    } else {	       // global categories are only added
		const struct categories* c = _settings.global_categories;
		for (; c && selcat > 1; --selcat, c = c->next) {
		}
		FeedCategoryAdd (current_feed, c->name);
	    }
	}
    }
}

// Allocates and returns a filter string the user has chosen from the list of
// available categories.
// If no filter is chosen a NULL pointer is returned.
char* DialogGetCategoryFilter (void)
{
    // Determine number of global categories.
    unsigned nglobalcat = 0;
    for (const struct categories * c = _settings.global_categories; c; c = c->next)
	++nglobalcat;

    UISupportDrawBox ((COLS / 2) - 35, 2, (COLS / 2) + 35, nglobalcat + 4);

    attron (WA_REVERSE);
    const char* title = _("Select filter to apply");
    mvaddstr (3, (COLS - utf8_length(title)) / 2u, title);

    char catletter = '1';
    unsigned y = 3;
    for (const struct categories * c = _settings.global_categories; c; ++y, c = c->next) {
	mvprintw (y + 1, (COLS / 2) - 33, "%c. %s", catletter, c->name);
	if (++catletter == '9' + 1)
	    catletter = 'a';   // Fast forward to 'a' after the digits
    }

    UIStatus (_("Select a category number or any other key to reset filters."), 0, 0);

    refresh();

    // If uiinput < catletter (ASCII of max selectable element) ignore event.
    int uiinput = getch();
    if (uiinput < '1' || (uiinput > '9' && uiinput < 'a') || uiinput > 'z' || uiinput >= catletter)
	return NULL;
    unsigned sel;
    if (uiinput <= '9')
	sel = uiinput - '0';
    else
	sel = uiinput - ('a' - 10);
    const struct categories* c = _settings.global_categories;
    for (; c && sel > 1; --sel, c = c->next) {
    }
    return strdup (c->name);
}

int UIPerFeedFilter (struct feed* current_feed)
{
    if (current_feed->smartfeed != 0)
	return -1;

    // Clear screen area we want to "draw" to.
    attron (WA_REVERSE);
    UISupportDrawBox (3, 5, COLS - 4, 7);

    UIStatus (_("Enter script to pipe feed through."), 0, 0);

    char* newstring = UIOneLineEntryField (5, 6);
    if (strlen (newstring) == 0) {	// If strlen is zero, return 1.
	free (newstring);
	return 1;
    } else if (strstr (newstring, "|") != NULL) {	// If newname contains "|", abort since this is used as a delimiter for the config file.
	free (newstring);
	return 3;
    } else {
	free (current_feed->perfeedfilter);
	current_feed->perfeedfilter = newstring;
	return 0;
    }
}
