how to create persistent muc room in smack 4.1 beta2 - xmpp

migrated from asmack to smack 4.1 beta2.
The muc rooms created are no longer persistent.
MultiUserChatManager mucm=MultiUserChatManager.getInstanceFor(connection);
muc=mucm.getMultiUserChat(groupid+"#conference.localhost");
DiscussionHistory histroy=new DiscussionHistory();
histroy.setMaxStanzas(10);
muc.createOrJoin(username,null,histroy,SmackConfiguration.getDefaultPacketReplyTimeout());
muc.nextMessage();
when created with gajim, the rooms are persistent.
EDIT : Here is code we used earlier. By default the chat rooms were persistent,
muc = new MultiUserChat(connection, groupid+"#conference.localhost");
if(!muc.isJoined())
{
DiscussionHistory histroy=new DiscussionHistory();
histroy.setMaxStanzas(10);
muc.join(username,null,histroy,SmackConfiguration.getDefaultPacketReplyTimeout());
muc.nextMessage(0);
}

You need to submit form like this for making a persistent group:
private void setConfig(MultiUserChat multiUserChat) {
try {
Form form = multiUserChat.getConfigurationForm();
Form submitForm = form.createAnswerForm();
for (Iterator<FormField> fields = submitForm.getFields(); fields.hasNext();) {
FormField field = (FormField) fields.next();
if (!FormField.TYPE_HIDDEN.equals(field.getType()) && field.getVariable() != null) {
submitForm.setDefaultAnswer(field.getVariable());
}
}
submitForm.setAnswer("muc#roomconfig_publicroom", true);
submitForm.setAnswer("muc#roomconfig_persistentroom", true);
multiUserChat.sendConfigurationForm(submitForm);
} catch (Exception e) {
e.printStackTrace();
}
}

You need to set muc#roomconfig_persistentroom to true in the MUC configuration from when creating the room.
MultiuserChat muc = manager.getMultiUserChat("myroom#muc.example.org");
muc.create("myNick");
// room is now created by locked
Form form = muc.getConfigurationForm();
Form answerForm = form.createAnswerForm();
answerForm.setAnswer("muc#roomconfig_persistentroom", true);
muc.sendConfigurationForm(answerForm);
// sending the configuration form unlocks the room
Note that not all XMPP MUC services support persistent rooms. For more information see:
https://www.igniterealtime.org/builds/smack/dailybuilds/javadoc/org/jivesoftware/smackx/muc/MultiUserChat.html#create(java.lang.String)
https://www.igniterealtime.org/builds/smack/dailybuilds/documentation/extensions/muc.html
http://xmpp.org/extensions/xep-0045.html#createroom

In smack 4.1.1, The answers given by #saurabh dixit throw an exception. Please check this thread on ignite website Correct implementation for persistent rooms smack 4.1.1

multiUserChatManager = MultiUserChatManager.getInstanceFor(connection);
multiUserChat = multiUserChatManager.getMultiUserChat(JidCreate.entityBareFrom(roomJID));
multiUserChat.create(Resourcepart.from(nickname));
Form form = multiUserChat.getConfigurationForm();
Form submitForm = form.createAnswerForm();
submitForm.getField("muc#roomconfig_enablelogging").addValue("1");
submitForm.getField("x-muc#roomconfig_reservednick").addValue("0");
submitForm.getField("x-muc#roomconfig_canchangenick").addValue("0");
submitForm.getField("x-muc#roomconfig_registration").addValue("0");
submitForm.getField("muc#roomconfig_passwordprotectedroom").addValue("0");
submitForm.getField("muc#roomconfig_roomname").addValue(roomName);
submitForm.getField("muc#roomconfig_whois").addValue("participants");
submitForm.getField("muc#roomconfig_membersonly").addValue("1");
submitForm.getField("muc#roomconfig_persistentroom").addValue("1");
multiUserChat.sendConfigurationForm(submitForm);
This is how you can send the room configuration from and configure room.
For more Details please see question.
How to send room configuration form and create persistce rooms from android using smack 4.3.4

Related

Leverage Groups for Workflow Approvals

We're implementing a new workflow (combined with staging task sync) on an existing website where we would like to notify all members that "own" that particular section/content to approve changes.
One of the options is to have multiple roles and their corresponding workflows configured for their role and scope, but this seems like overkill - at least for us, as currently one single role is set for approvals (and another for editors)
However I've recently come across this new page property:
And have a couple of questions:
Can regular CMS users (without membership) be part of a group?
Would we be able to leverage this group for the workflow's email notifications instead of the roles? E.g. email to everyone in the owner group when a page was sent for approval.
Is this option by default inherited from the parent page when a new one is created or does it need to be set individually for each page?
We have a Kentico 11 EMS license and working on an advanced workflow, therefore custom code is possible.
Can regular CMS users (without membership) be part of a group?
- why don't you use roles here?
Would we be able to leverage this group for the workflow's email
notifications instead of the roles? E.g. email to everyone in the
owner group when a page was sent for approval.
- you'll need to customize workflow manager class, but in general yes, it is possible. You could find an inspiration in this post
Is this option by default inherited from the parent page when a new
one is created or does it need to be set individually for each page?
- Use a macro to default the field. If you populate it with anything else then the new values will be saved.
Sample code snippet for Custom Global Event Handler for Workflow steps i.e., Reject and Approve steps.
using CMS;
using CMS.Base;
using CMS.DataEngine;
using CMS.DocumentEngine;
using CMS.EmailEngine;
using CMS.EventLog;
using CMS.Helpers;
using CMS.MacroEngine;
using CMS.SiteProvider;
using CMS.WorkflowEngine;
using System;
// Registers the custom module into the system
[assembly: RegisterModule(typeof(CustomWorkflowEvent))]
public class CustomWorkflowEvent : CMSModuleLoader
{
// Module class constructor, the system registers the module under the name "CustomInit"
public CustomWorkflowEvent()
: base("CustomInit")
{
}
// Contains initialization code that is executed when the application starts
protected override void OnInit()
{
base.OnInit();
// Assigns custom handlers to events
// WorkflowEvents.Approve.After += WorkFlow_Event_After();
WorkflowEvents.Reject.After += WorkFlow_Event_After;
WorkflowEvents.Approve.After += Approve_After;
// WorkflowEvents.Action.After += WorkFlowAction_Event_After;
}
private void Approve_After(object sender, WorkflowEventArgs e)
{
try
{
WorkflowStepInfo wsi = e.PreviousStep;
if (wsi != null)
{
CMS.WorkflowEngine.Definitions.SourcePoint s = wsi.GetSourcePoint(Guid.NewGuid());
//Make sure it was an approval (standard) step
var approvers = WorkflowStepInfoProvider.GetUsersWhoCanApprove(wsi, null, SiteContext.CurrentSiteID, "UserID = " + CMSActionContext.CurrentUser.UserID, "UserID", 0, "Email, FullName, Username");
EventLogProvider.LogInformation("Approvers Data", "Approvers Data", approvers.ToString());
if (approvers != null)
{
//Loop through the approvers
string siteName = null;
SiteInfo si = SiteInfoProvider.GetSiteInfo(SiteContext.CurrentSiteID);
if (si != null)
{
siteName = si.SiteName;
}
EmailTemplateInfo eti = EmailTemplateProvider.GetEmailTemplate("Workflow.Rejected", SiteContext.CurrentSiteName);
MacroResolver mcr = MacroResolver.GetInstance();
EmailMessage message = new EmailMessage();
// Get sender from settings
message.EmailFormat = EmailFormatEnum.Both;
message.From = eti.TemplateFrom;
// Do not send the e-mail if there is no sender specified
if (message.From != "")
{
// Initialize message
// message.Recipients = strRecipientEmail;
message.Subject = eti.TemplateSubject;
// Send email via Email engine API
// EmailSender.SendEmailWithTemplateText(SiteContext.CurrentSiteName, message, eti, mcr, true);
}
}
}
}
catch (Exception ex)
{
throw;
}
}
private void WorkFlow_Event_After(object sender, WorkflowEventArgs e)
{
try
{
WorkflowStepInfo wsi = e.PreviousStep;
if (wsi != null)
{
CMS.WorkflowEngine.Definitions.SourcePoint s = wsi.GetSourcePoint(Guid.NewGuid());
//Make sure it was an approval (standard) step
var approvers = WorkflowStepInfoProvider.GetUsersWhoCanApprove(wsi, null, SiteContext.CurrentSiteID, "UserID = " + CMSActionContext.CurrentUser.UserID, "UserID", 0, "Email, FullName, Username");
EventLogProvider.LogInformation("Approvers Data", "Approvers Data", approvers.ToString());
if (approvers != null)
{
//Loop through the approvers
string siteName = null;
SiteInfo si = SiteInfoProvider.GetSiteInfo(SiteContext.CurrentSiteID);
if (si != null)
{
siteName = si.SiteName;
}
EmailTemplateInfo eti = EmailTemplateProvider.GetEmailTemplate("Workflow.Rejected", SiteContext.CurrentSiteName);
MacroResolver mcr = MacroResolver.GetInstance();
EmailMessage message = new EmailMessage();
// Get sender from settings
message.EmailFormat = EmailFormatEnum.Both;
message.From = eti.TemplateFrom;
// Do not send the e-mail if there is no sender specified
if (message.From != "")
{
// Initialize message
// message.Recipients = strRecipientEmail;
message.Subject = eti.TemplateSubject;
// Send email via Email engine API
// EmailSender.SendEmailWithTemplateText(SiteContext.CurrentSiteName, message, eti, mcr, true);
}
}
}
}
catch (Exception ex)
{
throw;
}
}
}
Hope Helps you.
Can regular CMS users (without membership) be part of a group?
It is not part of CMS users. Groups are coming from Groups Application.
GROUP: Allows you to manage user groups. Groups are a social networking
feature enabling users to find information and communicate according
to shared interests.
Would we be able to leverage this group for the workflow's email notifications instead of the roles? E.g. email to everyone in the owner group when a page was sent for approval.
No
Is this option by default inherited from the parent page when a new one is created or does it need to be set individually for each page?
No

Smack Multi user chat set answer XMPPError: bad-request-cancel

I developed android chat app by using XMPP server (prosody) and smack library. When I trying to create chat room, the room is created successfully, but when I send configuration Form this error is appears:
XMPPError: bad-request - cancel
My Code:
EntityBareJid entityBareJid = null;
entityBareJid = JidCreate.entityBareFrom("room5#conference.MyServiceName.com");
MultiUserChat muc = multiUserChatManager.getMultiUserChat(entityBareJid);
muc.join(Resourcepart.from("rshRoom5"));
Log.d("GROUP" , "Room now is created ...... ");
Form form = muc.getConfigurationForm();
Form answerForm = form.createAnswerForm();
answerForm.setAnswer("muc#roomconfig_persistentroom", true);
muc.sendConfigurationForm(answerForm);
And this is the muc component in server configuration file:
Component "conference.MyServiceName.com" "muc"
name = "chatrooms server"
restrict_room_creation = false;

In identity server 3 how to relate user to client

I am using Identity Server 3. I have couple applications ie. Client configured and have few users configured. How do i establish the relationship between User and a Client and also view all applications that the selected User has access to.
Update 1
I am sorry if question was confusing. On IdSvr3 home page, there is a link to revoke application permissions. I am guessing in order to revoke the permission you have to first establish the relationship between user and application.
and i wanted to know how to establish that permission when i add new user?
There's no direct way to limit one or multiple users to a certain client. This is where you should think about implementing your own custom validation. Fortunately, the IdentityServer provides an extensibility point for this kind of requirement.
ICustomRequestValidator
You should implement this interface to further validate users to see if they belong to certain clients and filter them out. You can look into the user details by looking at ValidatedAuthorizeRequest.Subject. This custom validator will start after validating optional parameters such as nonce, prompt, arc_values ( AuthenticationContextReference ), login_hint, and etc. The endpoint is AuthorizeEndPointController and the default implementation of the interface for the tailored job is AuthorizeRequestValidator and its RunValidationAsync. You should take a look at the controller and the class.
Implementation tip
By the time the custom request validation begins, a Client reference will be presented in ValidatedAuthorizeRequest. So all you need to do would be matching the client id or some other identifiers you think you need to verify the client. Probably, you might want to add a Claim key-value pair to your client which you want to allow a few users.
Maybe something like this.
new InMemoryUser{Subject = "870805", Username = "damon", Password = "damon",
Claims = new Claim[]
{
new Claim(Constants.ClaimTypes.Name, "Damon Jeong"),
new Claim(Constants.ClaimTypes.Email, "dmjeong#email.com"),
new Claim(Constants.ClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean)
}
}
Assume you have above user, then add the subject id to the claim of a client like below.
new Client
{
ClientName = "WPF WebView Client Sample",
ClientId = "wpf.webview.client",
Flow = Flows.Implicit,
.
.
.
// Add claim for limiting this client to certain users.
// Since a claim only accepts type and value as string,
// You can add a list of subject id by comma separated values
// eg ( new Claim("BelongsToThisUser", "870805, 870806, 870807") )
Claims = new List<Claim>
{
new Claim("BelongsToThisUser", "870805")
}
},
And then just implement the ICustomRequestValidator and try to match the Claim value with the given user in its ValidateAuthorizeRequestAsync.
public class UserRequestLimitor : ICustomRequestValidator
{
public Task<AuthorizeRequestValidationResult> ValidateAuthorizeRequestAsync(ValidatedAuthorizeRequest request)
{
var clientClaim = request.Client.claims.Where(x => x.Type == "BelongsToThisUser").FirstOrDefault();
// Check is this client has "BelongsToThisUser" claim.
if(clientClaim != null)
{
var subClaim = request.Subject.Claims.Where(x => x.Type == "sub").FirstOrDefault() ?? new Claim(string.Empty, string.Empty);
if(clientClaim.Value == userClaim.Value)
{
return Task.FromResult<AuthorizeRequestValidationResult>(new AuthorizeRequestValidationResult
{
IsError = false
});
}
else
{
return Task.FromResult<AuthorizeRequestValidationResult>(new AuthorizeRequestValidationResult
{
ErrorDescription = "This client doesn't have an authorization to request a token for this user.",
IsError = true
});
}
}
// This client has no access controls over users.
else
{
return Task.FromResult<AuthorizeRequestValidationResult>(new AuthorizeRequestValidationResult
{
IsError = false
});
}
}
public Task<TokenRequestValidationResult> ValidateTokenRequestAsync(ValidatedTokenRequest request)
{
// your implementation
}
}
Time to DI
You need to inject your own dependency when you configure up your IdentityServer. The authorization server uses IdentityServerServiceFactory for registering dependencies.
var factory = new IdentityServerServiceFactory();
factory.Register(new Registration<ICustomRequestValidator>(resolver => new UserRequestLimitor()));
Then Autofac; the IoC container in IdentityServer will do the rest of the DI jobs for you.

xamarin forms: Calling phone and sending email (IOS, Android and UWP)

Currently using following code for calling and email features, but it is only working in Android and not working in IOS. Also, I need these features in UWP.
For call:
string phoneno = "1234567890";
Device.OpenUri(new Uri("tel:" + phoneno));
For mail:
string email = "sreejithsree139#gmail.com";
Device.OpenUri(new Uri("mailto:" + email ));
Any package available for this?
Xamarin.Essentials (Nuget) is available as a preview package and contains functionality to both open the default mail app and attach information such as the recipients, subject and the body as well as open the phone dialer with a certain number.
There is also a blog post about Xamarin.Essentials available on blog.xamarin.com.
Edit:
As for your mail issue, Xamarin.Essentials expects an array of strings as recipients so you are able to send mail to multiple people at once. Just pass a string array with one single value.
var recipients = new string[1] {"me#watercod.es"};
If you're using the overload that expects an EmailMessage instance, you are supposed to pass a List of string objects.
In that case, the following should work:
var recipients = new List<string> {"me#watercod.es"};
Updating the complete code for calling and mailing features using Xamarin.Essentials, this might help others.
For call:
try
{
PhoneDialer.Open(number);
}
catch (ArgumentNullException anEx)
{
// Number was null or white space
}
catch (FeatureNotSupportedException ex)
{
// Phone Dialer is not supported on this device.
}
catch (Exception ex)
{
// Other error has occurred.
}
For Mail:
List<string> recipients = new List<string>();
string useremail = email.Text;
recipients.Add(useremail);
try
{
var message = new EmailMessage
{
//Subject = subject,
//Body = body,
To = recipients
//Cc = ccRecipients,
//Bcc = bccRecipients
};
await Email.ComposeAsync(message);
}
catch (Exception ex)
{
Debug.WriteLine("Exception:>>"+ex);
}
Hello to make a call in UWP:
if (Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.ApplicationModel.Calls.PhoneCallManager"))
{
Windows.ApplicationModel.Calls.PhoneCallManager.ShowPhoneCallUI("123", "name to call");
}
To send a Text:
private async void ComposeSms(Windows.ApplicationModel.Contacts.Contact recipient,
string messageBody,
StorageFile attachmentFile,
string mimeType)
{
var chatMessage = new Windows.ApplicationModel.Chat.ChatMessage();
chatMessage.Body = messageBody;
if (attachmentFile != null)
{
var stream = Windows.Storage.Streams.RandomAccessStreamReference.CreateFromFile(attachmentFile);
var attachment = new Windows.ApplicationModel.Chat.ChatMessageAttachment(
mimeType,
stream);
chatMessage.Attachments.Add(attachment);
}
var phone = recipient.Phones.FirstOrDefault<Windows.ApplicationModel.Contacts.ContactPhone>();
if (phone != null)
{
chatMessage.Recipients.Add(phone.Number);
}
await Windows.ApplicationModel.Chat.ChatMessageManager.ShowComposeSmsMessageAsync(chatMessage);
}
as found in Microsoft documentation here: Compose SMS documentation
==> So you can make (If not already done) a shared service interface in your Xamarin app, then the implementation with these codes in your UWP app...
To send an email:
To send an email in UWP, you can refer to the Microsoft documentation too:
Send Email documentation (UWP)
Using a plugin
Else you can use a Xamarin plugin:
documentation: Xamarin cross messaging plugin
Nuget: Nuget plugin package
In our app, we are doing the phone calling with a DependencyService.
Therefore in our PCL, we have
public interface IPhoneCall
{
void Call(string number);
}
On the iOS side, the following method does the calling:
public void Call(string number)
{
if (string.IsNullOrEmpty(number))
return;
var url = new NSUrl("tel:" + number);
if (!UIApplication.SharedApplication.OpenUrl(url))
{
var av = new UIAlertView("Error",
"Your device does not support calls",
null,
Keys.Messages.BUTTON_OK,
null);
av.Show();
}
}
If don't want to wait for the Xamarin essentials that is still in pre-release as of today, you can use this open source plugin. It works on iOS, Android and UWP. There is a sample from the github documentation :
// Make Phone Call
var phoneDialer = CrossMessaging.Current.PhoneDialer;
if (phoneDialer.CanMakePhoneCall)
phoneDialer.MakePhoneCall("+27219333000");
// Send Sms
var smsMessenger = CrossMessaging.Current.SmsMessenger;
if (smsMessenger.CanSendSms)
smsMessenger.SendSms("+27213894839493", "Well hello there from Xam.Messaging.Plugin");
var emailMessenger = CrossMessaging.Current.EmailMessenger;
if (emailMessenger.CanSendEmail)
{
// Send simple e-mail to single receiver without attachments, bcc, cc etc.
emailMessenger.SendEmail("to.plugins#xamarin.com", "Xamarin Messaging Plugin", "Well hello there from Xam.Messaging.Plugin");
// Alternatively use EmailBuilder fluent interface to construct more complex e-mail with multiple recipients, bcc, attachments etc.
var email = new EmailMessageBuilder()
.To("to.plugins#xamarin.com")
.Cc("cc.plugins#xamarin.com")
.Bcc(new[] { "bcc1.plugins#xamarin.com", "bcc2.plugins#xamarin.com" })
.Subject("Xamarin Messaging Plugin")
.Body("Well hello there from Xam.Messaging.Plugin")
.Build();
emailMessenger.SendEmail(email);
}

Smack - get entry starts with specific letter

I'm using Smack to build simple XMPP android client, I need to retrieve users only starts with letter "a" I've tried to use roster and UserSearchManager both need specific user id I couldn't use wild card for e.g.
UserSearch userSearch = new UserSearch();
answerForm.setAnswer("user", "a*");
or
RosterEntry entry = roster.getEntry("a*");
Any help?
This is a working snippet:
public static List<Row> searchOnServerForUsers(String searchString, XmppManager xmppManager) throws Exception
{
UserSearchManager usersearchManager = new UserSearchManager(abstractXMPPConnection.getConnection());
String searchServiceName = XmppConstants.USER_SERVICE_NAME_PREFIX + abstractXMPPConnection.getConnection().getServiceName();
Form form = usersearchManager.getSearchForm( searchServiceName );
Form answers = form.createAnswerForm();
answers.setAnswer("Name", false);
answers.setAnswer("Email", false);
answers.setAnswer("Username", true);
// answers.setAnswer("search", "*"); //search for all registered users
answers.setAnswer("search", "a*"); //your search string
ReportedData data = usersearchManager.getSearchResults(answers, searchServiceName);
List<Row> rows = data.getRows();
return rows;
}
So you have to use UserSearch,
on each column (like Username, pay attention to case!)
you have to set if search (true) or to not search (false)
your search string (in your usecase: "a*")
Don't use smack version 4.4.0 alpha1 it has some bugs. After reverting it to 4.1.1 . I got all the users. from UserSearchManager