/*
$Id: lowlevel.c,v 1.18 2002/07/12 18:10:01 pkot Exp $
S M S D
A Linux/Unix GUI for Nokia mobile phones.
This file is part of gnokii.
Gnokii 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 2 of the License, or
(at your option) any later version.
Gnokii 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 gnokii; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Copyright (C) 1999 Pavel Janík ml., Hugh Blemings
& Ján Derfiòák
.
*/
#include
#include
#include
#include
#include "misc.h"
#include "gsm-common.h"
#include "gsm-api.h"
#include "phones/nk7110.h"
#include "phones/nk6510.h"
#include "phones/nk6100.h"
#include "phones/nk3110.h"
#include "phones/nk2110.h"
#include "smsd.h"
#include "lowlevel.h"
#include "cfgreader.h"
pthread_t monitor_th;
PhoneMonitor phoneMonitor;
pthread_mutex_t smsMutex;
pthread_cond_t smsCond;
pthread_mutex_t sendSMSMutex;
pthread_cond_t sendSMSCond;
static pthread_mutex_t eventsMutex;
static GSList *ScheduledEvents = NULL;
static GSM_Statemachine sm;
static char *lockfile = NULL;
inline void InsertEvent (PhoneEvent *event)
{
# ifdef XDEBUG
g_print ("Inserting Event: %d\n", event->event);
# endif
pthread_mutex_lock (&eventsMutex);
ScheduledEvents = g_slist_prepend (ScheduledEvents, event);
pthread_mutex_unlock (&eventsMutex);
}
inline static PhoneEvent *RemoveEvent (void)
{
GSList *list;
PhoneEvent *event = NULL;
pthread_mutex_lock (&eventsMutex);
list = g_slist_last (ScheduledEvents);
if (list)
{
event = (PhoneEvent *) list->data;
ScheduledEvents = g_slist_remove_link (ScheduledEvents, list);
g_slist_free_1 (list);
}
pthread_mutex_unlock (&eventsMutex);
return (event);
}
static GSM_Error InitModelInf (void)
{
GSM_Data data;
gchar buf[64];
GSM_Error error;
char model[64], rev[64], manufacturer[64];
GSM_DataClear(&data);
data.Manufacturer = manufacturer;
data.Model = model;
data.Revision = rev;
error = SM_Functions (GOP_GetModel, &data, &sm);
if (error != GE_NONE)
return error;
g_free (phoneMonitor.phone.model);
phoneMonitor.phone.version = g_strdup (model);
phoneMonitor.phone.model = GetPhoneModel (model)->model;
if (phoneMonitor.phone.model == NULL)
phoneMonitor.phone.model = g_strdup (_("unknown"));
phoneMonitor.supported = GetPhoneModel (model)->flags;
g_free (phoneMonitor.phone.revision);
phoneMonitor.phone.revision = g_strdup (rev);
#ifdef XDEBUG
g_print ("Version: %s\n", phoneMonitor.phone.version);
g_print ("Model: %s\n", phoneMonitor.phone.model);
g_print ("Revision: %s\n", phoneMonitor.phone.revision);
#endif
return (GE_NONE);
}
static void busterminate(void)
{
SM_Functions(GOP_Terminate, NULL, &sm);
if (lockfile) unlock_device(lockfile);
}
static GSM_Error fbusinit (bool enable_monitoring)
{
GSM_Error error = GE_NOLINK;
GSM_ConnectionType connection = GCT_Serial;
char *aux;
static bool atexit_registered = false;
if (!strcmp(smsdConfig.connection, "infrared"))
connection = GCT_Infrared;
if (!strcmp(smsdConfig.connection, "irda"))
connection = GCT_Irda;
if (!strcmp(smsdConfig.connection, "dau9p"))
connection = GCT_DAU9P;
if (!strcmp(smsdConfig.connection, "tcp"))
connection = GCT_TCP;
/* register cleanup function */
if (!atexit_registered) {
atexit_registered = true;
atexit(busterminate);
}
/* signal(SIGINT, bussignal); */
aux = CFG_Get(CFG_Info, "global", "use_locking");
/* Defaults to 'no' */
if (aux && !strcmp(aux, "yes")) {
lockfile = lock_device(smsdConfig.port);
if (lockfile == NULL) {
fprintf(stderr, _("Lock file error. Exiting\n"));
exit(1);
}
}
/* Initialise the code for the GSM interface. */
error = GSM_Initialise (smsdConfig.model, smsdConfig.port,
smsdConfig.initlength, connection, NULL, &sm);
#ifdef XDEBUG
g_print ("fbusinit: error %d\n", error);
#endif
if (error != GE_NONE) {
g_print (_("GSM/FBUS init failed! (Unknown model ?). Quitting.\n"));
return (error);
}
/* Why GSM_Initialise returns before initialization is completed?
We must wait cca 2 seconds. If smsd segfaults during initialiazation
try to increase number of seconds.
*/
sleep (2);
return InitModelInf ();
}
void InitPhoneMonitor (void)
{
phoneMonitor.phone.model = g_strdup (_("unknown"));
phoneMonitor.phone.version = phoneMonitor.phone.model;
phoneMonitor.phone.revision = g_strdup (_("unknown"));
phoneMonitor.supported = 0;
phoneMonitor.working = FALSE;
phoneMonitor.sms.unRead = phoneMonitor.sms.number = 0;
phoneMonitor.sms.messages = NULL;
pthread_mutex_init (&smsMutex, NULL);
pthread_cond_init (&smsCond, NULL);
pthread_mutex_init (&sendSMSMutex, NULL);
pthread_cond_init (&sendSMSCond, NULL);
pthread_mutex_init (&eventsMutex, NULL);
}
static inline void FreeElement (gpointer data, gpointer userData)
{
g_free ((GSM_SMSMessage *) data);
}
static inline void FreeArray (GSList **array)
{
if (*array) {
g_slist_foreach (*array, FreeElement, NULL);
g_slist_free (*array);
*array = NULL;
}
}
static void RefreshSMS (const gint number)
{
static GSM_Data data;
GSM_Error error;
GSM_API_SMS *msg;
SMS_Folder *fld;
SMS_FolderList *list;
register gint i;
#ifdef XDEBUG
g_print ("RefreshSMS is running...\n");
#endif
pthread_mutex_lock (&smsMutex);
FreeArray (&(phoneMonitor.sms.messages));
phoneMonitor.sms.number = 0;
pthread_mutex_unlock (&smsMutex);
GSM_DataClear(&data);
fld = g_malloc(sizeof(SMS_Folder));
list = g_malloc(sizeof(SMS_FolderList));
fld->FolderID = 0;
i = 0;
while (1) {
msg = g_malloc(sizeof(GSM_API_SMS));
if (phoneMonitor.supported & PM_FOLDERS)
msg->MemoryType = GMT_IN;
else
msg->MemoryType = GMT_SM;
msg->Number = ++i;
data.SMS = msg;
data.SMSFolder = fld;
data.SMSFolderList = list;
if ((error = GetSMS (&data, &sm)) == GE_NONE) {
pthread_mutex_lock (&smsMutex);
phoneMonitor.sms.messages = g_slist_append (phoneMonitor.sms.messages, msg);
phoneMonitor.sms.number++;
if (phoneMonitor.sms.number == number) {
pthread_cond_signal (&smsCond);
pthread_mutex_unlock (&smsMutex);
g_free (fld);
g_free (list);
return;
}
pthread_mutex_unlock (&smsMutex);
} else if (error == GE_INVALIDLOCATION) { /* All positions are read */
g_free (msg);
g_free (fld);
g_free (list);
pthread_cond_signal (&smsCond);
break;
} else {
g_free (msg);
}
/*
usleep (350000);
*/
}
}
static gint A_SendSMSMessage (gpointer data)
{
D_SMSMessage *d = (D_SMSMessage *) data;
GSM_Error error;
GSM_Data dt;
error = d->status = GE_UNKNOWN;
if (d) {
pthread_mutex_lock (&sendSMSMutex);
GSM_DataClear (&dt);
if (!d->sms->SMSC.Number[0]) {
dt.MessageCenter = calloc (1, sizeof (SMS_MessageCenter));
dt.MessageCenter->No = 1;
if (SM_Functions (GOP_GetSMSCenter, &dt, &sm) == GE_NONE) {
strcpy (d->sms->SMSC.Number, dt.MessageCenter->SMSC.Number);
d->sms->SMSC.Type = dt.MessageCenter->SMSC.Type;
}
free (dt.MessageCenter);
}
if (!d->sms->SMSC.Type)
d->sms->SMSC.Type = SMS_Unknown;
GSM_DataClear (&dt);
dt.SMS = d->sms;
error = d->status = SendSMS (&dt, &sm);
pthread_cond_signal (&sendSMSCond);
pthread_mutex_unlock (&sendSMSMutex);
}
if (d->status == GE_NONE)
return (GE_NONE);
else
return (error);
}
static gint A_DeleteSMSMessage (gpointer data)
{
GSM_Data dt;
GSM_Error error = GE_UNKNOWN;
SMS_Folder SMSFolder;
SMS_FolderList SMSFolderList;
GSM_DataClear(&dt);
dt.SMS = (GSM_API_SMS *) data;
dt.SMSFolder = &SMSFolder;
dt.SMSFolderList = &SMSFolderList;
dprintf("Delete SMS message!\n");
if (dt.SMS)
error = DeleteSMS(&dt, &sm);
return (error);
}
static gint A_Exit (gpointer data)
{
pthread_exit (0);
return (0); /* just to be proper */
}
gint (*DoAction[])(gpointer) = {
A_SendSMSMessage,
A_DeleteSMSMessage,
A_Exit
};
void *Connect (void *a)
{
GSM_Data data;
SMS_Status SMSStatus = {0, 0, 0, 0};
SMS_Folder SMSFolder;
PhoneEvent *event;
GSM_Error error;
GSM_DataClear(&data);
#ifdef XDEBUG
g_print ("Initializing connection...\n");
#endif
if (fbusinit (true) != GE_NONE)
exit (1);
#ifdef XDEBUG
g_print ("Phone connected. Starting monitoring...\n");
#endif
while (1) {
phoneMonitor.working = FALSE;
if (phoneMonitor.supported & PM_FOLDERS) {
data.SMSFolder = &SMSFolder;
SMSFolder.FolderID = GMT_IN;
if ((error = SM_Functions (GOP_GetSMSFolderStatus, &data, &sm)) == GE_NONE) {
if (phoneMonitor.sms.number != SMSFolder.Number) {
phoneMonitor.working = TRUE;
RefreshSMS (SMSFolder.Number);
phoneMonitor.working = FALSE;
}
phoneMonitor.sms.unRead = 0;
}
} else {
data.SMSStatus = &SMSStatus;
if ((error = SM_Functions (GOP_GetSMSStatus, &data, &sm)) == GE_NONE) {
if (phoneMonitor.sms.unRead != SMSStatus.Unread ||
phoneMonitor.sms.number != SMSStatus.Number) {
phoneMonitor.working = TRUE;
RefreshSMS (SMSStatus.Number);
phoneMonitor.working = FALSE;
}
phoneMonitor.sms.unRead = SMSStatus.Unread;
}
}
while ((event = RemoveEvent ()) != NULL) {
#ifdef XDEBUG
g_print ("Processing Event: %d\n", event->event);
#endif
phoneMonitor.working = TRUE;
if (event->event <= Event_Exit)
if ((error = DoAction[event->event] (event->data)) != GE_NONE)
g_print (_("Event %d failed with return code %d!\n"), event->event, error);
g_free (event);
}
sleep (2);
}
}