about summary refs log blame commit diff stats
path: root/src/contact.c
blob: 9cbe5d69665287c9227b0e7347f80e4c3370d259 (plain) (tree)
1
2
3
4
5
  


                                                     
  
















                                                                       


                   

                 


                    
              
               
                   
                 
                       
                         

  
        

                                                              
                                                          

                                                          
                               
 







                                                        
        
                                             





                                         


                                                     
                                                
 

                                       


                   

                                

                                                       








                                               
 



                                               
 




                                                           


                

                                
 



                               
 


                                
     





                                    




                                  




                                        



                   
            





                                     
                                      



                         
            
                                          
 
                             

 

                                        


                           
 





                                              





                                             





























                                                                           

                                                           
 
                                                    
                                                       
                                                                   
                                                             
                                                                               
 
                                                                              
 
/*
 * contact.c
 *
 * Copyright (C) 2012 James Booth <boothj5@gmail.com>
 *
 * This file is part of Profanity.
 *
 * Profanity is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Profanity is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Profanity.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <stdlib.h>
#include <string.h>

#include <glib.h>

#include "contact.h"

struct p_contact_t {
    char *jid;
    char *name;
    char *presence;
    char *status;
    char *subscription;
    gboolean pending_out;
};

PContact
p_contact_new(const char * const jid, const char * const name,
    const char * const presence, const char * const status,
    const char * const subscription, gboolean pending_out)
{
    PContact contact = malloc(sizeof(struct p_contact_t));
    contact->jid = strdup(jid);

    if (name != NULL) {
        contact->name = strdup(name);
    } else {
        contact->name = NULL;
    }

    if (presence == NULL || (strcmp(presence, "") == 0))
        contact->presence = strdup("online");
    else
        contact->presence = strdup(presence);

    if (status != NULL)
        contact->status = strdup(status);
    else
        contact->status = NULL;

    if (subscription != NULL)
        contact->subscription = strdup(subscription);
    else
        contact->subscription = strdup("none");;

    contact->pending_out = pending_out;

    return contact;
}

PContact
p_contact_copy(PContact contact)
{
    PContact copy = malloc(sizeof(struct p_contact_t));
    copy->jid = strdup(contact->jid);

    if (contact->name != NULL) {
        copy->name = strdup(contact->name);
    } else {
        copy->name = NULL;
    }

    copy->presence = strdup(contact->presence);

    if (contact->status != NULL)
        copy->status = strdup(contact->status);
    else
        copy->status = NULL;

    if (contact->subscription != NULL)
        copy->subscription = strdup(contact->subscription);
    else
        copy->subscription = NULL;

    return copy;
}

void
p_contact_free(PContact contact)
{
    if (contact->jid != NULL) {
        free(contact->jid);
        contact->jid = NULL;
    }

    if (contact->name != NULL) {
        free(contact->name);
        contact->name = NULL;
    }

    if (contact->presence != NULL) {
        free(contact->presence);
        contact->presence = NULL;
    }

    if (contact->status != NULL) {
        free(contact->status);
        contact->status = NULL;
    }

    if (contact->subscription != NULL) {
        free(contact->subscription);
        contact->subscription = NULL;
    }

    free(contact);
    contact = NULL;
}

const char *
p_contact_jid(const PContact contact)
{
    return contact->jid;
}

const char *
p_contact_name(const PContact contact)
{
    return contact->name;
}

const char *
p_contact_presence(const PContact contact)
{
    return contact->presence;
}

const char *
p_contact_status(const PContact contact)
{
    return contact->status;
}

const char *
p_contact_subscription(const PContact contact)
{
    return contact->subscription;
}

gboolean
p_contact_pending_out(const PContact contact)
{
    return contact->pending_out;
}

void
p_contact_set_presence(const PContact contact, const char * const presence)
{
    if (contact->presence != NULL) {
        free(contact->presence);
        contact->presence = NULL;
    }

    if (presence == NULL) {
        contact->presence = NULL;
    } else {
        contact->presence = strdup(presence);
    }
}

void
p_contact_set_status(const PContact contact, const char * const status)
{
    if (contact->status != NULL) {
        free(contact->status);
        contact->status = NULL;
    }

    if (status == NULL) {
        contact->status = NULL;
    } else {
        contact->status = strdup(status);
    }
}

int
p_contacts_equal_deep(const PContact c1, const PContact c2)
{
    int jid_eq = (g_strcmp0(c1->jid, c2->jid) == 0);
    int name_eq = (g_strcmp0(c1->name, c2->name) == 0);
    int presence_eq = (g_strcmp0(c1->presence, c2->presence) == 0);
    int status_eq = (g_strcmp0(c1->status, c2->status) == 0);
    int subscription_eq = (g_strcmp0(c1->subscription, c2->subscription) == 0);

    return (jid_eq && name_eq && presence_eq && status_eq && subscription_eq);
}
class="cm">/*space for length*/1; ensure_space(size); long long int event_data_address = Current_routine->alloc; Memory[event_data_address] = num_events; ++Current_routine->alloc; for (long long int i = 0; i < SIZE(r.steps); ++i) { const instruction& curr = r.steps.at(i); if (curr.name == "left-click") { Memory[Current_routine->alloc] = /*tag for 'touch-event' variant of 'event' exclusive-container*/2; Memory[Current_routine->alloc+1+/*offset of 'type' in 'mouse-event'*/0] = TB_KEY_MOUSE_LEFT; Memory[Current_routine->alloc+1+/*offset of 'row' in 'mouse-event'*/1] = to_integer(curr.ingredients.at(0).name); Memory[Current_routine->alloc+1+/*offset of 'column' in 'mouse-event'*/2] = to_integer(curr.ingredients.at(1).name); Current_routine->alloc += size_of_event(); } else if (curr.name == "press") { string key = curr.ingredients.at(0).name; if (is_integer(key)) Memory[Current_routine->alloc+1] = to_integer(key); else if (Key.find(key) != Key.end()) Memory[Current_routine->alloc+1] = Key[key]; else raise_error << "assume-console: can't press " << key << '\n' << end(); if (Memory[Current_routine->alloc+1] < 256) // these keys are in ascii Memory[Current_routine->alloc] = /*tag for 'text' variant of 'event' exclusive-container*/0; else { // distinguish from unicode Memory[Current_routine->alloc] = /*tag for 'keycode' variant of 'event' exclusive-container*/1; } Current_routine->alloc += size_of_event(); } // End Event Handlers else { // keyboard input assert(curr.name == "type"); const string& contents = curr.ingredients.at(0).name; const char* raw_contents = contents.c_str(); long long int num_keyboard_events = unicode_length(contents); long long int curr = 0; for (long long int i = 0; i < num_keyboard_events; ++i) { Memory[Current_routine->alloc] = /*tag for 'text' variant of 'event' exclusive-container*/0; uint32_t curr_character; assert(curr < SIZE(contents)); tb_utf8_char_to_unicode(&curr_character, &raw_contents[curr]); Memory[Current_routine->alloc+/*skip exclusive container tag*/1] = curr_character; curr += tb_utf8_char_length(raw_contents[curr]); Current_routine->alloc += size_of_event(); } } } assert(Current_routine->alloc == event_data_address+size); // wrap the array of events in a console object ensure_space(size_of_console()); Memory[CONSOLE] = Current_routine->alloc; Current_routine->alloc += size_of_console(); Memory[Memory[CONSOLE]+/*offset of 'data' in container 'events'*/1] = event_data_address; break; } :(before "End Globals") map<string, long long int> Key; :(before "End One-time Setup") initialize_key_names(); :(code) void initialize_key_names() { Key["F1"] = TB_KEY_F1; Key["F2"] = TB_KEY_F2; Key["F3"] = TB_KEY_F3; Key["F4"] = TB_KEY_F4; Key["F5"] = TB_KEY_F5; Key["F6"] = TB_KEY_F6; Key["F7"] = TB_KEY_F7; Key["F8"] = TB_KEY_F8; Key["F9"] = TB_KEY_F9; Key["F10"] = TB_KEY_F10; Key["F11"] = TB_KEY_F11; Key["F12"] = TB_KEY_F12; Key["insert"] = TB_KEY_INSERT; Key["delete"] = TB_KEY_DELETE; Key["home"] = TB_KEY_HOME; Key["end"] = TB_KEY_END; Key["page-up"] = TB_KEY_PGUP; Key["page-down"] = TB_KEY_PGDN; Key["up-arrow"] = TB_KEY_ARROW_UP; Key["down-arrow"] = TB_KEY_ARROW_DOWN; Key["left-arrow"] = TB_KEY_ARROW_LEFT; Key["right-arrow"] = TB_KEY_ARROW_RIGHT; Key["ctrl-a"] = TB_KEY_CTRL_A; Key["ctrl-b"] = TB_KEY_CTRL_B; Key["ctrl-c"] = TB_KEY_CTRL_C; Key["ctrl-d"] = TB_KEY_CTRL_D; Key["ctrl-e"] = TB_KEY_CTRL_E; Key["ctrl-f"] = TB_KEY_CTRL_F; Key["ctrl-g"] = TB_KEY_CTRL_G; Key["backspace"] = TB_KEY_BACKSPACE; Key["ctrl-h"] = TB_KEY_CTRL_H; Key["tab"] = TB_KEY_TAB; Key["ctrl-i"] = TB_KEY_CTRL_I; Key["ctrl-j"] = TB_KEY_CTRL_J; Key["enter"] = TB_KEY_NEWLINE; // ignore CR/LF distinction; there is only 'enter' Key["ctrl-k"] = TB_KEY_CTRL_K; Key["ctrl-l"] = TB_KEY_CTRL_L; Key["ctrl-m"] = TB_KEY_CTRL_M; Key["ctrl-n"] = TB_KEY_CTRL_N; Key["ctrl-o"] = TB_KEY_CTRL_O; Key["ctrl-p"] = TB_KEY_CTRL_P; Key["ctrl-q"] = TB_KEY_CTRL_Q; Key["ctrl-r"] = TB_KEY_CTRL_R; Key["ctrl-s"] = TB_KEY_CTRL_S; Key["ctrl-t"] = TB_KEY_CTRL_T; Key["ctrl-u"] = TB_KEY_CTRL_U; Key["ctrl-v"] = TB_KEY_CTRL_V; Key["ctrl-w"] = TB_KEY_CTRL_W; Key["ctrl-x"] = TB_KEY_CTRL_X; Key["ctrl-y"] = TB_KEY_CTRL_Y; Key["ctrl-z"] = TB_KEY_CTRL_Z; Key["escape"] = TB_KEY_ESC; } :(scenario events_in_scenario) scenario events-in-scenario [ assume-console [ type [abc] left-click 0, 1 press up-arrow type [d] ] run [ # 3 keyboard events; each event occupies 4 locations 1:event <- read-event console:address:console 5:event <- read-event console:address:console 9:event <- read-event console:address:console # mouse click 13:event <- read-event console:address:console # non-character keycode 17:event <- read-event console:address:console # final keyboard event 21:event <- read-event console:address:console ] memory-should-contain [ 1 <- 0 # 'text' 2 <- 97 # 'a' 3 <- 0 # unused 4 <- 0 # unused 5 <- 0 # 'text' 6 <- 98 # 'b' 7 <- 0 # unused 8 <- 0 # unused 9 <- 0 # 'text' 10 <- 99 # 'c' 11 <- 0 # unused 12 <- 0 # unused 13 <- 2 # 'mouse' 14 <- 65513 # mouse click 15 <- 0 # row 16 <- 1 # column 17 <- 1 # 'keycode' 18 <- 65517 # up arrow 19 <- 0 # unused 20 <- 0 # unused 21 <- 0 # 'text' 22 <- 100 # 'd' 23 <- 0 # unused 24 <- 0 # unused 25 <- 0 ] ] //: Deal with special keys and unmatched brackets by allowing each test to //: independently choose the unicode symbol to denote them. :(before "End Primitive Recipe Declarations") REPLACE_IN_CONSOLE, :(before "End Primitive Recipe Numbers") Recipe_ordinal["replace-in-console"] = REPLACE_IN_CONSOLE; :(before "End Primitive Recipe Checks") case REPLACE_IN_CONSOLE: { break; } :(before "End Primitive Recipe Implementations") case REPLACE_IN_CONSOLE: { assert(scalar(ingredients.at(0))); if (!Memory[CONSOLE]) { raise_error << "console not initialized\n" << end(); break; } long long int console_data = Memory[Memory[CONSOLE]+1]; long long int size = Memory[console_data]; // array size for (long long int i = 0, curr = console_data+1; i < size; ++i, curr+=size_of_event()) { if (Memory[curr] != /*text*/0) continue; if (Memory[curr+1] != ingredients.at(0).at(0)) continue; for (long long int n = 0; n < size_of_event(); ++n) Memory[curr+n] = ingredients.at(1).at(n); } break; } :(code) long long int count_events(const recipe& r) { long long int result = 0; for (long long int i = 0; i < SIZE(r.steps); ++i) { const instruction& curr = r.steps.at(i); if (curr.name == "type") result += unicode_length(curr.ingredients.at(0).name); else result++; } return result; } long long int size_of_event() { // memoize result if already computed static long long int result = 0; if (result) return result; type_tree* type = new type_tree(Type_ordinal["event"]); result = size_of(type); delete type; return result; } long long int size_of_console() { // memoize result if already computed static long long int result = 0; if (result) return result; assert(Type_ordinal["console"]); type_tree* type = new type_tree(Type_ordinal["console"]); result = size_of(type); delete type; return result; }