static void _presence_join_room(char *room, char *nick, char * passwd) { Jid *jid = jid_create_from_bare_and_resource(room, nick); log_debug("Sending room join presence to: %s", jid->fulljid); xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_conn_t *conn = connection_get_conn(); resource_presence_t presence_type = accounts_get_last_presence(jabber_get_account_name()); const char *show = stanza_get_presence_string_from_type(presence_type); char *status = jabber_get_presence_message(); int pri = accounts_get_priority_for_presence_type(jabber_get_account_name(), presence_type); xmpp_stanza_t *presence = stanza_create_room_join_presence(ctx, jid->fulljid, passwd); stanza_attach_show(ctx, presence, show); stanza_attach_status(ctx, presence, status); stanza_attach_priority(ctx, presence, pri); stanza_attach_caps(ctx, presence); xmpp_send(conn, presence); xmpp_stanza_release(presence); jid_destroy(jid); }
jabber_conn_status_t jabber_connect_with_account(const ProfAccount * const account) { assert(account != NULL); log_info("Connecting using account: %s", account->name); // save account name and password for reconnect if (saved_account.name) { free(saved_account.name); } saved_account.name = strdup(account->name); if (saved_account.passwd) { free(saved_account.passwd); } saved_account.passwd = strdup(account->password); // connect with fulljid Jid *jidp = jid_create_from_bare_and_resource(account->jid, account->resource); jabber_conn_status_t result = _jabber_connect(jidp->fulljid, account->password, account->server, account->port); jid_destroy(jidp); return result; }
static char* _session_jid(const char *const barejid) { ChatSession *session = chat_session_get(barejid); char *jid = NULL; if (session) { Jid *jidp = jid_create_from_bare_and_resource(session->barejid, session->resource); jid = strdup(jidp->fulljid); jid_destroy(jidp); } else { jid = strdup(barejid); } return jid; }
jabber_conn_status_t jabber_connect_with_details(const char *const jid, const char *const passwd, const char *const altdomain, const int port, const char *const tls_policy) { assert(jid != NULL); assert(passwd != NULL); // save details for reconnect, remember name for account creating on success saved_details.name = strdup(jid); saved_details.passwd = strdup(passwd); if (altdomain) { saved_details.altdomain = strdup(altdomain); } else { saved_details.altdomain = NULL; } if (port != 0) { saved_details.port = port; } else { saved_details.port = 0; } if (tls_policy) { saved_details.tls_policy = strdup(tls_policy); } else { saved_details.tls_policy = NULL; } // use 'profanity' when no resourcepart in provided jid Jid *jidp = jid_create(jid); if (jidp->resourcepart == NULL) { jid_destroy(jidp); jidp = jid_create_from_bare_and_resource(jid, "profanity"); saved_details.jid = strdup(jidp->fulljid); } else { saved_details.jid = strdup(jid); } jid_destroy(jidp); // connect with fulljid log_info("Connecting without account, JID: %s", saved_details.jid); return _jabber_connect( saved_details.jid, passwd, saved_details.altdomain, saved_details.port, saved_details.tls_policy); }
void handle_contact_offline(char *contact, char *resource, char *status) { gboolean updated = roster_contact_offline(contact, resource, status); if (resource != NULL && updated && prefs_get_boolean(PREF_STATUSES)) { Jid *jid = jid_create_from_bare_and_resource(contact, resource); PContact result = roster_get_contact(contact); if (p_contact_subscription(result) != NULL) { if (strcmp(p_contact_subscription(result), "none") != 0) { ui_contact_offline(jid->fulljid, "offline", status); ui_current_page_off(); } } jid_destroy(jid); } }
void ui_contact_offline(char *barejid, char *resource, char *status) { char *show_console = prefs_get_string(PREF_STATUSES_CONSOLE); char *show_chat_win = prefs_get_string(PREF_STATUSES_CHAT); Jid *jid = jid_create_from_bare_and_resource(barejid, resource); PContact contact = roster_get_contact(barejid); if (p_contact_subscription(contact)) { if (strcmp(p_contact_subscription(contact), "none") != 0) { // show in console if "all" if (g_strcmp0(show_console, "all") == 0) { cons_show_contact_offline(contact, resource, status); // show in console of "online" } else if (g_strcmp0(show_console, "online") == 0) { cons_show_contact_offline(contact, resource, status); } // show in chat win if "all" if (g_strcmp0(show_chat_win, "all") == 0) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { chatwin_contact_offline(chatwin, resource, status); } // show in chat win if "online" and presence online } else if (g_strcmp0(show_chat_win, "online") == 0) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { chatwin_contact_offline(chatwin, resource, status); } } } } ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin && chatwin->resource_override && (g_strcmp0(resource, chatwin->resource_override) == 0)) { FREE_SET_NULL(chatwin->resource_override); } prefs_free_string(show_console); prefs_free_string(show_chat_win); jid_destroy(jid); }
void sv_ev_room_occupent_banned(const char *const room, const char *const nick, const char *const actor, const char *const reason) { muc_roster_remove(room, nick); ProfMucWin *mucwin = wins_get_muc(room); if (mucwin) { mucwin_occupant_banned(mucwin, nick, actor, reason); } Jid *jidp = jid_create_from_bare_and_resource(room, nick); ProfPrivateWin *privwin = wins_get_private(jidp->fulljid); jid_destroy(jidp); if (privwin != NULL) { privwin_occupant_banned(privwin, actor, reason); } occupantswin_occupants(room); rosterwin_roster(); }
gboolean roster_update_presence(const char *const barejid, Resource *resource, GDateTime *last_activity) { assert(barejid != NULL); assert(resource != NULL); PContact contact = roster_get_contact(barejid); if (contact == NULL) { return FALSE; } if (!_datetimes_equal(p_contact_last_activity(contact), last_activity)) { p_contact_set_last_activity(contact, last_activity); } p_contact_set_presence(contact, resource); Jid *jid = jid_create_from_bare_and_resource(barejid, resource->name); autocomplete_add(fulljid_ac, jid->fulljid); jid_destroy(jid); return TRUE; }
void ui_contact_online(const char * const barejid, const char * const resource, const char * const show, const char * const status, GDateTime *last_activity) { Jid *jid = jid_create_from_bare_and_resource(barejid, resource); PContact contact = roster_get_contact(barejid); GString *display_str = g_string_new(""); // use nickname if exists if (p_contact_name(contact) != NULL) { g_string_append(display_str, p_contact_name(contact)); } else { g_string_append(display_str, barejid); } // add resource if not default provided by profanity if (strcmp(jid->resourcepart, "__prof_default") != 0) { g_string_append(display_str, " ("); g_string_append(display_str, jid->resourcepart); g_string_append(display_str, ")"); } ProfWin *console = wins_get_console(); _show_status_string(console, display_str->str, show, status, last_activity, "++", "online"); ProfWin *window = wins_get_by_recipient(barejid); if (window != NULL) { _show_status_string(window, display_str->str, show, status, last_activity, "++", "online"); } jid_destroy(jid); g_string_free(display_str, TRUE); if (wins_is_current(console)) { wins_refresh_current(); } else if ((window != NULL) && (wins_is_current(window))) { wins_refresh_current(); } }
gboolean roster_contact_offline(const char *const barejid, const char *const resource, const char *const status) { PContact contact = roster_get_contact(barejid); if (contact == NULL) { return FALSE; } if (resource == NULL) { return TRUE; } else { gboolean result = p_contact_remove_resource(contact, resource); if (result == TRUE) { Jid *jid = jid_create_from_bare_and_resource(barejid, resource); autocomplete_remove(fulljid_ac, jid->fulljid); jid_destroy(jid); } return result; } }
void handle_contact_offline(char *barejid, char *resource, char *status) { gboolean updated = roster_contact_offline(barejid, resource, status); if (resource != NULL && updated) { char *show_console = prefs_get_string(PREF_STATUSES_CONSOLE); char *show_chat_win = prefs_get_string(PREF_STATUSES_CHAT); Jid *jid = jid_create_from_bare_and_resource(barejid, resource); PContact contact = roster_get_contact(barejid); if (p_contact_subscription(contact) != NULL) { if (strcmp(p_contact_subscription(contact), "none") != 0) { // show in console if "all" if (g_strcmp0(show_console, "all") == 0) { cons_show_contact_offline(contact, resource, status); // show in console of "online" } else if (g_strcmp0(show_console, "online") == 0) { cons_show_contact_offline(contact, resource, status); } // show in chat win if "all" if (g_strcmp0(show_chat_win, "all") == 0) { ui_chat_win_contact_offline(contact, resource, status); // show in char win if "online" and presence online } else if (g_strcmp0(show_chat_win, "online") == 0) { ui_chat_win_contact_offline(contact, resource, status); } } } prefs_free_string(show_console); prefs_free_string(show_chat_win); jid_destroy(jid); } ui_roster(); }
void sv_ev_room_occupant_offline(const char *const room, const char *const nick, const char *const show, const char *const status) { muc_roster_remove(room, nick); char *muc_status_pref = prefs_get_string(PREF_STATUSES_MUC); ProfMucWin *mucwin = wins_get_muc(room); if (mucwin && (g_strcmp0(muc_status_pref, "none") != 0)) { mucwin_occupant_offline(mucwin, nick); } prefs_free_string(muc_status_pref); Jid *jidp = jid_create_from_bare_and_resource(room, nick); ProfPrivateWin *privwin = wins_get_private(jidp->fulljid); jid_destroy(jidp); if (privwin != NULL) { privwin_occupant_offline(privwin); } occupantswin_occupants(room); rosterwin_roster(); }
void sv_ev_muc_occupant_online(const char *const room, const char *const nick, const char *const jid, const char *const role, const char *const affiliation, const char *const actor, const char *const reason, const char *const show, const char *const status) { Occupant *occupant = muc_roster_item(room, nick); const char *old_role = NULL; const char *old_affiliation = NULL; if (occupant) { old_role = muc_occupant_role_str(occupant); old_affiliation = muc_occupant_affiliation_str(occupant); } gboolean updated = muc_roster_add(room, nick, jid, role, affiliation, show, status); // not yet finished joining room if (!muc_roster_complete(room)) { return; } // handle nickname change char *old_nick = muc_roster_nick_change_complete(room, nick); if (old_nick) { ProfMucWin *mucwin = wins_get_muc(room); if (mucwin) { mucwin_occupant_nick_change(mucwin, old_nick, nick); } wins_private_nick_change(mucwin->roomjid, old_nick, nick); free(old_nick); occupantswin_occupants(room); rosterwin_roster(); return; } // joined room if (!occupant) { char *muc_status_pref = prefs_get_string(PREF_STATUSES_MUC); ProfMucWin *mucwin = wins_get_muc(room); if (mucwin && g_strcmp0(muc_status_pref, "none") != 0) { mucwin_occupant_online(mucwin, nick, role, affiliation, show, status); } prefs_free_string(muc_status_pref); Jid *jidp = jid_create_from_bare_and_resource(mucwin->roomjid, nick); ProfPrivateWin *privwin = wins_get_private(jidp->fulljid); jid_destroy(jidp); if (privwin) { privwin_occupant_online(privwin); } occupantswin_occupants(room); rosterwin_roster(); return; } // presence updated if (updated) { char *muc_status_pref = prefs_get_string(PREF_STATUSES_MUC); ProfMucWin *mucwin = wins_get_muc(room); if (mucwin && (g_strcmp0(muc_status_pref, "all") == 0)) { mucwin_occupant_presence(mucwin, nick, show, status); } prefs_free_string(muc_status_pref); occupantswin_occupants(room); // presence unchanged, check for role/affiliation change } else { ProfMucWin *mucwin = wins_get_muc(room); if (mucwin && prefs_get_boolean(PREF_MUC_PRIVILEGES)) { // both changed if ((g_strcmp0(role, old_role) != 0) && (g_strcmp0(affiliation, old_affiliation) != 0)) { mucwin_occupant_role_and_affiliation_change(mucwin, nick, role, affiliation, actor, reason); // role changed } else if (g_strcmp0(role, old_role) != 0) { mucwin_occupant_role_change(mucwin, nick, role, actor, reason); // affiliation changed } else if (g_strcmp0(affiliation, old_affiliation) != 0) { mucwin_occupant_affiliation_change(mucwin, nick, affiliation, actor, reason); } } occupantswin_occupants(room); } rosterwin_roster(); }
void win_show_occupant_info(ProfWin *window, const char *const room, Occupant *occupant) { const char *presence_str = string_from_resource_presence(occupant->presence); const char *occupant_affiliation = muc_occupant_affiliation_str(occupant); const char *occupant_role = muc_occupant_role_str(occupant); theme_item_t presence_colour = theme_main_presence_attrs(presence_str); win_print(window, '!', 0, NULL, NO_EOL, presence_colour, "", occupant->nick); win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", presence_str); if (occupant->status) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", occupant->status); } win_newline(window); if (occupant->jid) { win_vprint(window, '!', 0, NULL, 0, 0, "", " Jid: %s", occupant->jid); } win_vprint(window, '!', 0, NULL, 0, 0, "", " Affiliation: %s", occupant_affiliation); win_vprint(window, '!', 0, NULL, 0, 0, "", " Role: %s", occupant_role); Jid *jidp = jid_create_from_bare_and_resource(room, occupant->nick); EntityCapabilities *caps = caps_lookup(jidp->fulljid); jid_destroy(jidp); if (caps) { // show identity if (caps->identity) { DiscoIdentity *identity = caps->identity; win_print(window, '!', 0, NULL, NO_EOL, 0, "", " Identity: "); if (identity->name) { win_print(window, '!', 0, NULL, NO_DATE | NO_EOL, 0, "", identity->name); if (identity->category || identity->type) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", " "); } } if (identity->type) { win_print(window, '!', 0, NULL, NO_DATE | NO_EOL, 0, "", identity->type); if (identity->category) { win_print(window, '!', 0, NULL, NO_DATE | NO_EOL, 0, "", " "); } } if (identity->category) { win_print(window, '!', 0, NULL, NO_DATE | NO_EOL, 0, "", identity->category); } win_newline(window); } if (caps->software_version) { SoftwareVersion *software_version = caps->software_version; if (software_version->software) { win_vprint(window, '!', 0, NULL, NO_EOL, 0, "", " Software: %s", software_version->software); } if (software_version->software_version) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, 0, "", ", %s", software_version->software_version); } if (software_version->software || software_version->software_version) { win_newline(window); } if (software_version->os) { win_vprint(window, '!', 0, NULL, NO_EOL, 0, "", " OS: %s", software_version->os); } if (software_version->os_version) { win_vprint(window, '!', 0, NULL, NO_DATE | NO_EOL, 0, "", ", %s", software_version->os_version); } if (software_version->os || software_version->os_version) { win_newline(window); } } caps_destroy(caps); } win_print(window, '-', 0, NULL, 0, 0, "", ""); }
static int _bookmark_handle_result(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_ctx_t *ctx = connection_get_ctx(); char *id = (char *)userdata; xmpp_stanza_t *ptr; xmpp_stanza_t *nick; char *name; char *jid; char *autojoin; gboolean autojoin_val; Jid *my_jid; Bookmark *item; xmpp_timed_handler_delete(conn, _bookmark_handle_delete); g_free(id); name = xmpp_stanza_get_name(stanza); if (!name || strcmp(name, STANZA_NAME_IQ) != 0) { return 0; } ptr = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); if (!ptr) { return 0; } ptr = xmpp_stanza_get_child_by_name(ptr, STANZA_NAME_STORAGE); if (!ptr) { return 0; } if (bookmark_ac == NULL) { bookmark_ac = autocomplete_new(); } my_jid = jid_create(jabber_get_fulljid()); ptr = xmpp_stanza_get_children(ptr); while (ptr) { name = xmpp_stanza_get_name(ptr); if (!name || strcmp(name, STANZA_NAME_CONFERENCE) != 0) { ptr = xmpp_stanza_get_next(ptr); continue; } jid = xmpp_stanza_get_attribute(ptr, STANZA_ATTR_JID); if (!jid) { ptr = xmpp_stanza_get_next(ptr); continue; } log_debug("Handle bookmark for %s", jid); name = NULL; nick = xmpp_stanza_get_child_by_name(ptr, "nick"); if (nick) { char *tmp; tmp = xmpp_stanza_get_text(nick); if (tmp) { name = strdup(tmp); xmpp_free(ctx, tmp); } } autojoin = xmpp_stanza_get_attribute(ptr, "autojoin"); if (autojoin && (strcmp(autojoin, "1") == 0 || strcmp(autojoin, "true") == 0)) { autojoin_val = TRUE; } else { autojoin_val = FALSE; } autocomplete_add(bookmark_ac, jid); item = malloc(sizeof(*item)); item->jid = strdup(jid); item->nick = name; item->autojoin = autojoin_val; bookmark_list = g_list_append(bookmark_list, item); /* TODO: preference whether autojoin */ if (autojoin_val) { if (autojoin_count < BOOKMARK_AUTOJOIN_MAX) { Jid *room_jid; ++autojoin_count; if (name == NULL) { name = my_jid->localpart; } log_debug("Autojoin %s with nick=%s", jid, name); room_jid = jid_create_from_bare_and_resource(jid, name); if (!muc_room_is_active(room_jid)) { presence_join_room(room_jid); /* TODO: this should be removed after fixing #195 */ ui_room_join(room_jid); } jid_destroy(room_jid); } else { log_debug("Rejected autojoin %s (maximum has been reached)", jid); } } ptr = xmpp_stanza_get_next(ptr); } jid_destroy(my_jid); return 0; }
static int _bookmark_handle_result(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza, void *const userdata) { xmpp_ctx_t *ctx = connection_get_ctx(); char *id = (char *)userdata; xmpp_stanza_t *ptr; xmpp_stanza_t *nick; xmpp_stanza_t *password_st; char *name; char *jid; char *autojoin; char *password; gboolean autojoin_val; Jid *my_jid; Bookmark *item; xmpp_timed_handler_delete(conn, _bookmark_handle_delete); g_free(id); name = xmpp_stanza_get_name(stanza); if (!name || strcmp(name, STANZA_NAME_IQ) != 0) { return 0; } ptr = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); if (!ptr) { return 0; } ptr = xmpp_stanza_get_child_by_name(ptr, STANZA_NAME_STORAGE); if (!ptr) { return 0; } if (bookmark_ac == NULL) { bookmark_ac = autocomplete_new(); } my_jid = jid_create(jabber_get_fulljid()); ptr = xmpp_stanza_get_children(ptr); while (ptr) { name = xmpp_stanza_get_name(ptr); if (!name || strcmp(name, STANZA_NAME_CONFERENCE) != 0) { ptr = xmpp_stanza_get_next(ptr); continue; } jid = xmpp_stanza_get_attribute(ptr, STANZA_ATTR_JID); if (!jid) { ptr = xmpp_stanza_get_next(ptr); continue; } log_debug("Handle bookmark for %s", jid); name = NULL; nick = xmpp_stanza_get_child_by_name(ptr, "nick"); if (nick) { char *tmp; tmp = xmpp_stanza_get_text(nick); if (tmp) { name = strdup(tmp); xmpp_free(ctx, tmp); } } password = NULL; password_st = xmpp_stanza_get_child_by_name(ptr, "password"); if (password_st) { char *tmp; tmp = xmpp_stanza_get_text(password_st); if (tmp) { password = strdup(tmp); xmpp_free(ctx, tmp); } } autojoin = xmpp_stanza_get_attribute(ptr, "autojoin"); if (autojoin && (strcmp(autojoin, "1") == 0 || strcmp(autojoin, "true") == 0)) { autojoin_val = TRUE; } else { autojoin_val = FALSE; } autocomplete_add(bookmark_ac, jid); item = malloc(sizeof(*item)); item->jid = strdup(jid); item->nick = name; item->password = password; item->autojoin = autojoin_val; bookmark_list = g_list_append(bookmark_list, item); if (autojoin_val) { Jid *room_jid; char *account_name = jabber_get_account_name(); ProfAccount *account = accounts_get_account(account_name); if (name == NULL) { name = account->muc_nick; } log_debug("Autojoin %s with nick=%s", jid, name); room_jid = jid_create_from_bare_and_resource(jid, name); if (!muc_active(room_jid->barejid)) { presence_join_room(jid, name, password); muc_join(jid, name, password, TRUE); } jid_destroy(room_jid); account_free(account); } ptr = xmpp_stanza_get_next(ptr); } jid_destroy(my_jid); return 0; }
void win_show_info(ProfWin *window, PContact contact) { const char *barejid = p_contact_barejid(contact); const char *name = p_contact_name(contact); const char *presence = p_contact_presence(contact); const char *sub = p_contact_subscription(contact); GDateTime *last_activity = p_contact_last_activity(contact); theme_item_t presence_colour = theme_main_presence_attrs(presence); win_print(window, '-', 0, NULL, 0, 0, "", ""); win_print(window, '-', 0, NULL, NO_EOL, presence_colour, "", barejid); if (name) { win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", " (%s)", name); } win_print(window, '-', 0, NULL, NO_DATE, 0, "", ":"); if (sub) { win_vprint(window, '-', 0, NULL, 0, 0, "", "Subscription: %s", sub); } if (last_activity) { GDateTime *now = g_date_time_new_now_local(); GTimeSpan span = g_date_time_difference(now, last_activity); int hours = span / G_TIME_SPAN_HOUR; span = span - hours * G_TIME_SPAN_HOUR; int minutes = span / G_TIME_SPAN_MINUTE; span = span - minutes * G_TIME_SPAN_MINUTE; int seconds = span / G_TIME_SPAN_SECOND; if (hours > 0) { win_vprint(window, '-', 0, NULL, 0, 0, "", "Last activity: %dh%dm%ds", hours, minutes, seconds); } else { win_vprint(window, '-', 0, NULL, 0, 0, "", "Last activity: %dm%ds", minutes, seconds); } g_date_time_unref(now); } GList *resources = p_contact_get_available_resources(contact); GList *ordered_resources = NULL; if (resources) { win_print(window, '-', 0, NULL, 0, 0, "", "Resources:"); // sort in order of availability GList *curr = resources; while (curr) { Resource *resource = curr->data; ordered_resources = g_list_insert_sorted(ordered_resources, resource, (GCompareFunc)resource_compare_availability); curr = g_list_next(curr); } } g_list_free(resources); GList *curr = ordered_resources; while (curr) { Resource *resource = curr->data; const char *resource_presence = string_from_resource_presence(resource->presence); theme_item_t presence_colour = theme_main_presence_attrs(resource_presence); win_vprint(window, '-', 0, NULL, NO_EOL, presence_colour, "", " %s (%d), %s", resource->name, resource->priority, resource_presence); if (resource->status) { win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", resource->status); } win_newline(window); Jid *jidp = jid_create_from_bare_and_resource(barejid, resource->name); EntityCapabilities *caps = caps_lookup(jidp->fulljid); jid_destroy(jidp); if (caps) { // show identity if (caps->identity) { DiscoIdentity *identity = caps->identity; win_print(window, '-', 0, NULL, NO_EOL, 0, "", " Identity: "); if (identity->name) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", identity->name); if (identity->category || identity->type) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", " "); } } if (identity->type) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", identity->type); if (identity->category) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", " "); } } if (identity->category) { win_print(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", identity->category); } win_newline(window); } if (caps->software_version) { SoftwareVersion *software_version = caps->software_version; if (software_version->software) { win_vprint(window, '-', 0, NULL, NO_EOL, 0, "", " Software: %s", software_version->software); } if (software_version->software_version) { win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", ", %s", software_version->software_version); } if (software_version->software || software_version->software_version) { win_newline(window); } if (software_version->os) { win_vprint(window, '-', 0, NULL, NO_EOL, 0, "", " OS: %s", software_version->os); } if (software_version->os_version) { win_vprint(window, '-', 0, NULL, NO_DATE | NO_EOL, 0, "", ", %s", software_version->os_version); } if (software_version->os || software_version->os_version) { win_newline(window); } } caps_destroy(caps); } curr = g_list_next(curr); } g_list_free(ordered_resources); }