static LibBalsaABErr libbalsa_address_book_ldap_modify_address(LibBalsaAddressBook *ab, LibBalsaAddress *address, LibBalsaAddress *newval) { gchar *dn; LDAPMod *mods[5]; LDAPMod modarr[4]; int rc, cnt; char *cn[] = {NULL, NULL}; char *gn[] = {NULL, NULL}; char *org[] = {NULL, NULL}; char *sn[] = {NULL, NULL}; LibBalsaAddressBookLdap *ldap_ab = LIBBALSA_ADDRESS_BOOK_LDAP(ab); g_return_val_if_fail(address, LBABERR_CANNOT_WRITE); g_return_val_if_fail(address->address_list, LBABERR_CANNOT_WRITE); g_return_val_if_fail(newval->address_list, LBABERR_CANNOT_WRITE); if(!STREQ(address->address_list->data,newval->address_list->data)) { /* email address has changed, we have to remove old entry and * add a new one. */ if( (rc=libbalsa_address_book_ldap_add_address(ab, newval)) != LBABERR_OK) return rc; return libbalsa_address_book_ldap_remove_address(ab, address); } /* the email address has not changed, continue with changing other * attributes. */ if (ldap_ab->directory == NULL) { if( (rc=libbalsa_address_book_ldap_open_connection(ldap_ab)) != LDAP_SUCCESS) return LBABERR_CANNOT_CONNECT; } dn = g_strdup_printf("mail=%s,%s", (char*)address->address_list->data, ldap_ab->priv_book_dn); cnt = 0; if(!STREQ(address->full_name,newval->full_name)) { if(newval->full_name) SETMOD(mods[cnt],modarr[cnt],LDAP_MOD_REPLACE,"cn",cn, newval->full_name); else SETMOD(mods[cnt],modarr[cnt],LDAP_MOD_DELETE,"cn",cn, address->full_name); cnt++; } if(!STREQ(address->first_name,newval->first_name)) { if(newval->first_name) SETMOD(mods[cnt],modarr[cnt],LDAP_MOD_REPLACE,"givenName",gn, newval->first_name); else SETMOD(mods[cnt],modarr[cnt],LDAP_MOD_DELETE,"givenName",gn, address->first_name); cnt++; } if(!STREQ(address->last_name,newval->last_name)) { if(newval->last_name) SETMOD(mods[cnt],modarr[cnt],LDAP_MOD_REPLACE,"sn",sn, newval->last_name); else SETMOD(mods[cnt],modarr[cnt],LDAP_MOD_DELETE,"sn",sn, address->last_name); cnt++; } if(!STREQ(address->organization,newval->organization)) { if(newval->organization) SETMOD(mods[cnt],modarr[cnt],LDAP_MOD_REPLACE,"o", org, newval->organization); else SETMOD(mods[cnt],modarr[cnt],LDAP_MOD_DELETE,"o", org, address->organization); cnt++; } mods[cnt] = NULL; if(cnt == 0) { /* nothing to modify */ g_free(dn); return LBABERR_OK; } cnt = 0; do { rc = ldap_modify_ext_s(ldap_ab->directory, dn, mods, NULL, NULL); switch(rc) { case LDAP_SUCCESS: return LBABERR_OK; case LDAP_SERVER_DOWN: libbalsa_address_book_ldap_close_connection(ldap_ab); if( (rc=libbalsa_address_book_ldap_open_connection(ldap_ab)) != LDAP_SUCCESS) { g_free(dn); return LBABERR_CANNOT_CONNECT; } /* fall through */ default: fprintf(stderr, "ldap_modify for dn=“%s” failed[0x%x]: %s\n", dn, rc, ldap_err2string(rc)); } } while(cnt++<1); g_free(dn); libbalsa_address_book_set_status(ab, g_strdup(ldap_err2string(rc))); return LBABERR_CANNOT_WRITE; }
static LibBalsaABErr libbalsa_address_book_ldap_add_address(LibBalsaAddressBook *ab, LibBalsaAddress *address) { static char *object_class_values[] = { "person", "organizationalPerson", "inetOrgPerson", NULL }; gchar *dn; LDAPMod *mods[7]; LDAPMod modarr[6]; int cnt; char *cn[] = {NULL, NULL}; char *gn[] = {NULL, NULL}; char *org[] = {NULL, NULL}; char *sn[] = {NULL, NULL}; char *mail[] = {NULL, NULL}; LibBalsaAddressBookLdap *ldap_ab = LIBBALSA_ADDRESS_BOOK_LDAP(ab); g_return_val_if_fail(address, LBABERR_CANNOT_WRITE); g_return_val_if_fail(address->address_list, LBABERR_CANNOT_WRITE); if (ldap_ab->directory == NULL) { if(libbalsa_address_book_ldap_open_connection(ldap_ab) != LDAP_SUCCESS) return LBABERR_CANNOT_CONNECT; } if(ldap_ab->priv_book_dn == NULL) { libbalsa_address_book_set_status (ab, _("Undefined location of user address book")); return LBABERR_CANNOT_WRITE; } dn = g_strdup_printf("mail=%s,%s", (char*)address->address_list->data, ldap_ab->priv_book_dn); mods[0] = &modarr[0]; modarr[0].mod_op = LDAP_MOD_ADD; modarr[0].mod_type = "objectClass"; modarr[0].mod_values = object_class_values; cnt = 1; if(address->full_name) { SETMOD(mods[cnt],modarr[cnt],LDAP_MOD_ADD,"cn",cn,address->full_name); cnt++; } if(address->first_name) { SETMOD(mods[cnt],modarr[cnt],LDAP_MOD_ADD,"givenName",gn, address->first_name); cnt++; } if(address->last_name) { SETMOD(mods[cnt],modarr[cnt],LDAP_MOD_ADD,"sn",sn,address->last_name); cnt++; } if(address->organization) { SETMOD(mods[cnt],modarr[cnt],LDAP_MOD_ADD,"o",org, address->organization); cnt++; } SETMOD(mods[cnt],modarr[cnt],LDAP_MOD_ADD,"mail",mail, (char*)address->address_list->data); cnt++; mods[cnt] = NULL; cnt = 0; do { int rc = ldap_add_ext_s(ldap_ab->directory, dn, mods, NULL, NULL); switch(rc) { case LDAP_SUCCESS: g_free(dn); return LBABERR_OK; case LDAP_ALREADY_EXISTS: g_free(dn); libbalsa_address_book_set_status(ab, g_strdup(ldap_err2string(rc))); return LBABERR_DUPLICATE; case LDAP_SERVER_DOWN: libbalsa_address_book_ldap_close_connection(ldap_ab); if( (rc=libbalsa_address_book_ldap_open_connection(ldap_ab)) != LDAP_SUCCESS) { g_free(dn); return LBABERR_CANNOT_CONNECT; } /* fall through */ default: fprintf(stderr, "ldap_add for dn=“%s” failed[0x%x]: %s\n", dn, rc, ldap_err2string(rc)); } } while(cnt++<1); g_free(dn); libbalsa_address_book_set_status(ab, NULL); return LBABERR_CANNOT_WRITE; }
/** * Add new contact to LDAP * * \param server AddressBook resource * \param contact GHashTable with object to add */ void ldapsvr_add_contact(LdapServer *server, GHashTable *contact) { gchar *email = NULL, *param = NULL; LDAP *ld = NULL; LDAPMod *mods[MODSIZE]; LDAPMod modarr[7]; gint cnt = 0; char *cn[] = {NULL, NULL}; char *displayName[] = {NULL, NULL}; char *givenName[] = {NULL, NULL}; char **mail = NULL; char *sn[] = {NULL, NULL}; char *org[] = {NULL, NULL}; char *obj[] = {/*"top",*/ "person", "organizationalPerson", "inetOrgPerson", NULL}; int rc=0; GList *node; AttrKeyValue *ou, *commonName; ItemPerson *person; gchar *base_dn; GList *mailList; cm_return_if_fail(server != NULL || contact != NULL); node = g_hash_table_lookup(contact , "mail"); if (node) { EmailKeyValue *newEmail = node->data; email = g_strdup(newEmail->mail); } if (email == NULL) { server->retVal = LDAPRC_NODN; clean_up(ld, server, contact); return; } base_dn = g_strdup_printf("mail=%s,%s", email, server->control->baseDN?server->control->baseDN:"null"); g_free(email); person = ldapsvr_get_contact(server, g_hash_table_lookup(contact , "uid")); person->externalID = g_strdup(base_dn); debug_print("dn: %s\n", base_dn); ld = ldapsvr_connect(server->control); if (ld == NULL) { clean_up(ld, server, contact); debug_print("no ldap found\n"); return; } SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "objectClass", obj); cnt++; ou = get_ou(base_dn); if (ou != NULL) { SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, g_strdup(ou->key), org, g_strdup(ou->value)); cnt++; attrkeyvalue_free(ou); } commonName = get_cn(base_dn); if (commonName == NULL) { param = g_hash_table_lookup(contact , "cn"); if (param) { SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "cn", cn, param); } else { clean_up(ld, server, contact); debug_print("no CN found\n"); return; } } else { SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, g_strdup(commonName->key), cn, g_strdup(commonName->value)); cnt++; param = g_hash_table_lookup(contact , "cn"); SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "displayName", displayName, param); g_hash_table_insert(contact, "displayName", param); attrkeyvalue_free(commonName); } cnt++; param = g_hash_table_lookup(contact , "givenName"); if (param) { SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "givenName", givenName, param); cnt++; } mailList = g_hash_table_lookup(contact , "mail"); if (mailList) { char **tmp; tmp = g_malloc(sizeof(*tmp) * (g_list_length(mailList)+1)); mail = tmp; while (mailList) { EmailKeyValue *item = mailList->data; *tmp++ = g_strdup((gchar *) item->mail); mailList = g_list_next(mailList); } *tmp = NULL; SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "mail", mail); cnt++; } param = g_hash_table_lookup(contact, "sn"); if (param == NULL) param = g_strdup(N_("Some SN")); SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "sn", sn, param); cnt++; mods[cnt] = NULL; if (debug_get_mode()) { ldapsvr_print_ldapmod(mods); } server->retVal = LDAPRC_SUCCESS; rc = ldap_add_ext_s(ld, base_dn, mods, NULL, NULL); if (rc) { switch (rc) { case LDAP_ALREADY_EXISTS: server->retVal = LDAPRC_ALREADY_EXIST; break; default: g_printerr("ldap_modify for dn=%s\" failed[0x%x]: %s\n", base_dn, rc, ldaputil_get_error(ld)); if (rc == 0x8) server->retVal = LDAPRC_STRONG_AUTH; else server->retVal = LDAPRC_NAMING_VIOLATION; } } ldapsvr_handle_other_attributes(ld, server, base_dn, contact); g_free(base_dn); clean_up(ld, server, contact); }
/** * Deside which other attributes needs updating * * \param ld LDAP resource * \param server AddressBook resource * \param dn dn for the entry * \param contact GHashTable with information for the current contact */ void ldapsvr_handle_other_attributes(LDAP *ld, LdapServer *server, char *dn, GHashTable *contact) { GList *node; gboolean CHECKED_ATTRIBUTE[ATTRIBUTE_SIZE + 1]; LDAPMod *mods[ATTRIBUTE_SIZE + 1]; LDAPMod modarr[ATTRIBUTE_SIZE]; gint cnt = 0; char *attr[ATTRIBUTE_SIZE + 1][2]; int mod_op, rc, i; cm_return_if_fail(server != NULL || dn != NULL || contact != NULL); for (i = 0; i <= ATTRIBUTE_SIZE; i++) { CHECKED_ATTRIBUTE[i] = FALSE; attr[i][0] = attr[i][1] = NULL; } node = g_hash_table_lookup(contact , "attribute"); while (node) { AttrKeyValue *item = node->data; if (item) { int index = get_attribute_index(item->key); if (index >= 0) { debug_print("Found other attribute: %s = %s\n", item->key?item->key:"null", item->value?item->value:"null"); mod_op = ldapsvr_deside_operation(ld, server, dn, item->key, item->value); /* Only consider attributes which we no how to handle. * Set to TRUE in CHECKED_ATTRIBUTE array to indicate no further action */ if (mod_op < 0) { CHECKED_ATTRIBUTE[index] = TRUE; node = g_list_next(node); continue; } if (mod_op == LDAP_MOD_DELETE) { /* Setting param to NULL instructs OpenLDAP to remove any * value stored for this attribute and remove the attribute * completely. Should multiple instances of an attribute be * allowed in the future param is required to have the value * store for the attribute which is going to be deleted */ item->value = NULL; } if (mod_op == LDAP_MOD_REPLACE && strcmp(item->value, "") == 0) { /* Having an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we treate this as a request for deleting * the attribute. */ mod_op = LDAP_MOD_DELETE; item->value = NULL; } if (mod_op == LDAP_MOD_ADD && strcmp(item->value, "") == 0) { /* Adding an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we silently refuse to add this entry */ } else { SETMOD(mods[cnt], modarr[cnt], mod_op, g_strdup(item->key), attr[cnt], g_strdup(item->value)); cnt++; CHECKED_ATTRIBUTE[index] = TRUE; } } } node = g_list_next(node); } char **attribs = ldapctl_full_attribute_array(server->control); for (i = 0; i < ATTRIBUTE_SIZE; i++) { /* Attributes which holds no information are to be removed */ if (CHECKED_ATTRIBUTE[i] == FALSE) { /* Only consider those attributes which is currently part of the search criteria. * If attributes are not part of the search criteria they would seem to hold * no information since their values will not be populated in the GUI */ if (!strcmp(ATTRIBUTE[i], "jpegPhoto")) { debug_print("not updating jpegPhoto\n"); continue; } if (ldapsvr_check_search_attributes(attribs, (char *) ATTRIBUTE[i])) { mod_op = ldapsvr_deside_operation(ld, server, dn, (char *) ATTRIBUTE[i], ""); if (mod_op == LDAP_MOD_DELETE) { SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_DELETE, g_strdup((char *) ATTRIBUTE[i]), attr[cnt], NULL); cnt++; } } } } ldapctl_free_attribute_array(attribs); mods[cnt] = NULL; if (debug_get_mode()) ldapsvr_print_ldapmod(mods); server->retVal = LDAPRC_SUCCESS; rc = ldap_modify_ext_s(ld, dn, mods, NULL, NULL); if (rc) { switch (rc) { case LDAP_ALREADY_EXISTS: server->retVal = LDAPRC_ALREADY_EXIST; break; default: g_printerr("ldap_modify for dn=%s\" failed[0x%x]: %s\n", dn, rc, ldaputil_get_error(ld)); if (rc == 0x8) server->retVal = LDAPRC_STRONG_AUTH; else server->retVal = LDAPRC_NAMING_VIOLATION; } } else { char **attribs = ldapctl_full_attribute_array(server->control); for (i = 0; i < ATTRIBUTE_SIZE; i++) { if (!strcmp(ATTRIBUTE[i], "jpegPhoto")) { debug_print("not updating jpegPhoto\n"); continue; } if (ldapsvr_check_search_attributes(attribs, (char *) ATTRIBUTE[i])) { if (CHECKED_ATTRIBUTE[i] == FALSE) { AddrItemObject *aio = addrcache_get_object(server->addressCache, g_hash_table_lookup(contact , "uid")); ItemPerson *person = (ItemPerson *) aio; addritem_person_remove_attribute(person, (const gchar *) ATTRIBUTE[i]); } } } ldapctl_free_attribute_array(attribs); } }
/** * Update contact to LDAP * * \param server AddressBook resource * \param contact GHashTable with object to update */ void ldapsvr_update_contact(LdapServer *server, GHashTable *contact) { LDAP *ld = NULL; LDAPMod *mods[MODSIZE]; LDAPMod modarr[4]; gint cnt = 0; gchar *param, *dn; Rdn *NoRemove = NULL; char *cn[] = {NULL, NULL}; char *givenName[] = {NULL, NULL}; char **mail = NULL; char *sn[] = {NULL, NULL}; GList *mailList; int mod_op; cm_return_if_fail(server != NULL || contact != NULL); ld = ldapsvr_connect(server->control); if (ld == NULL) { clean_up(ld, server, contact); return; } dn = g_hash_table_lookup(contact, "dn"); if (dn == NULL) { clean_up(ld, server, contact); return; } NoRemove = ldapsvr_modify_dn(contact, dn); if (NoRemove) { /* We are trying to change RDN */ gchar *newRdn = g_strdup_printf("%s=%s", NoRemove->attribute, NoRemove->value); #ifdef OPEN_LDAP_API_AT_LEAST_3000 int rc = ldap_rename_s(ld, dn, newRdn, NULL, 1, NULL, NULL); #else /* This is deprecated as of OpenLDAP-2.3.0 */ int rc = ldap_modrdn2_s(ld, dn, newRdn, 1); #endif if(rc != LDAP_SUCCESS) { if (rc == LDAP_ALREADY_EXISTS) { /* We are messing with a contact with more than one listed email * address and the email we are changing is not the one used for dn */ /* It needs to be able to handle renaming errors to an already defined * dn. For now we just refuse the update. It will be caught later on as * a LDAPRC_NAMING_VIOLATION error. */ } else { g_printerr("Current dn: %s\n", dn); g_printerr("new dn: %s\n", newRdn); g_printerr("LDAP Error(ldap_modrdn2_s) failed[0x%x]: %s\n", rc, ldaputil_get_error(ld)); g_free(newRdn); clean_up(ld, server, contact); return; } } else { ItemPerson *person = g_hash_table_lookup(contact, "person"); g_free(newRdn); dn = g_strdup(NoRemove->new_dn); g_hash_table_replace(contact, "dn", dn); if (person) { g_free(person->externalID); person->externalID = dn; } } } else { server->retVal = LDAPRC_NODN; clean_up(ld, server, contact); return; } param = g_hash_table_lookup(contact , "cn"); mod_op = ldapsvr_deside_operation(ld, server, dn, "displayName", param); if (mod_op >= 0 && (strcmp(param, NoRemove->value) != 0 && strcmp("cn", NoRemove->attribute) != 0)) { if (mod_op == LDAP_MOD_DELETE) { /* Setting param to NULL instructs OpenLDAP to remove any * value stored for this attribute and remove the attribute * completely. Should multiple instances of an attribute be * allowed in the future param is required to have the value * store for the attribute which is going to be deleted */ param = NULL; } if (mod_op == LDAP_MOD_REPLACE && strcmp(param, "") == 0) { /* Having an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we treate this as a request for deleting * the attribute. */ mod_op = LDAP_MOD_DELETE; param = NULL; } if (mod_op == LDAP_MOD_ADD && strcmp(param, "") == 0) { /* Adding an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we silently refuse to add this entry */ } else { SETMOD(mods[cnt], modarr[cnt], mod_op, "displayName", cn, param); cnt++; g_hash_table_insert(contact, "displayName", param); } } param = g_hash_table_lookup(contact , "givenName"); mod_op = ldapsvr_deside_operation(ld, server, dn, "givenName", param); if (mod_op >= 0 && (strcmp(param, NoRemove->value) != 0 && strcmp("givenName", NoRemove->attribute) != 0)) { if (mod_op == LDAP_MOD_DELETE) { /* Setting param to NULL instructs OpenLDAP to remove any * value stored for this attribute and remove the attribute * completely. Should multiple instances of an attribute be * allowed in the future param is required to have the value * store for the attribute which is going to be deleted */ param = NULL; } if (mod_op == LDAP_MOD_REPLACE && strcmp(param, "") == 0) { /* Having an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we treate this as a request for deleting * the attribute. */ mod_op = LDAP_MOD_DELETE; param = NULL; } if (mod_op == LDAP_MOD_ADD && strcmp(param, "") == 0) { /* Adding an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we silently refuse to add this entry */ } else { SETMOD(mods[cnt], modarr[cnt], mod_op, "givenName", givenName, param); cnt++; } } mailList = g_hash_table_lookup(contact , "mail"); if (mailList) { debug_print("# of mail: %d\n", g_list_length(mailList)); if (!(strcmp("mail", NoRemove->attribute) == 0 && g_list_length(mailList) == 1)) { char **tmp; tmp = g_malloc(sizeof(*tmp) * (g_list_length(mailList)+1)); mail = tmp; while (mailList) { EmailKeyValue *item = mailList->data; *tmp++ = g_strdup((gchar *) item->mail); mailList = g_list_next(mailList); } *tmp = NULL; /* * At least one email address is required * in which case it will always be a replace */ SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_REPLACE, "mail", mail); cnt++; } } else { /* * an error condition since at least one email adress * is required. Should never occur though. */ } param = g_hash_table_lookup(contact , "sn"); mod_op = ldapsvr_deside_operation(ld, server, dn, "sn", param); if (mod_op >= 0 && (strcmp(param, NoRemove->value) != 0 && strcmp("sn", NoRemove->attribute) != 0)) { if (mod_op == LDAP_MOD_DELETE) { /* Setting param to NULL instructs OpenLDAP to remove any * value stored for this attribute and remove the attribute * completely. Should multiple instances of an attribute be * allowed in the future param is required to have the value * store for the attribute which is going to be deleted */ param = NULL; } if (mod_op == LDAP_MOD_REPLACE && strcmp(param, "") == 0) { /* Having an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we treate this as a request for deleting * the attribute. */ mod_op = LDAP_MOD_DELETE; param = NULL; } if (mod_op == LDAP_MOD_ADD && strcmp(param, "") == 0) { /* Adding an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we silently refuse to add this entry */ } else { SETMOD(mods[cnt], modarr[cnt], mod_op, "sn", sn, param); cnt++; } } debug_print("newDN: %s\n", dn); if (NoRemove) rdn_free(NoRemove); server->retVal = LDAPRC_SUCCESS; if (cnt > 0) { int rc; mods[cnt] = NULL; rc = ldap_modify_ext_s(ld, dn, mods, NULL, NULL); if (rc) { g_printerr("ldap_modify for dn=%s\" failed[0x%x]: %s\n", dn, rc, ldaputil_get_error(ld)); server->retVal = LDAPRC_NAMING_VIOLATION; } if (mail) g_free(mail); } ldapsvr_handle_other_attributes(ld, server, dn, contact); /* If we do not make changes persistent at this point then changes * will be lost if the user makes new search on the same server since * changes are only present in Claws' internal cache. This issue has to * be solved in addressbook.c since this involves access to structures * which are only accessible in addressbook.c */ clean_up(ld, server, contact); }
void ui_events(struct UI_PANE_LIST *panes, int render) { //override for dialogues such as message boxes. if(ui_panelist_dialogue.pane) { ui_panelist_render(panes); panes=&ui_panelist_dialogue; } UI_EVENT e; UI_EVENT_MOUSE e_m; UI_EVENT_BUTTONS e_b; UI_EVENT_UI e_u; static UI_EVENT_KEYBOARD e_k={0, 0, 0}, e_k_repeat={0, 0, 0}; static int repeat=0; DARNIT_KEYS buttons; buttons=d_keys_get(); memcpy(&e_b, &buttons, sizeof(UI_EVENT_BUTTONS)); DARNIT_MOUSE mouse; mouse=d_mouse_get(); e_m.x=mouse.x; e_m.y=mouse.y; e_m.buttons=(mouse.lmb)|(mouse.rmb<<2); e_m.wheel=mouse.wheel; int key_action=0; DARNIT_KEY_RAW rawkey=d_key_raw_pop(); key_action=rawkey.action; e_k.keysym=rawkey.keysym; switch(e_k.keysym) { case KEY(LCTRL): SETMOD(LCTRL); break; case KEY(RCTRL): SETMOD(RCTRL); break; case KEY(LSHIFT): SETMOD(LSHIFT); break; case KEY(RSHIFT): SETMOD(RSHIFT); break; case KEY(LALT): SETMOD(LALT); break; case KEY(RALT): SETMOD(RALT); break; case KEY(LSUPER): SETMOD(LSUPER); break; case KEY(RSUPER): SETMOD(RSUPER); break; } e_k.character=rawkey.unicode; e.keyboard=&e_k; if(ui_selected_widget) { //Keyboard events for selected widget if(e_k_repeat.character||e_k_repeat.keysym==8) { if(repeat>KEYBOARD_REPEAT_DELAY&&!((repeat-KEYBOARD_REPEAT_DELAY)%KEYBOARD_REPEAT_SPEED)) { UI_EVENT e_repeat={.keyboard=&e_k_repeat}; ui_selected_widget->event_handler->send(ui_selected_widget, UI_EVENT_TYPE_KEYBOARD_PRESS, &e_repeat); } repeat++; } if(key_action==DARNIT_KEYACTION_PRESS) { if(e_k.character||e_k.keysym==8) { e_k_repeat=e_k; repeat=0; } ui_selected_widget->event_handler->send(ui_selected_widget, UI_EVENT_TYPE_KEYBOARD_PRESS, &e); } else if(key_action==DARNIT_KEYACTION_RELEASE) { if(e_k.keysym==e_k_repeat.keysym) { e_k_repeat.character=0; e_k_repeat.keysym=0; e_k_repeat.modifiers=0; repeat=0; } ui_selected_widget->event_handler->send(ui_selected_widget, UI_EVENT_TYPE_KEYBOARD_RELEASE, &e); } } else {