diff --git a/doc/variables.xml b/doc/variables.xml
index 28b453f5..8fb4c120 100644
--- a/doc/variables.xml
+++ b/doc/variables.xml
@@ -1499,6 +1499,14 @@
Percent of file system used space.
+
+
+
+
+
+
+ Number of GitHub notifications.
+
@@ -1507,7 +1515,6 @@
The next element will be printed at position 'x'.
-
diff --git a/src/common.cc b/src/common.cc
index 799fd5c1..d0c5b07b 100644
--- a/src/common.cc
+++ b/src/common.cc
@@ -275,6 +275,7 @@ void format_seconds_short(char *buf, unsigned int n, long seconds) {
conky::simple_config_setting no_buffers("no_buffers", true, true);
conky::simple_config_setting bar_fill("console_bar_fill", "#", false);
conky::simple_config_setting bar_unfill("console_bar_unfill", ".", false);
+conky::simple_config_setting github_token("github_token", "", false);
void update_stuff() {
/* clear speeds, addresses and up status in case device was removed and
@@ -692,6 +693,106 @@ void print_include(struct text_object *obj, char *p, unsigned int p_max_size) {
}
#ifdef BUILD_CURL
+#define NEW_TOKEN "https://github.com/settings/tokens/new?scopes=notifications&description=conky-query-github\n"
+static size_t read_github_data_cb(char *, size_t, size_t, char *);
+static size_t read_github_data_cb(char *data, size_t size, size_t nmemb, char *p) {
+ char *ptr = data;
+ size_t sz = nmemb * size;
+ size_t z = 0;
+ static size_t x = 0;
+ static unsigned int skip = 0U;
+
+ for (; *ptr; ptr++, z++) {
+ if (z+4 < sz) { /* Verifying up to *(ptr+4) */
+ if ('u' == *ptr && 'n' == *(ptr+1) &&
+ 'r' == *(ptr+2) && 'e' == *(ptr+3)) { /* "unread" */
+ ++x;
+ skip = 0U;
+ }
+ if ('m' == *ptr && 'e' == *(ptr+1) &&
+ 's' == *(ptr+2) && 's' == *(ptr+3) && z+13 < sz) { /* "message": */
+ if ('B' == *(ptr+10) && 'a' == *(ptr+11) &&
+ 'd' == *(ptr+12)) { /* "Bad credentials" */
+ NORM_ERR("Bad credentials: generate a new token:\n" NEW_TOKEN);
+ snprintf(p, 80, "%s", "GitHub: Bad credentials, generate a new token.");
+ skip = 1U;
+ break;
+ }
+ if ('M' == *(ptr+10) && 'i' == *(ptr+11) &&
+ 's' == *(ptr+12)) { /* Missing the 'notifications' scope. */
+ NORM_ERR("Missing 'notifications' scope. Generate a new token\n" NEW_TOKEN);
+ snprintf(p, 80, "%s", "GitHub: Missing the notifications scope. Generate a new token.");
+ skip = 1U;
+ break;
+ }
+ }
+ }
+ }
+ if (0U == skip) {
+ snprintf(p, 49, "%zu", x);
+ }
+ return sz;
+}
+
+void print_github(struct text_object *obj, char *p, unsigned int p_max_size) {
+ (void)obj;
+ char github_url[256] = {""};
+ char user_agent[30] = {""};
+ static char cached_result[256] = {""};
+ static unsigned int last_update = 1U;
+ CURL *curl = nullptr;
+ CURLcode res;
+
+ if (0 == strcmp(github_token.get(*state).c_str(), "")) {
+ NORM_ERR("${github_notifications} requires token. "
+ "Go ahead and generate one "
+ NEW_TOKEN
+ "Insert it in conky.config = { github_token='TOKEN_SHA' }\n");
+ snprintf(p, p_max_size, "%s", "GitHub notifications requires token, generate a new one.");
+ return;
+ }
+
+ if (1U != last_update) {
+ --last_update;
+ snprintf(p, p_max_size, "%s", cached_result);
+ return;
+ }
+
+ snprintf(github_url, 255, "%s%s",
+ "https://api.github.com/notifications?access_token=", github_token.get(*state).c_str());
+ /* unique string for each conky user, so we dont hit any query limits */
+ snprintf(user_agent, 29, "conky/%s", github_token.get(*state).c_str());
+
+ curl_global_init(CURL_GLOBAL_ALL);
+ if (nullptr == (curl = curl_easy_init())) {
+ goto error;
+ }
+ curl_easy_setopt(curl, CURLOPT_URL, github_url);
+ curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "gzip");
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent);
+ curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20L);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, read_github_data_cb);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, p);
+
+ res = curl_easy_perform(curl);
+ if (CURLE_OK != res) {
+ goto error;
+ }
+ snprintf(cached_result, 255, "%s", p);
+ last_update = 60U;
+
+error:
+ if (nullptr != curl) {
+ curl_easy_cleanup(curl);
+ }
+ curl_global_cleanup();
+
+ if (!isdigit((unsigned char)*p)) {
+ last_update = 1U;
+ }
+}
+
void print_stock(struct text_object *obj, char *p, unsigned int p_max_size) {
if (!obj->data.s) {
p[0] = 0;
diff --git a/src/common.h b/src/common.h
index e1b7353a..23c83f37 100644
--- a/src/common.h
+++ b/src/common.h
@@ -76,6 +76,7 @@ unsigned int round_to_int(float);
extern conky::simple_config_setting no_buffers;
extern conky::simple_config_setting bar_fill;
extern conky::simple_config_setting bar_unfill;
+extern conky::simple_config_setting github_token;
int open_acpi_temperature(const char *name);
double get_acpi_temperature(int fd);
@@ -170,6 +171,7 @@ void print_updates(struct text_object *, char *, unsigned int);
int updatenr_iftest(struct text_object *);
#ifdef BUILD_CURL
+void print_github(struct text_object *, char *, unsigned int);
void print_stock(struct text_object *, char *, unsigned int);
void free_stock(struct text_object *);
#endif /* BUILD_CURL */
diff --git a/src/core.cc b/src/core.cc
index 4aff963d..401a714b 100644
--- a/src/core.cc
+++ b/src/core.cc
@@ -1697,6 +1697,7 @@ struct text_object *construct_text_object(char *s, const char *arg, long line,
curl_parse_arg(obj, arg);
obj->callbacks.print = &curl_print;
obj->callbacks.free = &curl_obj_free;
+ END OBJ(github_notifications, 0) obj->callbacks.print = &print_github;
#endif /* BUILD_CURL */
#ifdef BUILD_RSS
END OBJ_ARG(rss, 0,