Commit 0be08763 authored by Lucian Langa's avatar Lucian Langa
Browse files

hook feed properties in folder properties

parent 98d1342e
2009-05-15 Lucian Langa <lucilanga@gnome.org>
* src/org-gnome-evolution-rss.eplug.xml:
* src/rss-config-factory.c (build_dialog_add),
(actions_dialog_add), (create_dialog_add), (delete_response),
(feeds_dialog_edit), (e_plugin_lib_get_configure_widget),
(rss_folder_factory_abort), (rss_folder_factory_commit),
(rss_folder_factory): hook rss properties in folder properties
* src/rss.c (rss_error), (taskbar_op_set_progress),
(taskbar_op_finish), (statuscb), (browser_write), (pfree),
(org_gnome_cooly_format_rss), (org_gnome_cooly_folder_icon),
(setup_feed), (update_sr_message), (generic_finish_feed),
(fetch_feed), (update_articles), (get_main_folder),
(get_feed_folders), (lookup_original_folder), (update_feed_folder),
(check_feed_folder), (store_folder_renamed),
(custom_update_articles), (custom_fetch_feed), (icon_activated),
(org_gnome_cooly_rss_startup), (check_folders),
(org_gnome_cooly_rss_refresh), (org_gnome_cooly_rss),
(create_mail), (write_feed_status_line), (finish_enclosure): - various
cleanups
2009-05-12 Lucian Langa <lucilanga@gnome.org>
* src/network-soup.c: add GNOME_PROXY_RESOLVER for webkit session
......
......@@ -19,7 +19,6 @@
* when adding a feed as opml file offer to import (file detection)
* run-time migration function from text/evolution-rss-feed -> x-evolution/evolution-rss-feed
* cache large feeds
* hook feed properties in folder properties
* if necessary implement config code for evo 2.12
* fix recursivity on layer_find_pos
* fix annoying cursor jump when browsing through evo-rss folders
......
......@@ -207,7 +207,8 @@ proxify_webkit_session(EProxy *proxy, gchar *uri)
break;
g_object_set (G_OBJECT (webkit_session), SOUP_SESSION_PROXY_URI, proxy_uri, NULL);
case 0:
soup_session_add_feature_by_type (webkit_session, SOUP_TYPE_PROXY_RESOLVER_GNOME);
if (rss_soup_jar)
soup_session_add_feature_by_type (webkit_session, SOUP_TYPE_PROXY_RESOLVER_GNOME);
break;
}
......@@ -533,15 +534,13 @@ net_get_unblocking(gchar *url,
/* Queue an async HTTP request */
msg = soup_message_new ("GET", url);
if (!msg)
{
if (!msg) {
g_set_error(err, NET_ERROR, NET_ERROR_GENERIC,
soup_status_get_phrase(2)); //invalid url
return -1;
}
if (track)
{
if (track) {
//we want to be able to abort this session by calling
//abort_all_soup
g_hash_table_insert(rf->session, soup_sess, msg);
......
......@@ -64,17 +64,18 @@ HTML can be displayed using the following engines: gtkHTML, Apple's Webkit or Fi
format="org_gnome_cooly_format_rss"/>
</group>
</hook>
<!-- <hook class="org.gnome.evolution.mail.config:1.0">
<hook class="org.gnome.evolution.mail.config:1.0">
<group id="org.gnome.evolution.mail.folderConfig"
target="folder"
check= "rss_folder">
abort="rss_folder_factory_abort"
commit="rss_folder_factory_commit">
<item
type="page"
path="10.size"
_label="Size"
factory="folder_factory"/>
factory="rss_folder_factory"/>
</group>
</hook>-->
</hook>
<hook class="org.gnome.evolution.mail.events:1.0">
<event id="mail.sendreceive"
......
......@@ -246,7 +246,7 @@ parse_html(char *url, const char *html, int len)
return doc;
}
static char *
char *
layer_find_innerelement (xmlNodePtr node,
char *match, char *el,
char *fail)
......@@ -450,7 +450,7 @@ layer_find_ns_tag(xmlNodePtr node,
}
/* find matching tag (with html entities) */
static char *
char *
layer_find_tag (xmlNodePtr node,
char *match,
char *fail)
......@@ -555,7 +555,7 @@ layer_find_tag_prop (xmlNodePtr node,
return fail;
}
static gchar *
gchar *
layer_find_innerhtml (xmlNodePtr node,
char *match, char *submatch,
char *fail)
......
......@@ -22,10 +22,10 @@
gchar *update_channel(RDF *r);
char *layer_find (xmlNodePtr node, char *match, char *fail);
static char *layer_find_innerelement (xmlNodePtr node, char *match, char *el, char *fail);
static gchar *layer_find_innerhtml (xmlNodePtr node, char *match, char *submatch, char *fail);
char *layer_find_innerelement (xmlNodePtr node, char *match, char *el, char *fail);
gchar *layer_find_innerhtml (xmlNodePtr node, char *match, char *submatch, char *fail);
xmlNodePtr layer_find_pos (xmlNodePtr node, char *match, char *submatch);
static char *layer_find_tag (xmlNodePtr node, char *match, char *fail);
char *layer_find_tag (xmlNodePtr node, char *match, char *fail);
#endif /*__RSS_H__*/
......@@ -304,29 +304,30 @@ ttl_cb (GtkWidget *widget, add_feed *data)
data->ttl = adj;
}
static void
void
del_days_cb (GtkWidget *widget, add_feed *data)
{
guint adj = gtk_spin_button_get_value((GtkSpinButton*)widget);
data->del_days = adj;
}
static void
void
del_messages_cb (GtkWidget *widget, add_feed *data)
{
guint adj = gtk_spin_button_get_value((GtkSpinButton*)widget);
data->del_messages = adj;
}
add_feed *
create_dialog_add(gchar *text, gchar *feed_text)
build_dialog_add(gchar *url, gchar *feed_text)
{
char *gladefile;
add_feed *feed = g_new0(add_feed, 1);
feed->enabled = TRUE;
GladeXML *gui;
gchar *flabel = NULL;
gboolean fhtml = FALSE;
gboolean enabled = TRUE;
gboolean del_unread = FALSE;
guint del_feed = 0;
guint del_days = 10;
......@@ -340,27 +341,27 @@ create_dialog_add(gchar *text, gchar *feed_text)
g_free (gladefile);
GtkWidget *dialog1 = (GtkWidget *)glade_xml_get_widget (gui, "feed_dialog");
gtk_widget_show(dialog1);
gtk_window_set_keep_above(GTK_WINDOW(dialog1), FALSE);
if (text != NULL)
GtkWidget *child = (GtkWidget *)glade_xml_get_widget (gui, "dialog-vbox9");
// gtk_widget_show(dialog1);
// gtk_window_set_keep_above(GTK_WINDOW(dialog1), FALSE);
if (url != NULL)
gtk_window_set_title (GTK_WINDOW (dialog1), _("Edit Feed"));
else
gtk_window_set_title (GTK_WINDOW (dialog1), _("Add Feed"));
gtk_window_set_modal (GTK_WINDOW (dialog1), FALSE);
// gtk_window_set_modal (GTK_WINDOW (dialog1), FALSE);
GtkWidget *adv_options = (GtkWidget *)glade_xml_get_widget (gui, "adv_options");
GtkWidget *entry1 = (GtkWidget *)glade_xml_get_widget (gui, "url_entry");
//editing
if (text != NULL)
{
if (url != NULL) {
gtk_expander_set_expanded(GTK_EXPANDER(adv_options), TRUE);
gtk_entry_set_text(GTK_ENTRY(entry1), text);
gtk_entry_set_text(GTK_ENTRY(entry1), url);
fhtml = GPOINTER_TO_INT(
g_hash_table_lookup(rf->hrh,
lookup_key(feed_text)));
enabled = GPOINTER_TO_INT(
feed->enabled = GPOINTER_TO_INT(
g_hash_table_lookup(rf->hre,
lookup_key(feed_text)));
del_feed = GPOINTER_TO_INT(
......@@ -385,17 +386,15 @@ create_dialog_add(gchar *text, gchar *feed_text)
g_hash_table_lookup(rf->hrttl_multiply,
lookup_key(feed_text)));
}
gboolean validate = 1;
feed->validate = 1;
GtkWidget *entry2 = (GtkWidget *)glade_xml_get_widget (gui, "entry2");
if (text != NULL)
{
if (url != NULL) {
flabel = g_strdup_printf("%s: <b>%s</b>", _("Folder"),
lookup_feed_folder(feed_text));
gtk_label_set_text(GTK_LABEL(entry2), flabel);
gtk_label_set_use_markup(GTK_LABEL(entry2), 1);
}
else
} else
gtk_label_set_text(GTK_LABEL(entry2), flabel);
GtkWidget *combobox1 = (GtkWidget *)glade_xml_get_widget (gui, "combobox1");
......@@ -405,12 +404,12 @@ create_dialog_add(gchar *text, gchar *feed_text)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton1), 1-fhtml);
GtkWidget *checkbutton2 = (GtkWidget *)glade_xml_get_widget (gui, "enabled_check");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton2), enabled);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton2), feed->enabled);
GtkWidget *checkbutton3 = (GtkWidget *)glade_xml_get_widget (gui, "validate_check");
if (text)
if (url)
gtk_widget_set_sensitive(checkbutton3, FALSE);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton3), validate);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton3), feed->validate);
GtkWidget *spinbutton1 = (GtkWidget *)glade_xml_get_widget (gui, "storage_sb1");
GtkWidget *spinbutton2 = (GtkWidget *)glade_xml_get_widget (gui, "storage_sb2");
......@@ -427,8 +426,7 @@ create_dialog_add(gchar *text, gchar *feed_text)
GtkWidget *ttl_value = (GtkWidget *)glade_xml_get_widget (gui, "ttl_value");
gtk_spin_button_set_range((GtkSpinButton *)ttl_value, 0, (guint)MAX_TTL);
switch (del_feed)
{
switch (del_feed) {
case 1: //all but the last
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(radiobutton2), 1);
......@@ -455,8 +453,7 @@ create_dialog_add(gchar *text, gchar *feed_text)
gtk_combo_box_set_active(GTK_COMBO_BOX(combobox1), feed->ttl_multiply);
g_signal_connect(combobox1, "changed", G_CALLBACK(ttl_multiply_cb), feed);
switch (feed->update)
{
switch (feed->update) {
case 2:
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radiobutton5), 1);
break;
......@@ -484,21 +481,46 @@ create_dialog_add(gchar *text, gchar *feed_text)
GTK_ACCEL_VISIBLE);
gtk_window_add_accel_group (GTK_WINDOW (dialog1), accel_group);
gint result = gtk_dialog_run(GTK_DIALOG(dialog1));
switch (result)
{
feed->fetch_html = fhtml;
feed->dialog = dialog1;
feed->child = child;
feed->gui = gui;
if (flabel)
g_free(flabel);
return feed;
}
void
actions_dialog_add(add_feed *feed, gchar *url)
{
GtkWidget *entry1 = (GtkWidget *)glade_xml_get_widget (feed->gui, "url_entry");
GtkWidget *checkbutton1 = (GtkWidget *)glade_xml_get_widget (feed->gui, "html_check");
GtkWidget *checkbutton2 = (GtkWidget *)glade_xml_get_widget (feed->gui, "enabled_check");
GtkWidget *checkbutton3 = (GtkWidget *)glade_xml_get_widget (feed->gui, "validate_check");
GtkWidget *checkbutton4 = (GtkWidget *)glade_xml_get_widget (feed->gui, "storage_unread");
GtkWidget *radiobutton1 = (GtkWidget *)glade_xml_get_widget (feed->gui, "storage_rb1");
GtkWidget *radiobutton2 = (GtkWidget *)glade_xml_get_widget (feed->gui, "storage_rb2");
GtkWidget *radiobutton3 = (GtkWidget *)glade_xml_get_widget (feed->gui, "storage_rb3");
GtkWidget *radiobutton4 = (GtkWidget *)glade_xml_get_widget (feed->gui, "ttl_global");
GtkWidget *radiobutton5 = (GtkWidget *)glade_xml_get_widget (feed->gui, "ttl");
GtkWidget *radiobutton6 = (GtkWidget *)glade_xml_get_widget (feed->gui, "ttl_disabled");
GtkWidget *spinbutton1 = (GtkWidget *)glade_xml_get_widget (feed->gui, "storage_sb1");
GtkWidget *spinbutton2 = (GtkWidget *)glade_xml_get_widget (feed->gui, "storage_sb2");
GtkWidget *ttl_value = (GtkWidget *)glade_xml_get_widget (feed->gui, "ttl_value");
gboolean fhtml = feed->fetch_html;
gint result = gtk_dialog_run(GTK_DIALOG(feed->dialog));
switch (result) {
case GTK_RESPONSE_OK:
feed->feed_url = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry1)));
fhtml = gtk_toggle_button_get_active (
GTK_TOGGLE_BUTTON (checkbutton1));
fhtml ^= 1;
feed->fetch_html = fhtml;
enabled = gtk_toggle_button_get_active(
feed->enabled = gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(checkbutton2));
feed->enabled = enabled;
validate = gtk_toggle_button_get_active(
feed->validate = gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(checkbutton3));
feed->validate = validate;
guint i=0;
while (i<3) {
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radiobutton1)))
......@@ -532,20 +554,26 @@ create_dialog_add(gchar *text, gchar *feed_text)
feed->ttl = gtk_spin_button_get_value((GtkSpinButton *)ttl_value);
feed->add = 1;
// there's no reason to feetch feed if url isn't changed
if (text && !strncmp(text, feed->feed_url, strlen(text)))
if (url && !strncmp(url, feed->feed_url, strlen(url)))
feed->changed = 0;
else
feed->changed = 1;
break;
default:
feed->add = 0;
gtk_widget_destroy (dialog1);
gtk_widget_destroy (feed->dialog);
break;
}
feed->dialog = dialog1;
if (flabel)
g_free(flabel);
return feed;
}
add_feed *
create_dialog_add(gchar *url, gchar *feed_text)
{
add_feed *feed = NULL;
feed = build_dialog_add(url, feed_text);
actions_dialog_add(feed, url);
return feed;
}
void
......@@ -784,11 +812,9 @@ delete_response(GtkWidget *selector, guint response, gpointer user_data)
CamelFolder *mail_folder;
if (response == GTK_RESPONSE_OK) {
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(user_data));
if (gtk_tree_selection_get_selected(selection, &model, &iter))
{
if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
gtk_tree_model_get (model, &iter, 3, &name, -1);
if (gconf_client_get_bool(rss_gconf, GCONF_KEY_REMOVE_FOLDER, NULL))
{
if (gconf_client_get_bool(rss_gconf, GCONF_KEY_REMOVE_FOLDER, NULL)) {
//delete folder
CamelStore *store = mail_component_peek_local_store(NULL);
gchar *full_path = g_strdup_printf("%s/%s",
......@@ -797,8 +823,7 @@ delete_response(GtkWidget *selector, guint response, gpointer user_data)
delete_feed_folder_alloc(lookup_feed_folder(name));
camel_exception_init (&ex);
rss_delete_folders (store, full_path, &ex);
if (camel_exception_is_set (&ex))
{
if (camel_exception_is_set (&ex)) {
e_error_run(NULL,
"mail:no-delete-folder", full_path, ex.desc, NULL);
camel_exception_clear (&ex);
......@@ -922,22 +947,20 @@ feeds_dialog_edit(GtkDialog *d, gpointer data)
/* This will only work in single or browse selection mode! */
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
if (gtk_tree_selection_get_selected(selection, &model, &iter))
{
if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
gtk_tree_model_get (model, &iter, 3, &feed_name, -1);
name = g_hash_table_lookup(rf->hr, lookup_key(feed_name));
if (name)
{
if (name) {
add_feed *feed = create_dialog_add(name, feed_name);
if (feed->dialog)
gtk_widget_destroy(feed->dialog);
GtkWidget *msg_feeds = e_error_new(NULL, "org-gnome-evolution-rss:rssmsg", "", NULL);
GtkWidget *progress = gtk_progress_bar_new();
gtk_box_pack_start(GTK_BOX(((GtkDialog *)msg_feeds)->vbox), progress, FALSE, FALSE, 0);
gtk_progress_bar_set_fraction((GtkProgressBar *)progress, 0);
/* xgettext:no-c-format */
gtk_progress_bar_set_text((GtkProgressBar *)progress, _("0% done"));
feed->progress=progress;
GtkWidget *progress = gtk_progress_bar_new();
gtk_box_pack_start(GTK_BOX(((GtkDialog *)msg_feeds)->vbox), progress, FALSE, FALSE, 0);
gtk_progress_bar_set_fraction((GtkProgressBar *)progress, 0);
/* xgettext:no-c-format */
gtk_progress_bar_set_text((GtkProgressBar *)progress, _("0% done"));
feed->progress=progress;
gtk_window_set_keep_above(GTK_WINDOW(msg_feeds), TRUE);
g_signal_connect(msg_feeds, "response", G_CALLBACK(msg_feeds_response), NULL);
gtk_widget_show_all(msg_feeds);
......@@ -949,12 +972,10 @@ feeds_dialog_edit(GtkDialog *d, gpointer data)
feed->feed_url = sanitize_url(feed->feed_url);
g_free(text);
url = name;
if (feed->feed_url)
{
if (feed->feed_url) {
gtk_tree_model_get (model, &iter, 3, &name, -1);
gpointer key = lookup_key(name);
if (strcmp(url, feed->feed_url))
{
if (strcmp(url, feed->feed_url)) {
//prevent adding of an existing feed (url)
//which might screw things
if (g_hash_table_find(rf->hr,
......@@ -968,27 +989,22 @@ feeds_dialog_edit(GtkDialog *d, gpointer data)
hrfeed *saved_feed = save_feed_hash(name);
remove_feed_hash(name);
gpointer md5 = gen_md5(feed->feed_url);
if (!setup_feed(feed))
{
if (!setup_feed(feed)) {
//editing might loose a corectly setup feed
//so re-add previous deleted feed
restore_feed_hash(key, saved_feed);
}
else
} else
destroy_feed_hash_content(saved_feed);
gtk_list_store_clear(GTK_LIST_STORE(model));
g_hash_table_foreach(rf->hrname, construct_list, model);
save_gconf_feed();
g_free(md5);
}
else
{
} else {
key = gen_md5(url);
g_hash_table_replace(rf->hrh,
g_strdup(key),
GINT_TO_POINTER(feed->fetch_html));
if (feed->update == 2)
{
if (feed->update == 2) {
g_hash_table_replace(rf->hrttl,
g_strdup(key),
GINT_TO_POINTER(feed->ttl));
......@@ -1663,8 +1679,7 @@ e_plugin_lib_get_configure_widget (EPlugin *epl)
GCONF_KEY_HTML_RENDER,
NULL));
switch (render)
{
switch (render) {
case 10:
gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
break;
......@@ -1760,49 +1775,45 @@ e_plugin_lib_get_configure_widget (EPlugin *epl)
return hbox;
}
GtkWidget *
folder_factory (EPlugin *epl, EConfigHookItemFactoryData *data)
void rss_folder_factory_abort (EPlugin *epl, EConfigTarget *target)
{
EMConfigTargetFolder *target= (EMConfigTargetFolder *)data->config->target;
GtkWidget *lbl_size, *lbl_size_val;
GtkVBox *vbx;
GtkHBox *hbx_size;
char *folder_size;
GladeXML *gui;
g_print("abort");
}
char *gladefile;
gladefile = g_build_filename (EVOLUTION_GLADEDIR,
"rss-ui.glade",
NULL);
gui = glade_xml_new (gladefile, NULL, NULL);
g_free (gladefile);
void rss_folder_factory_commit (EPlugin *epl, EConfigTarget *target)
{
g_print("commit");
}
GtkWidget *dialog1 = (GtkWidget *)glade_xml_get_widget (gui, "vbox6");
// gtk_widget_show(dialog1);
GtkWidget *
rss_folder_factory (EPlugin *epl, EConfigHookItemFactoryData *data)
{
EMConfigTargetFolder *target = (EMConfigTargetFolder *)data->config->target;
gchar *url = NULL, *ofolder = NULL;
gchar *main_folder = get_main_folder();
gchar *folder = target->folder->full_name;
add_feed *feed = NULL;
//filter only rss folders
if (folder == NULL
|| g_ascii_strncasecmp(folder, main_folder, strlen(main_folder)))
goto out;
ofolder = lookup_original_folder(folder);
url = g_hash_table_lookup(rf->hr, lookup_key(ofolder));
if (url) {
feed = build_dialog_add(url, ofolder);
//we do not need ok/cancel buttons here
GtkWidget *action_area = gtk_dialog_get_action_area(GTK_DIALOG(feed->dialog));
gtk_widget_hide(action_area);
gtk_widget_ref(feed->child);
gtk_container_remove (GTK_CONTAINER (feed->child->parent), feed->child);
gtk_notebook_remove_page((GtkNotebook *) data->parent, 0);
gtk_notebook_insert_page((GtkNotebook *) data->parent, (GtkWidget *) feed->child, NULL, 0);
}
// model = exchange_account_folder_size_get_model (account);
// if (model)
// folder_size = g_strdup_printf (_("%s KB"), exchange_folder_size_get_val (model, folder_name));
// else
folder_size = g_strdup (_("0 KB"));
hbx_size = (GtkHBox*) gtk_window_new (GTK_WINDOW_POPUP);
vbx = (GtkVBox *)gtk_notebook_get_nth_page (GTK_NOTEBOOK (data->parent), 0);
lbl_size = gtk_label_new_with_mnemonic (_("Size:"));
lbl_size_val = gtk_label_new_with_mnemonic (_(folder_size));
gtk_widget_show (lbl_size);
gtk_widget_show (lbl_size_val);
gtk_misc_set_alignment (GTK_MISC (lbl_size), 0.0, 0.5);
gtk_misc_set_alignment (GTK_MISC (lbl_size_val), 0.0, 0.5);
gtk_box_pack_start (GTK_BOX (dialog1), lbl_size, FALSE, TRUE, 12);
gtk_box_pack_start (GTK_BOX (dialog1), lbl_size_val, FALSE, TRUE, 10);
gtk_widget_show_all (GTK_WIDGET (dialog1));
gtk_box_pack_start (GTK_BOX (vbx), GTK_WIDGET (dialog1), FALSE, FALSE, 0);
g_free (folder_size);
return GTK_WIDGET (hbx_size);
g_free(ofolder);
out: return NULL;
}
/*=============*
......
......@@ -21,6 +21,7 @@
void store_redraw(GtkTreeView *data);
void import_dialog_response(GtkWidget *selector, guint response, gpointer user_data);
void del_days_cb (GtkWidget *widget, add_feed *data);
#endif /*__RSS_CONFIG_FACTORY_H_*/
This diff is collapsed.
......@@ -179,6 +179,8 @@ enum {
typedef struct ADD_FEED {
GtkWidget *dialog;
GtkWidget *progress;
GtkWidget *child; //the dialog child
GladeXML *gui;
gchar *feed_url;
gchar *feed_name;
gboolean fetch_html; //show webpage instead of summary
......@@ -307,6 +309,7 @@ gboolean update_articles(gboolean disabler);
xmlNode *html_find (xmlNode *node, char *match);
gchar *lookup_main_folder(void);
gchar *lookup_feed_folder(gchar *folder);
gchar *lookup_original_folder(gchar *folder);
gchar *decode_utf8_entities(gchar *str);
gchar *decode_html_entities(gchar *str);
gchar *get_real_channel_name(gchar *uri, gchar *failed);
......@@ -350,6 +353,7 @@ CamelFolder *check_feed_folder(gchar *folder_name);
gboolean setup_feed(add_feed *feed);
gboolean feed_is_new(gchar *file_name, gchar *needle);
gboolean web_auth_dialog(gchar *url);
gchar *get_main_folder(void);
#ifdef _WIN32
char *strcasestr(const char *a, const char *b);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment