Added support for receiving notifications.

When issue gets update, reporter can receive mail notifications, but has to have bugzilla account first. The later could not be avoided. Implements #201.
This commit is contained in:
Sanel Zukan 2012-11-07 12:49:43 +00:00
parent c605359ea1
commit 15dd0b0a80
7 changed files with 145 additions and 78 deletions

View File

@ -28,14 +28,18 @@ struct BugzillaData {
xmlrpc_env xenv;
xmlrpc_client *xcli;
String url;
BugzillaErrorCallback cb;
void *cb_data;
};
BugzillaData *bugzilla_new(const char *u) {
BugzillaData *bugzilla_new(const char *url, BugzillaErrorCallback cb, void *cb_data) {
BugzillaData *data = new BugzillaData;
bugzilla_set_error_callback(data, cb, cb_data);
xmlrpc_env_init(&data->xenv);
xmlrpc_client_setup_global_const(&data->xenv);
data->url = u;
data->url = url;
/*
* to allow https connections; curl by default refuse connections without valid certificate
@ -51,6 +55,7 @@ BugzillaData *bugzilla_new(const char *u) {
xmlrpc_client_create(&data->xenv, XMLRPC_CLIENT_NO_FLAGS, "ede-bug-report", "0.1", &gparms, sizeof(gparms), &data->xcli);
if(data->xenv.fault_occurred) {
E_WARNING(E_STRLOC ": Unable to init xmlrpc client data (%s)\n", data->xenv.fault_string);
if(cb) cb(data->xenv.fault_string, cb_data);
delete data;
data = NULL;
}
@ -68,6 +73,12 @@ void bugzilla_free(BugzillaData *data) {
delete data;
}
void bugzilla_set_error_callback(BugzillaData *data, BugzillaErrorCallback cb, void *cb_data) {
E_ASSERT(data != NULL);
data->cb = cb;
data->cb_data = cb_data;
}
char *bugzilla_get_version(BugzillaData *data) {
E_ASSERT(data != NULL);
@ -76,12 +87,12 @@ char *bugzilla_get_version(BugzillaData *data) {
if(data->xenv.fault_occurred) {
E_WARNING(E_STRLOC ": Unable to call xmlrpc function (%s)\n", data->xenv.fault_string);
if(data->cb) (data->cb)(data->xenv.fault_string, data->cb_data);
return (char*)"";
}
/* this value will be malloc()-ated by xmlrpc_decompose_value() and should be freeed by user */
char *ret;
xmlrpc_decompose_value(&data->xenv, result, "{s:s,*}", "version", &ret);
xmlrpc_DECREF(result);
@ -103,6 +114,7 @@ int bugzilla_login(BugzillaData *data, const char *user, const char *passwd) {
if(data->xenv.fault_occurred) {
E_WARNING(E_STRLOC ": Unable to perform login function (%s)\n", data->xenv.fault_string);
if(data->cb) (data->cb)(data->xenv.fault_string, data->cb_data);
return id;
}
@ -120,41 +132,70 @@ void bugzilla_logout(BugzillaData *data) {
if(data->xenv.fault_occurred) {
E_WARNING(E_STRLOC ": Unable to call xmlrpc function (%s)\n", data->xenv.fault_string);
if(data->cb) (data->cb)(data->xenv.fault_string, data->cb_data);
return;
}
xmlrpc_DECREF(result);
}
int bugzilla_submit_bug(BugzillaData *data, const char *product,
const char *component,
const char *summary,
const char *version,
const char *description,
const char *op_sys,
const char *platform,
const char *priority,
const char *severity)
int bugzilla_submit_bug(BugzillaData *data,
const char *product,
const char *component,
const char *summary,
const char *version,
const char *description,
const char *op_sys,
const char *platform,
const char *priority,
const char *severity,
const char *cc)
{
E_ASSERT(data != NULL);
int bug_id = -1;
xmlrpc_value *result;
xmlrpc_client_call2f(&data->xenv, data->xcli, data->url.c_str(), "Bug.create", &result,
"({s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s})",
"product", product,
"component", component,
"summary", summary,
"version", version,
"description", description,
"op_sys", op_sys,
"platform", platform,
"priority", priority,
"severity", severity);
/* if given CC, add it so bugzilla assign that email as notification receiver */
if(cc) {
/* as for now we only support single email address */
xmlrpc_value *cc_array, *cc_str;
cc_array = xmlrpc_array_new(&data->xenv);
cc_str = xmlrpc_string_new(&data->xenv, (const char *const)cc);
xmlrpc_array_append_item(&data->xenv, cc_array, cc_str);
xmlrpc_DECREF(cc_str);
xmlrpc_client_call2f(&data->xenv, data->xcli, data->url.c_str(), "Bug.create", &result,
"({s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:A})",
"product", product,
"component", component,
"summary", summary,
"version", version,
"description", description,
"op_sys", op_sys,
"platform", platform,
"priority", priority,
"severity", severity,
"cc", cc_array);
xmlrpc_DECREF(cc_array);
} else {
xmlrpc_client_call2f(&data->xenv, data->xcli, data->url.c_str(), "Bug.create", &result,
"({s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s})",
"product", product,
"component", component,
"summary", summary,
"version", version,
"description", description,
"op_sys", op_sys,
"platform", platform,
"priority", priority,
"severity", severity);
}
if(data->xenv.fault_occurred) {
E_WARNING(E_STRLOC ": Unable to perform submit function (%s)\n", data->xenv.fault_string);
if(data->cb) (data->cb)(data->xenv.fault_string, data->cb_data);
return bug_id;
}

View File

@ -14,9 +14,11 @@
#define __BUGZILLA_H__
struct BugzillaData;
typedef void (*BugzillaErrorCallback)(const char *str, void *data);
BugzillaData *bugzilla_new(const char *url);
BugzillaData *bugzilla_new(const char *url, BugzillaErrorCallback cb = NULL, void *data = NULL);
void bugzilla_free(BugzillaData *data);
void bugzilla_set_error_callback(BugzillaData *data, BugzillaErrorCallback cb, void *cb_data = NULL);
/* return bugzilla version or empty string if fails; returned value must be free()-ed */
char *bugzilla_get_version(BugzillaData *data);
@ -26,13 +28,15 @@ int bugzilla_login(BugzillaData *data, const char *user, const char *
void bugzilla_logout(BugzillaData *data);
/* return bug id or -1 if fails */
int bugzilla_submit_bug(BugzillaData *data, const char *product,
const char *component,
const char *summary,
const char *version,
const char *description,
const char *op_sys,
const char *platform,
const char *priority,
const char *severity);
int bugzilla_submit_bug(BugzillaData *data,
const char *product,
const char *component,
const char *summary,
const char *version,
const char *description,
const char *op_sys,
const char *platform,
const char *priority,
const char *severity,
const char *cc);
#endif

View File

@ -27,10 +27,10 @@
#include <edelib/String.h>
#include "PulseProgress.h"
#include "BugzillaSender.h"
#include "Bugzilla.h"
#include "BugzillaSender.h"
#define EDE_BUGZILLA_XMLRPC_URL "http://bugs.equinox-project.org/xmlrpc.cgi"
#define EDE_BUGZILLA_XMLRPC_URL "http://bugs.equinox-project.org/xmlrpc.cgi"
/* must match to existing user */
#define EDE_BUGZILLA_USER "ede-bugs@lists.sourceforge.net"
@ -49,6 +49,7 @@ EDELIB_NS_USING(String)
struct BugContent {
const char *bug_title;
const char *bug_content;
const char *bug_sender;
};
static Fl_Double_Window *win;
@ -176,13 +177,13 @@ static void* thread_worker(void *d) {
goto done;
}
/* wait some time if user decided to press 'Cancel' */
sleep(1);
pthread_mutex_lock(&runner_mutex);
should_cancel = cancel_sending;
pthread_mutex_unlock(&runner_mutex);
/* allow user to cancel it */
sleep(1);
if(should_cancel) {
write_string(report_pipe[1], "CANCELED");
goto done;
@ -190,18 +191,18 @@ static void* thread_worker(void *d) {
write_string(report_pipe[1], _("Submitting the report..."));
ret = bugzilla_submit_bug(bdata,
"ede",
"general",
data->bug_title,
"unspecified",
data->bug_content,
"All",
"All",
"P5",
"normal");
"ede",
"general",
data->bug_title,
"unspecified",
data->bug_content,
"All",
"All",
"P5",
"normal",
data->bug_sender);
if(ret == -1) {
write_string_fail(report_pipe[1], _("Unable to properly submit the data. Please try again"));
write_string_fail(report_pipe[1], _("Unable to send the data. Either your email address is not registered on EDE Tracker or the host is temporarily down"));
goto done;
}
@ -214,11 +215,11 @@ done:
delete data;
pthread_exit(NULL);
/* shutup compiler */
/* shutup the compiler */
return NULL;
}
static void perform_send(const char *title, const char *content) {
static void perform_send(const char *title, const char *content, const char *sender) {
pthread_t thread;
/*
@ -228,6 +229,7 @@ static void perform_send(const char *title, const char *content) {
BugContent *c = new BugContent;
c->bug_title = title;
c->bug_content = content;
c->bug_sender = sender;
/* Create joinable thread. Some implementations prefer this explicitly was set. */
pthread_attr_t attr;
@ -244,33 +246,36 @@ static void perform_send(const char *title, const char *content) {
pthread_attr_destroy(&attr);
}
bool bugzilla_send_with_progress(const char *title, const char *content) {
bool bugzilla_send_with_progress(const char *title, const char *content, const char *cc) {
data_submitted = false;
cancel_sending = false;
bdata = bugzilla_new(EDE_BUGZILLA_XMLRPC_URL);
if(!bdata) {
alert(_("Unable to initialize bugzilla interface!"));
return false;
}
/* setup communication as soon as possible */
if(pipe(report_pipe) != 0) {
alert(_("Unable to initialize communication pipe"));
return false;
}
/* prepare mutex */
pthread_mutex_init(&runner_mutex, NULL);
Fl_Button *cancel;
/* register our callback on pipe */
Fl::add_fd(report_pipe[0], FL_READ, report_pipe_cb);
bdata = bugzilla_new(EDE_BUGZILLA_XMLRPC_URL);
if(!bdata) {
alert(_("Unable to initialize bugzilla interface!"));
goto send_done;
}
/* prepare mutex */
pthread_mutex_init(&runner_mutex, NULL);
win = new Fl_Double_Window(275, 90, _("Sending report data"));
win->begin();
progress = new PulseProgress(10, 20, 255, 25, _("Sending report..."));
progress->selection_color((Fl_Color)137);
Fl_Button *cancel = new Fl_Button(175, 55, 90, 25, _("&Cancel"));
cancel = new Fl_Button(175, 55, 90, 25, _("&Cancel"));
cancel->callback(cancel_cb);
win->end();
@ -280,17 +285,18 @@ bool bugzilla_send_with_progress(const char *title, const char *content) {
progress->label(_("Preparing data..."));
Fl::add_timeout(PROGRESS_STEP_REFRESH, progress_timeout);
perform_send(title, content);
perform_send(title, content, cc);
while(win->shown())
Fl::wait();
pthread_mutex_destroy(&runner_mutex);
send_done:
/* clear pipe callback */
Fl::remove_fd(report_pipe[0]);
clear_timeouts();
pthread_mutex_destroy(&runner_mutex);
close(report_pipe[0]);
close(report_pipe[1]);

View File

@ -13,6 +13,8 @@
#ifndef __BUGZILLASENDER_H__
#define __BUGZILLASENDER_H__
bool bugzilla_send_with_progress(const char *title, const char *content);
bool bugzilla_send_with_progress(const char *title,
const char *content,
const char *cc);
#endif

View File

@ -43,7 +43,7 @@ void PulseProgress::draw(void) {
draw_box(box(), x(), y(), w(), h(), color());
fl_clip(xoff, yoff, woff, hoff);
fl_push_clip(xoff, yoff, woff, hoff);
Fl_Color c = fl_color();
fl_color(color2());
@ -63,6 +63,7 @@ void PulseProgress::draw(void) {
fl_color(c);
fl_pop_clip();
labelcolor(fl_contrast(labelcolor(), color()));
draw_label(x() + bx, y() + by, w() - bw, h() - bh);
}

View File

@ -23,6 +23,7 @@
#include <FL/Fl_Text_Editor.H>
#include <FL/Fl_Text_Buffer.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Check_Button.H>
#include <edelib/Window.h>
#include <edelib/WindowUtils.h>
@ -49,6 +50,7 @@ EDELIB_NS_USING(RX_CASELESS)
static Fl_Input *bug_title_input;
static Fl_Input *email_input;
static Fl_Text_Buffer *text_buf;
static Fl_Check_Button *notify_reporter;
/* check if string has spaces */
static bool empty_entry(const char *en) {
@ -67,7 +69,7 @@ static bool valid_email(const char *e) {
Regex r;
/* regex stolen from http://www.regular-expressions.info/email.html */
if(!r.compile("\\b[A-Z0-9._%-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b", RX_CASELESS)) {
if(!r.compile("^\\b[A-Z0-9._%-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b$", RX_CASELESS)) {
E_WARNING(E_STRLOC ": Unable to properly compile regex pattern");
return false;
}
@ -81,8 +83,8 @@ static void close_cb(Fl_Widget*, void *w) {
}
static void send_cb(Fl_Widget*, void *w) {
const char *txt;
String title, content;
const char *txt, *cc = NULL;
String title, content;
if(empty_entry(bug_title_input->value())) {
alert(_("Report title is missing"));
@ -102,7 +104,7 @@ static void send_cb(Fl_Widget*, void *w) {
}
if(!valid_email(email_input->value())) {
alert(_("Email address is invalid. Please use the valid email address"));
alert(_("Email address is invalid. Please use the valid email address so developers can contact you in case more details are needed"));
return;
}
@ -126,7 +128,10 @@ static void send_cb(Fl_Widget*, void *w) {
free((void *) txt);
if(bugzilla_send_with_progress(title.c_str(), content.c_str()))
if(notify_reporter->value())
cc = email_input->value();
if(bugzilla_send_with_progress(title.c_str(), content.c_str(), cc))
close_cb(0, w);
}
#endif /* HAVE_CURL */
@ -184,6 +189,10 @@ int main(int argc, char** argv) {
E_WARNING(E_STRLOC ": Unable to read '%s' as debugger output. Continuing...\n");
}
notify_reporter = new Fl_Check_Button(10, 330, 265, 25, _("Receive notifications"));
notify_reporter->tooltip(_("Receive notifications when developers updates or comments this issue. You have to create EDE Bugzilla account first to get notifications."));
notify_reporter->down_box(FL_DOWN_BOX);
/* resizable box */
Fl_Box *rbox = new Fl_Box(180, 273, 55, 37);
@ -195,9 +204,9 @@ int main(int argc, char** argv) {
Fl_Group::current()->resizable(rbox);
win->window_icon(bug_xpm);
/* win->show(argc, argv); */
window_center_on_screen(win);
win->show();
win->show(argc, argv);
return Fl::run();
#endif /* HAVE_CURL */
}

View File

@ -1,19 +1,19 @@
# data file for the Fltk User Interface Designer (fluid)
version 1.0108
version 1.0300
header_name {.h}
code_name {.cxx}
Function {} {open
} {
Fl_Window {} {
label {EDE Bug Reporting Tool} open
xywh {357 193 480 365} type Double resizable visible
xywh {353 189 480 365} type Double resizable visible
} {
Fl_Box {} {
image {../icons/bug.png} xywh {10 10 60 59}
}
Fl_Box {} {
label {EDE Bug Reporting Tool}
xywh {80 10 390 30} labelfont 1 labelsize 14 align 20
xywh {80 10 390 30} labelfont 1 align 20
}
Fl_Box {} {
label {To help us to improve the future EDE versions, please describe the problem with much details as possible.
@ -33,6 +33,10 @@ Note: valid email address is required, so developers can contact you for more in
label {Detail description of the problem:}
xywh {10 215 460 105} align 5
}
Fl_Check_Button {} {
label {Receive notifications} selected
tooltip {Receive notifications when developers updates or comments this issue} xywh {10 330 265 25} down_box DOWN_BOX
}
Fl_Button {} {
label {&Send}
xywh {285 330 90 25}
@ -41,8 +45,8 @@ Note: valid email address is required, so developers can contact you for more in
label {&Cancel}
xywh {380 330 90 25}
}
Fl_Box {} {selected
xywh {180 273 55 37} labelsize 14 resizable
Fl_Box {} {
xywh {180 273 55 37} resizable
code0 {/* resizable box */}
}
}