How to get "SIP header of incoming call" in PJSUA2? - android

I'm developing an android app which supports SIP using pjsip2.7 and pjsua2. I needed to set custom header to my sip call, which I had done, and I set Asterisk 13 Server to forward my header to other party. I could see in logs that my custom header is received but I cant use this header in receiver. I need a way to get this parameters I sent in header.
Is there any way to do that ?

I am using pjsua2 with golang instead of C++ and I had the same problem. Although, I didn't find the best way to do it, I found one that works.
First at all, you need to implement one account which extends to the pjsua2 account. Then, overwritte the OnIncomingCall callback in order to use the OnIncomingCallParam, I have used this code to get the header (it's in golang)
func (acc *MyAccount) OnIncomingCall(prm pjsua2.OnIncomingCallParam) {
msg := prm.GetRdata().GetWholeMsg()
msgindex := strings.Index(msg, "NEWHEADER")
if msgindex != -1 {
cabecera = true
msg = msg[msgindex:]
msg = msg[strings.Index(msg, ":")+1:]
msgindex = strings.Index(msg, "Content-Type")
msg = msg[:msgindex] //this is to avoid spaces
msg = strings.Trim(msg, " ")
msg = strings.Trim(msg, "\n")
msg = strings.Trim(msg, "\r")
log.Info("NEWHEADER info:" + msg + "")
} else {
log.Error("THERE IS NO NEWHEADER")
}
I'm sorry for being so late

Related

how to implement client listener in Android using golang object?

Problem description:
I am working on a small project in which i need to port the existing mqtt client library from Golang to Android.
I found using gomobile repository as an option to prevent duplicating the same functionality in different programming languages (GO and Java).
To use this library we have two different options:
Design the android app purely in Go and use "gomobile -build" to generate an APK file. An APK file then can be loaded to android device or emulator using adb tool.
Implement some functionality and then bind them into existing Android project using "gomobile -bind". With this option there are some restriction for conversion and building Golang objects.
For my case I plan to pick the second option. Also trying to convert the following small sample GO implementation to Android (borrowed from here).
package main
import (
"fmt"
mqtt "github.com/eclipse/paho.mqtt.golang"
"log"
"time"
)
var messagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
fmt.Printf("Received message: %s from topic: %s\n", msg.Payload(), msg.Topic())
}
var connectHandler mqtt.OnConnectHandler = func(client mqtt.Client) {
fmt.Println("Connected")
}
var connectLostHandler mqtt.ConnectionLostHandler = func(client mqtt.Client, err error) {
fmt.Printf("Connect lost: %v", err)
}
func main() {
var broker = "broker.emqx.io"
var port = 1883
opts := mqtt.NewClientOptions()
opts.AddBroker(fmt.Sprintf("tcp://%s:%d", broker, port))
opts.SetClientID("go_mqtt_client")
opts.SetUsername("emqx")
opts.SetPassword("public")
opts.SetDefaultPublishHandler(messagePubHandler)
opts.OnConnect = connectHandler
opts.OnConnectionLost = connectLostHandler
client := mqtt.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil {
panic(token.Error())
}
sub(client)
publish(client)
client.Disconnect(250)
}
func publish(client mqtt.Client) {
num := 10
for i := 0; i < num; i++ {
text := fmt.Sprintf("Message %d", i)
token := client.Publish("topic/test", 0, false, text)
token.Wait()
time.Sleep(time.Second)
}
}
func sub(client mqtt.Client) {
topic := "topic/test"
token := client.Subscribe(topic, 1, nil)
token.Wait()
fmt.Printf("Subscribed to topic: %s", topic)
}
My Question:
After converting the sample code, i am not sure how i can implement the listener side.
the probelm is that "gomobile -bind" cannot convert all user data types (i.e client into Java).
I can implement the connect, subscribe, and publish, but not the listener one (in other words, the "opts.SetDefaultPublishHandler(messagePubHandler)" is not repeatedly working when i call the corresponding method in Android)
Any suggestion?
This is what is tried, but it does not work
var Options *mqtt.ClientOptions
var ReceivedMsg string
func AddBroker(broker string, port int) {
Options = mqtt.NewClientOptions()
Options.AddBroker(fmt.Sprintf("tcp://%s:%d", broker, port))
}
var MessagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
ReceivedMsg = " Message " + string(msg.Payload()) + " received on topic" + msg.Topic()
fmt.Printf(ReceivedMsg)
}
func Listener(clientId string) {
Options.SetClientID(clientId)
Options.SetDefaultPublishHandler(MessagePubHandler)
Options.OnConnect = ConnectHandler
Options.OnConnectionLost = ConnectionLostHandler
}

How to fix this Firebase message format sent from ESP32 (Arduino, ESP-IDF - all text, no Firebase library used)

I'm trying to get this code below to work which was working perfectly a year ago the last time I tried it. After running it I receive no notification in my app. Using in Arduino IDE on ESP32 module. No changes were made at all to the sketch that was once working other than updating the token. I do not get the "firebase error" message in the serial output so assuming no error.
WiFiClient client;
String serve = "MY SERVER KEY";
String appToken = "MY APP TOKEN";
String data = "{";
data = data + "\"to\": \"" + appToken + "\",";
data = data + "\"notification\": {";
data = data + "\"body\": \"example body\",";
data = data + "\"title\" : \"my title\" ";
data = data + "} }";
Serial.println("Send data...");
if (client.connect("fcm.googleapis.com", 80)) {
Serial.println("Connected to the server..");
client.println("POST /fcm/send HTTP/1.1");
client.println("Authorization: key=" + serve + "");
client.println("Content-Type: application/json");
client.println("Host: fcm.googleapis.com");
client.print("Content-Length: ");
client.println(data.length());
client.print("\n");
client.print(data);
Serial.println("data");
Serial.println(data);
}
else {
Serial.println("firebase error");
}
Serial.println("Data sent...Reading response..");
while (client.available()) {
char c = client.read();
Serial.print(c);
}
Serial.println("Finished!");
client.flush();
client.stop();
}
I just updated Firebase in my app and migrated to AndroidX and can receive messages sent from the Firebase console and I'm currently using this library successfully to send and receive the notifications in my app. Below is the example I'm using and it's working perfectly.
#include <WiFi.h>
#include <FirebaseESP32.h>
#define WIFI_SSID "YOUR_WIFI_AP"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
#define FIREBASE_HOST "YOUR_FIREBASE_PROJECT.firebaseio.com" //Do not include https:// in FIREBASE_HOST
#define FIREBASE_AUTH "YOUR_FIREBASE_DATABASE_SECRET"
#define FIREBASE_FCM_SERVER_KEY "YOUR_FIREBASE_PROJECT_CLOUD_MESSAGING_SERVER_KEY"
#define FIREBASE_FCM_DEVICE_TOKEN_1 "RECIPIENT_DEVICE_TOKEN"
#define FIREBASE_FCM_DEVICE_TOKEN_2 "ANOTHER_RECIPIENT_DEVICE_TOKEN"
FirebaseData firebaseData1;
unsigned long lastTime = 0;
int count = 0;
void sendMessage();
void setup()
{
Serial.begin(115200);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to Wi-Fi");
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
Firebase.reconnectWiFi(true);
firebaseData1.fcm.begin(FIREBASE_FCM_SERVER_KEY);
firebaseData1.fcm.addDeviceToken(FIREBASE_FCM_DEVICE_TOKEN_1);
firebaseData1.fcm.addDeviceToken(FIREBASE_FCM_DEVICE_TOKEN_2);
firebaseData1.fcm.setPriority("high");
firebaseData1.fcm.setTimeToLive(1000);
sendMessage();
}
void loop()
{
if (millis() - lastTime > 60 * 1000)
{
lastTime = millis();
sendMessage();
}
}
void sendMessage()
{
Serial.println("------------------------------------");
Serial.println("Send Firebase Cloud Messaging...");
firebaseData1.fcm.setNotifyMessage("Notification", "Hello World! " + String(count));
firebaseData1.fcm.setDataMessage("{\"myData\":" + String(count) + "}");
//if (Firebase.broadcastMessage(firebaseData1))
//if (Firebase.sendTopic(firebaseData1))
if (Firebase.sendMessage(firebaseData1, 0))//send message to recipient index 0
{
Serial.println("PASSED");
Serial.println(firebaseData1.fcm.getSendResult());
Serial.println("------------------------------------");
Serial.println();
}
else
{
Serial.println("FAILED");
Serial.println("REASON: " + firebaseData1.errorReason());
Serial.println("------------------------------------");
Serial.println();
}
count++;
}
I've tried sending the code at the top in data and notification message format with app in foreground and background and cannot receive a message. I'm wondering if something in the Firebase format or rules or such has changed within the last year. I need to use the code at the top instead of the library because I can just add a few more key value pairs in the message body and also send to iOS which I have done successfully in the past using the same code. I'm sure the key pairs could be added with the library actually which I'm working on now but would really prefer the simplicity of the top code. Would appreciate any advice.
I'm not certain but I believe the problem may be that the Arduino code is sending via HTTP and not HTTPS, which I read in the FB docs HTTPS is required. Maybe they changed that because this same code was working perfectly for me a year ago. But I was in the process of migrating my code over to ESP-IDF and this function below is working on that with no problem which has slight mods to comply with C++ I'm using in PlatformIO / VS Code IDE. This was the only thing changed:
esp_http_client_config_t config = {};
config.url = "https://fcm.googleapis.com/fcm/send";
config.event_handler = _http_event_handler;
I didn't need any type of SSL certificate, I just sent the code as shown. I didn't try messing around too much with the Arduino code for HTTPS.
static void firebasePost() {
esp_http_client_config_t config = {}; // important to initialize with "{}" when using C++ on ESP-IDF http client or it will crash easily
config.url = "https://fcm.googleapis.com/fcm/send";
config.event_handler = _http_event_handler;
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_err_t err = esp_http_client_perform(client);
const char *post_data = "{\"to\": \"eCiC-20m8Zw:APA91bE4i1rkC(SHORTENED)9JZpbW3gFe5Qfz9BhOFmqua3aeZoDZEQ\",\"notification\": {\"body\": \"Sample Body\",\"title\" : \"Sample Title\"} }";
esp_http_client_set_header(client, "Authorization", "key=AAAAZrM4XXXX:APA91bFnSr_U15y6mX(SHORTENED)WqaWECxYWaCf_rVPE");
esp_http_client_set_header(client, "Content-Type", "application/json");
esp_http_client_set_method(client, HTTP_METHOD_POST);
esp_http_client_set_post_field(client, post_data, strlen(post_data));
err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
} else {
ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
}
esp_http_client_cleanup(client);
}
The Arduino Firebase library connects to Firebase via SSL port 443 (HTTPS method) for both FCM and RTDB.
Your above assumption is not correct.
Your device token is invalid or not existed.
You don't have to know the code inside the Arduino library. Google only accept secure connection for their services. The problems can be the device uid or redundant of FCM payload data. You accept your answer with your own assumption. No solution for this issue. You need to open the issue at GitHub repo.

IHE and HL7. PCD-01 ACK

I'm trying to get data from a monitor to an Android application and I've took the IHE - PCD-01 transaction as a model.
The scheme is simple, is based on achieve the interconnection between the monitor and the tablet, where the monitor sends constantly information and the application is listening.
But what I don't understand is if I need an ACK or not after every message. Does anyone can help me with this?
TL;DR yes, nothing special here, support the usual HL7 ACK/NACK driven by MSH-15, MSH-16 fields. ACK-ing everything by default is "better safe then sorry"
The document "IHE Patient Care Device (PCD), Technical Framework, Volume 2 (PCD TF-2) Transactions, Revision 1.0 - Final Text, August 12, 2011" available at http://www.ihe.net/technical_framework/upload/ihe_pcd_tf_vol2_ft_2011-08-12.pdf says
..The common static definition of the HL7 acknowledgement (ACK) message is described in Appendix G, "HL7 Implementation Notes"..
which says
G.1 Network Guidelines
The HL7 2.6 standard does not define a network communications protocol. Beginning with HL7 2.2, the definitions of lower layer protocols were moved to the Implementation Guide, but are not HL7 requirements. The IHE Framework makes these recommendations:
Applications shall use the Minimal Lower Layer Protocol defined in Appendix C of the HL7 Implementation Guide.
An application that wants to send a message (initiate a transaction) will initiate a network connection to start the transaction. The receiver application will respond with an acknowledgement or response to query but will not initiate new transactions on this network connection
G.1.1 Acknowledgment Modes
ACKNOWLEDGMENT MESSAGES
Acknowledgment messages may be defined on an application basis. However the simple general acknowledgment message (ACK) may be used where the application does not define a special message (application level acknowledgment) and in other cases as described in Section 2.9, "Message Processing Rules".
The IHE PCD transaction PCD-03 supports „enhanced mode‟ acknowledgements. See discussion under PCD-03 Transactions as well as in B.1 MSH – Message Header Segment and B.2 MSA – Message Acknowledgement Segment
and document "Health Level Seven, Version 2.6 © 2007, Chapter 2: Control" coming from the "HL7 Messaging Standard Version 2.6" package which can be downloaded from http://www.hl7.org/implement/standards/product_brief.cfm?product_id=185 describes the accept and validate behavior in
2.9.2 Message response using the original processing rules
..too long to quote..
2.9.3 Response using enhanced acknowledgement
..too long to quote..
depending on the values of MSH-15 Accept Acknowledgement Type and MSH-16 Application Acknowledgment Type fields in the HL7 message
The above chapters from the HL7 standard contain what you want to read and implement/support.
EDIT:
Simply put, in HL7 protocol in every message sent the sender may request an ACK receipt by flagging appropriate fields in the message header segment. IHE does not remove this rule and does not enforce any other but enables any other convention to be defined on an application basis. Correct expected behavior is defined by the HL7 specification and in order to get it right and create a conforming implementation (without hidden surprises for your 3rd parties) you may need to read it several times (see also Stack Overflow: How can I make my system HL7 certified?)
For example this is how HAPI library handles the ACKing, snippet comes from http://sourceforge.net/p/hl7api/code/764/tree/tags/Root_REL_1_2/hapi-mvn/hapi-base/src/main/java/ca/uhn/hl7v2/protocol/impl/ProcessorImpl.java
/**
* #see ca.uhn.hl7v2.protocol.Processor#cycle(boolean)
*/
public void cycle(boolean expectingAck) throws HL7Exception {
log.debug("In cycle({})", expectingAck);
cleanReservations();
cleanAcceptAcks();
cleanReservedMessages();
Transportable in = null;
try {
if (expectingAck) {
in = tryReceive(myContext.getLocallyDrivenTransportLayer());
} else {
in = tryReceive(myContext.getRemotelyDrivenTransportLayer());
}
} catch (TransportException e) {
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {}
throw e;
}
// log
if (in != null) {
log.debug("Received message: {}", in.getMessage());
} else {
log.debug("Received no message");
}
// If we have a message, handle it
if (in != null) {
String acceptAckNeeded = null;
// String appAckNeeded = null;
String ackCode = null;
String ackId = null;
try {
String[] fieldPaths = {"MSH-15", "MSH-16", "MSA-1", "MSA-2"};
String[] fields = PreParser.getFields(in.getMessage(), fieldPaths);
acceptAckNeeded = fields[0];
// appAckNeeded = fields[1];
ackCode = fields[2];
ackId = fields[3];
} catch (HL7Exception e) {
log.warn("Failed to parse accept ack fields in incoming message", e);
}
if (ackId != null && ackCode != null && ackCode.startsWith("C")) {
long expiryTime = System.currentTimeMillis() + 1000 * 60;
myAcceptAcks.put(ackId, new ExpiringTransportable(in, expiryTime));
} else {
AcceptAcknowledger.AcceptACK ack = AcceptAcknowledger.validate(getContext(), in);
if ((acceptAckNeeded != null && acceptAckNeeded.equals(AL))
|| (acceptAckNeeded != null && acceptAckNeeded.equals(ER) && !ack.isAcceptable())
|| (acceptAckNeeded != null && acceptAckNeeded.equals(SU) && ack.isAcceptable())) {
trySend(myContext.getRemotelyDrivenTransportLayer(), ack.getMessage());
}
if (ack.isAcceptable()) {
if (isReserved(ackId)) {
log.debug("Received expected ACK message with ACK ID: {}", ackId);
removeReservation(ackId);
long expiryTime = System.currentTimeMillis() + 1000 * 60 * 5;
myAvailableMessages.put(ackId, new ExpiringTransportable(in, expiryTime));
} else {
log.debug("Sending message to router");
Transportable out = myContext.getRouter().processMessage(in);
sendAppResponse(out);
}
} else {
// TODO: should we do something more here? Might be nice to
// allow a configurable handler for this situation
log.warn("Incoming message was not acceptable");
}
}
} else {
String transport = expectingAck ? " Locally driven " : "Remotely driven";
log.debug("{} TransportLayer.receive() returned null.", transport);
}
sleepIfNeeded();
log.debug("Exiting cycle()");
}
Thanks for your answer :)
of course that it is better to use an ACK to make sure if the receiver is getting the message but what I wanted to know if it was mandatory or not using the PCD-01 transaction.
I've read your documents and what I've understood is that the use of ACK depends on the MSH-15 and MSH-16 fields content, but with the following information:
An application that wants to send a message (initiate a transaction) will initiate a network connection to start the transaction. The receiver application will respond with an acknowledgement or response to query but will not initiate new transactions on this network connection
I understand that the ACK is only at the beginning of the connection not after every message, is it right?

getting HTTP response headers with getAllResponseHeaders

I'm trying to get the http response headers every time I visit some site. I thought that using an observer like the following is enough to do it:
const OBS = Cc['#mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
let httpRequestObserver ={
observe: function(subject, topic, data){
var httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
if (topic == "http-on-examine-response") {
headers=httpChannel.getAllResponseHeaders();
}
}
};
And in the startup method I add it then in the shutdown I remove it:
OBS.addObserver(httpRequestObserver, "http-on-examine-response", false);//startup methode
OBS.addObserver(httpRequestObserver, "http-on-examine-response", false);//shutdown
But I'm getting this in the log:
JavaScript Error: "httpChannel.getAllResponseHeaders is not a function"
Am I taking the wrong way and the operation is more complicated than it seem? this is for an extension for firefox for android and i'm not using sdk. Thanks for your help.
nsIHttpChannel is not XMLHttpRequest. Instead XMLhttpRequest is a nice wrapper class around channels - not just http ones -, which also adds convenience functions such as getAllResponseHeaders().
You may use nsIHttpChannel.visitResponseHeaders to simulate getAllResponseHeaders.
if (subject instanceof Ci.nsIHttpChannel) {
var headers = "";
subject.visitResponseHeaders(function(header, value) {
headers += header + ": " + value + "\r\n";
});
}

JavaMail Message getHeader() bug

I am writing an Android GMail client application.
When it creates a message, I add a header to it like this:
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(username));
msg.setSubject(subject);
msg.setText(message);
msg.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
long time = someTime;
msg.addHeader("My_Header", Long.toString(time));
//IMAPFolder f declaration & initialization
f.open(Folder.READ_WRITE);
f.addMessages(new Message[]{msg});
f.close(true);
It all works fine and I am able to see the header correctly added to the message when viewing my GMail account on my PC. However, when I later try to retrieve the header information, it gets very weird.
When I call
String[] str = msg.getHeader("My_Header");
getHeader() returns null if I am running the app. However, when I debug the app and set a breakpoint before the getHeader() call, it returns the header value corrently.
My source code:
MimeMessage msg = getNextMessage();
String subject = msg.getSubject();
InternetAddresses to[] = msg.getAllRecipients()
String when[] = msg.getHeader(GMailClient.TIME_TO_SEND);
if (when == null) {
Log.i(TAG, "Null Header");
} else {
long time = Long.parseLong(when[0]);
Log.i(TAG, "Value retrieved: " + when[0]);
}
Possibly Gmail isn't returning the header information correctly via IMAP? You might want to look at the protocol trace to see exactly what the server is returning for your request.
Also, try writing out the entire message using (e.g.)
msg.writeTo(new FileOutputStream("msg.txt"));
and see if the header is there. If it is, and the protocol trace shows that it's not being returned for the getHeader call, it's a bug in the server. In that case, see the JavaMail FAQ entry for how to work around such server bugs.

Categories

Resources